使用 Kubernetes 和 Istio 学习微服务

查看k8s集群名称
kubectl config current-context

1、设置k8s集群

1.1、创建命名空间

export NAMESPACE=tutorial
kubectl create namespace $NAMESPACE

1.2、安装istio和附加组件

  • 附加组件的yaml文件在samples/addons目录下
  • 参考istio1-安装istio章节安装https://www.cnblogs.com/lixunblogs/p/19004831

1.3、创建Ingress

  • 目的是给上一步创建的每一个服务创建ingress资源
cat <<EOF>> ingress-istio-system.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: istio-system
  namespace: istio-system
spec:
  ingressClassName: istio
  rules:
  - host: my-istio-dashboard.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: grafana
            port:
              number: 3000
  - host: my-istio-tracing.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: tracing
            port:
              number: 9411
  - host: my-istio-logs-database.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheus
            port:
              number: 9090
  - host: my-kiali.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kiali
            port:
              number: 20001
EOF

kubectl apply -f ingress-istio-system.yaml

1.4、创建Role

  • 创建一个角色为 istio-system 命名空间提供读权限
cat <<EOF>> role-istio-system.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: istio-system-access
  namespace: istio-system
rules:
- apiGroups: ["", "extensions", "apps", "networking.k8s.io"]
  resources: ["*"]
  verbs: ["get", "list"]
EOF

kubectl apply -f role-istio-system.yaml

1.5、创建ServiceAccount

  • 为每个用户创建服务账号
cat <<EOF>> sa-istio-system.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ${NAMESPACE}-user
  namespace: $NAMESPACE
EOF

kubectl apply -f sa-istio-system.yaml

使用证书认证

生成私钥
openssl genrsa -out ops-user.key 2048

生成 CSR(证书签名请求)
openssl req -new \
  -key ops-user.key \
  -out ops-user.csr \
  -subj "/CN=ops-user/O=devops"

解释:
CN = 用户名
O = 组名(RBAC 里可用)

用 Kubernetes CA 签发证书
openssl x509 -req \
  -in ops-user.csr \
  -CA /etc/kubernetes/pki/ca.crt \
  -CAkey /etc/kubernetes/pki/ca.key \
  -CAcreateserial \
  -out ops-user.crt \
  -days 3650

创建 kubeconfig
定义集群信息
要访问的 K8s 集群地址、CA 证书
kubectl config set-cluster tutorial-cluster \
  --server=https://192.168.40.11:6443 \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --kubeconfig=ops-user.conf 

定义用户凭证
kubectl config set-credentials ops-user \
  --client-certificate=ops-user.crt \
  --client-key=ops-user.key \
  --kubeconfig=ops-user.conf

Context(上下文):把 “集群” 和 “用户” 绑定起来,相当于 “访问入口”;
kubectl config set-context ops-user@istio-k8s \
  --cluster=istio-k8s \
  --user=ops-user \
  --kubeconfig=ops-user.conf

use-context:应用配置
kubectl config use-context ops-user@istio-k8s \
  --kubeconfig=ops-user.conf

1.6、限制每个用户的权限

  • 用户只需要在他们自己的命名空间中创建资源以及从 istio-system 命名空间中读取资源
  • ingress在这个apigroup里,networking.k8s.io。确保role里有这个apigroup
cat <<EOF>> rolebinding-istio-system.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ${NAMESPACE}-access
  namespace: $NAMESPACE
rules:
- apiGroups: ["", "extensions", "apps", "networking.k8s.io", "networking.istio.io", "authentication.istio.io",
              "rbac.istio.io", "config.istio.io", "security.istio.io"]
  resources: ["*"]
  verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ${NAMESPACE}-access
  namespace: $NAMESPACE
subjects:
- kind: ServiceAccount
  name: ${NAMESPACE}-user
  namespace: $NAMESPACE
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ${NAMESPACE}-access
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ${NAMESPACE}-istio-system-access
  namespace: istio-system
subjects:
- kind: ServiceAccount
  name: ${NAMESPACE}-user
  namespace: $NAMESPACE
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: istio-system-access
EOF

kubectl apply -f rolebinding-istio-system.yaml

1.7、为每个用户创建k8s配置文件

  • 每个用户需要使用他们自己的 Kubernetes 配置文件。这个配置文件指明了集群的详细信息、服务账号、证书和用户的命名空间。kubectl 命令使用这个配置文件在集群上操作
cat <<EOF>> ./${NAMESPACE}-user-config.yaml
apiVersion: v1
kind: Config
preferences: {}

clusters:
- cluster:
    certificate-authority-data:
    server: $(kubectl config view -o jsonpath="{.clusters[?(.name==\"$(kubectl config view -o jsonpath="{.contexts[?(.name==\"$(kubectl config current-context)\")].context.cluster}")\")].cluster.server}")
  name: ${NAMESPACE}-cluster

users:
- name: ${NAMESPACE}-user
  user:
    client-key-data:
    token:

contexts:
- context:
    cluster: ${NAMESPACE}-cluster
    namespace: ${NAMESPACE}
    user: ${NAMESPACE}-user
  name: ${NAMESPACE}

current-context: ${NAMESPACE}
EOF
  • 这里生成的文件有空字段
tutorial-user-config.yaml
cat tutorial-user-config.yaml
apiVersion: v1
kind: Config
preferences: {}

clusters:
- cluster:
    certificate-authority-data:
    server: https://192.168.40.11:6443
  name: tutorial-cluster

users:
- name: tutorial-user
  user:
    token:

contexts:
- context:
    cluster: tutorial-cluster
    namespace: tutorial
    user: tutorial-user
  name: tutorial

current-context: tutorial

- 使用官网的例子配置文件,certificate-authority-data和token字段为空。 - 出于安全考虑从k8s1.24开始不再自动创建SA cecret,改用短期自动轮换的token,Pod里自动挂载短期token,不再存储在 Secret 对象中 - k8s1.24版本之前,创建 SA 后会自动生成 Secret,类型:kubernetes.io/service-account-token。 token永不过期,存在etcd里可以直接拷贝用,这存在安全风险。
  • 生成 token
kubectl create token tutorial-user -n tutorial --duration=24h

image

  • 生成CA
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}'

image

  • 验证
    • 分别填入token和certificate-authority-data后验证,如果不成功会提示输入用户名
kubectl --kubeconfig=tutorial-user-config.yaml get pods

说明:kubeconfig 有三种主流认证方式

  • Token 认证
    • 这种方式不需要 client-certificate-data不需要 client-key-data。所以client-key-data:应该删除或者留空。
users:
- name: tutorial-user
  user:
    token: xxxxx
  • 客户端证书认证(管理员常用)
    • 这里的 client-certificate-data = 客户端证书,client-key-data = 客户端私钥,通常来自 /etc/kubernetes/pki/,但这是 kubeadm 管理员级别用的。
users:
- name: kubernetes-admin
  user:
    client-certificate-data: <base64证书>
    client-key-data: <base64私钥>
  • OIDC 认证(企业常见)
    • 例如接入:Keycloak、LDAP、企业 SSO

1.8、应用新的config文件

export KUBECONFIG=$PWD/${NAMESPACE}-user-config.yaml
  • 可以使用unset KUBECONFIG,取消变量声明

1.9、验证默认命名空间

  • 打印当前命名空间以确认配置文件已生效,应该输出tutorial
kubectl config view -o jsonpath="{.contexts[?(@.name==\"$(kubectl config current-context)\")].context.namespace}"

2、配置本地计算机

  • 因为我是测试环境的k8s集群,本机计算机和集群在一台机器上
  • 需要本地计算机有curl、node.js、docker、kubectl。本机除了node.js其他都有

2.1、安装node.js

  • 服务器网络环境问题,先从浏览器下载脚本到服务器,再执行安装
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
  • 这里按照提示操作,重开终端或执行命令,这里我选的是重开终端

image

  • 继续安装,并查看版本

image

3、本地运行微服务

3.1、下载代码及依赖

  • 将服务代码和 其 package 文件 下载到一个单独的目录中
mkdir ratings && cd ratings
curl -s https://raw.githubusercontent.com/istio/istio/release-1.29/samples/bookinfo/src/ratings/ratings.js -o ratings.js
curl -s https://raw.githubusercontent.com/istio/istio/release-1.29/samples/bookinfo/src/ratings/package.json -o package.json
  • 将 rating 服务的依赖库安装在存储服务代码和 package 文件的同一目录下
npm install

image

3.2、启动服务

  • 在9080端口上监听服务
npm start 9080

image

3.3、验证

  • 修改产品的评级,并在修改前后查看
curl localhost:9080/ratings/7
curl -X POST localhost:9080/ratings/7 -d '{"Reviewer1":1,"Reviewer2":1}'
curl localhost:9080/ratings/7

image

4、在docker中运行ratings服务

cd ratings
curl -s https://raw.githubusercontent.com/istio/istio/release-1.29/samples/bookinfo/src/ratings/Dockerfile -o Dockerfile
docker build -t user/ratings .
docker run --name my-ratings  --rm -d -p 9081:9080 $USER/rating
curl localhost:9081/ratings/7
docker ps
docker stop my-ratings

5、使用 Kubernetes 运行 Bookinfo

设置环境变量 MYHOST 的值为应用程序的 URL

export MYHOST=$(kubectl config view -o jsonpath={.contexts..namespace}).bookinfo.com

image

部署应用

  • 确保已经应用环境变量echo $KUBECONFIG。没设置的话执行1.8步骤
# 下载bookinfo.yaml
wget https://raw.githubusercontent.com/istio/istio/release-1.29/samples/bookinfo/platform/kube/bookinfo.yaml

# 修改镜像源为国内地址
sed -i 's|docker\.io/istio|swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/istio|g' bookinfo.yaml > /dev/null 2>&1

# 通过标签筛选要安装的应用
kubectl apply -l version!=v2,version!=v3 -f  bookinfo.yaml

image

  • 如果在1.7步骤时token为空,这里会提示输入用户和密码
  • kubectl 认证流程是:先找token,没有的话尝试 client cert,还没有的话尝试 basic auth提示输入用户名密码,basic auth是K8S很早之前的认证,目前默认不开启,所以API Server 根本不会接受它。

image

  • 四个服务达到 Running 状态后,就可以扩展 deployment。要使每个微服务的每个版本在三个 Pod 中运行,请执行以下命令:
kubectl scale deployments --all --replicas 3

image

  • 在服务达到 Running 状态后,部署一个测试 Pod:curl。 此 Pod 用来向您的微服务发送请求:
# 替换镜像
sed -i 's|docker\.io|swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io|g' curl.yaml > /dev/null 2>&1
# 部署测试Pod
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.29/samples/curl/curl.yaml
  • 测试 Pod 中用 curl 命令发送请求给 Bookinfo 应用
kubectl exec $(kubectl get pod -l app=curl -o jsonpath='{.items[0].metadata.name}') -c curl -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

image

创建 Kubernetes Ingress 资源

cat <<EOF>> bookinfo-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: bookinfo
spec:
  ingressClassName: nginx
  rules:
  - host: $MYHOST
    http:
      paths:
      - path: /productpage
        pathType: Prefix
        backend:
          service:
            name: productpage
            port:
              number: 9080
      - path: /login
        pathType: Prefix
        backend:
          service:
            name: productpage
            port:
              number: 9080
      - path: /logout
        pathType: Prefix
        backend:
          service:
            name: productpage
            port:
              number: 9080
      - path: /static
        pathType: Prefix
        backend:
          service:
            name: productpage
            port:
              number: 9080
EOF

kubectl apply -f bookinfo-ingress.yaml

部署nginx ingress controller

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml -O nginx-ingress-controller.yaml
# 替换镜像,还需要手动删除镜像后的摘要
sed -i 's|registry.k8s.io|swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io|g' nginx-ingress-controller.yaml > /dev/null 2>&1

# 会创建ingressclass和controller
kubectl apply -f nginx-ingress-controller.yaml

更新 /etc/hosts 配置文件

  • 获取名为 bookinfo 的 Kubernetes Ingress 的 IP 地址
kubectl get ingress bookinfo
  • 以下命令的输出内容追加到 /etc/hosts 文件
echo $(kubectl get ingress istio-system -n istio-system -o jsonpath='{..ip} {..host}') $(kubectl get ingress bookinfo -o jsonpath='{..host}')
  • 输出内容为
192.168.40.13 my-istio-dashboard.io my-istio-tracing.io my-istio-logs-database.io my-kiali.io tutorial.bookinfo.com
  • 将 ingress-nginx 命名空间下的 svc,ingress-nginx-controller改成loadbalancer的类型,kubectl get svc 查看EXTERNAL-IP为pending,这是因为没有LB Congtroller,没有人分配IP,可以部署MetalLB给裸机 Kubernetes 提供LoadBalancer 功能的。这里继续使用nodeport类型,所以在访问时加上nodeport的端口
  • 测试访问
curl -s $MYHOST:31090/productpage | grep -o "<title>.*</title>"

image

模拟流量

  • 在一个单独的终端窗口中设置无限循环,将流量发送到您的应用程序,以模拟现实世界中恒定的用户流量:
# linux
while :; do curl -s $MYHOST:30190/productpage | grep -o "<title>.*</title>"; sleep 1; done
# windows
for /L %i in (0,0,1) do @curl -s tutorial.bookinfo.com:31090/productpage | findstr "title" & timeout /t 1 >nul

生产测试

测试单个微服务

  • 确保当前命名空间为tutorial

  • 从测试 pod 中向服务之一发起 HTTP 请求
    image

  • 在宿主机添加hosts后,在宿主机访问
    image

混沌测试

  • 在dashboard中将details的pod缩容至0个。模拟故障
    image

  • 再次查看,页面并没有完全崩溃,只是详情部分显示错误
    image

添加一个新版本的 reviews

  • 使用第五节的文件进行部署
  • 确保命名空间是tutorial
kubectl apply -l app=reviews,version=v2 -f bookinfo.yaml
  • 多访问几次 tutorial.bookinfo.com:31090/productpage (确保正确配置了hosts)会发现有的页面有星星(约%25的比例),因为v1的pod有3个,v2的pod有1个

image

  • 增加新版本的副本数
kubectl scale deployment reviews-v2 --replicas=3

在 productpage 启用 Istio

  • 需要在tutorial环境变量下创建
    export KUBECONFIG=/root/cert/ops-user.conf
# 应用默认destnation-rule
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.29/samples/bookinfo/networking/destination-rule-all.yaml

重新部署 productpage 微服务,启用 Istio

wget https://raw.githubusercontent.com/istio/istio/release-1.29/samples/bookinfo/platform/kube/bookinfo.yaml

sed -i 's|docker\.io/istio|swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/istio|g' bookinfo.yaml > /dev/null 2>&1

# 暂时恢复上下文,不然无法执行,原因是权限不足
unset KUBECONFIG

istioctl kube-inject -f bookinfo.yaml > bookinfo-ingected.yaml

sed -i 's/replicas: 1/replicas: 3/g' bookinfo-ingected.yaml > /dev/null 2>&1

export KUBECONFIG=/root/cert/ops-user.conf

# 需要在tutorial环境变量下创建
kubectl apply -l app=productpage,version=v1 -f bookinfo-ingected.yaml

image

在所有微服务上启用 Istio

  • 在dashboard上将tutorial命名空间下的pod缩容为1
    image
  • 重新部署注入了istio的pod
kubectl apply -l app!=reviews -f bookinfo-ingected.yaml -n tutorial
kubectl apply -l app=reviews,version=v1 -f bookinfo-ingected.yaml -n tutorial
kubectl apply -l app=reviews,version=v2 -f bookinfo-ingected.yaml -n tutorial
  • 可以看到,每个pod中有两个容器
    image

grafana中显示

image

image

image

posted @ 2026-03-27 11:23  立勋  阅读(21)  评论(0)    收藏  举报