kubernetes快速入门(中)


本文是《Kubernetes(k8s)快速入门》系列的中篇,延续了上篇的内容,旨在通过一个具体的微服务Demo项目,手把手地引导读者掌握Kubernetes的核心实践操作。文章以“app”和“app-gateway”两个无状态服务(即:微服务中的单个模块,区别于K8s Service)为例,详细讲解了从代码编译、镜像制作到K8s集群部署、配置管理、服务发现及优雅终止的完整流程。Demo项目代码,见https://github.com/Qinch/k8s-manifests/tree/master

0 Minikube工具简介

1 Demo项目简介

1.1 Demo构建
ubuntu@VM-0-15-ubuntu:~/k8s-manifests/part2/app$ tree -L 2
.
├── build // 编译相关脚本
│   ├── build.sh // go build
│   ├── image.sh // docker build
│   └── kustomize.sh // kustomize build
├── cmd
│   └── main.go
├── configs // app-conf镜像相关
│   ├── Dockerfile // 用于制作app-conf镜像
│   └── sparse.txt
├── deployments // K8s manifests
│   ├── base
│   ├── manifests
│   └── overlays
├── Dockerfile // 用于制作app镜像
├── go.mod
├── go.sum
├── internal
│   └── service
├── Makefile // make 入口
├── target // go build的结构
│   └── bin
└── vendor // 省略展示

2 Namespace

2.1 创建Namespace

3 K8s manifests

/k8s-manifests/part2/app/deployments # tree
.
├── base // base layer
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
├── manifests // kustomize build生成的结构
│   ├── app-prod // 省略展示
│   └── app-test // 测试环境
│       ├── apps_v1_deployment_app.yaml
│       └── v1_service_app.yaml
│       └── v1_namespace_test.yaml
└── overlays // patch layer
    ├── app-prod // prod环境,省略展示
    └── app-test // test环境
        ├── container_env.yaml
        ├── container_probe.yaml
        ├── ns.yaml
        └── kustomization.yaml
3.1 环境变量
cat ./app/deployments/overlays/app-test/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: test     # 显式指定test Namespace

resources:
- ../../base
- ./ns.yaml

patches:
- path: ./container_env.yaml
  target:
    kind: Deployment

cat ./app/deployments/overlays/app-test/container_env.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app  
spec:
  template:
    spec:
      containers:
        - name: app  
          env:
            - name: ENV # 设置环境变量,在app-prod中则value="prod"
              value: "test"

4 应用配置同步

4.1 Sidecar容器
cat ./app/configs/Dockerfile 

FROM registry.k8s.io/git-sync/git-sync:v4.6.0

WORKDIR /configs
COPY ./sparse.txt ./
- K8s Deployment中部分相关配置,如下:
cat ./app/deployments/base/deployment.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
# placeholder, 通过kustomize edit set image来注入real image:tag。
        - image: mock-image 
          name: app
          imagePullPolicy: IfNotPresent
          volumeMounts:
# 名为config-vol的卷挂载在app容器的/k8s-manifests/part2/app/configs目录上
            - mountPath: /k8s-manifests/part2/app/configs 
              name: config-vol
              readOnly: true
# placeholder, 通过kustomize edit set image来注入real image:tag。
        - image: mock-conf-image # app-conf容器
          name: app-conf
          imagePullPolicy: IfNotPresent
          volumeMounts:
# 名为config-vol的卷挂载在app-conf容器的/configs/git_configs目录上
            - mountPath: /configs/git_configs
              name: config-vol
          command: ["/git-sync"] # app-conf容器的启动命令
          args:
                 - --repo=https://github.com/Qinch/k8s-manifests.git
                 - --ref=master
                 - --root=/configs/git_configs
                 - --link=latest
                 - --sparse-checkout-file=/configs/sparse.txt
                 - --depth=1
                 - --period=60s
# init容器,所有Init容器必须全部执行成功(即:退出码为 0)之后,
# Pod 内的业务容器才会启动。
      initContainers:
        - name: init-config
# placeholder, 通过kustomize edit set image来注入real image:tag。
          image: mock-conf-image
          imagePullPolicy: IfNotPresent
          volumeMounts:
# 名为config-vol的卷挂载init容器的/configs/git_configs目录上
            - mountPath: /configs/git_configs
              name: config-vol
          command: ["/git-sync"] # init容器的启动命令
          args:
             - --repo=https://github.com/Qinch/k8s-manifests.git
             - --ref=master
             - --root=/configs/git_configs
             - --link=latest
             - --sparse-checkout-file=/configs/sparse.txt
             - --depth=1
# 只运行一次,然后退出。如果一直运行,会阻塞后续业务容器的启动。
             - --one-time 
      volumes:
# emptyDir卷没有独立的生命周期,而是和Pod的生命周期关联(
# 即:当Pod删除时,卷就会被删除,卷的内容也就丢失。)
        - name: config-vol
          emptyDir: {}

- 登陆Pod中app容器查看同步下来的config.yaml

图4-1

5 容器资源限制

at ./app/deployments/overlays/app-test/container_resources.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      containers:
        - name: app
          resources:
            requests:  # app容器的资源请求量
              cpu: 500m
              memory: 128Mi
            limits:     # app容器的资源limits
              cpu: 1
              memory: 256Mi

6 Pod健康检查

cat app/deployments/overlays/app-test/container_probe.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      containers:
      - name: app # app容器的健康检查
	  startupProbe: # 启动探针
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 5           # 每5秒检查一次
            failureThreshold: 10       # 最多失败10次
            successThreshold: 1       # 1次成功即通过
          livenessProbe: # 存活探针
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 10          # 每10秒检查一次
            failureThreshold: 3        # 最多失败3次
            successThreshold: 1
          readinessProbe: # 就绪探针
            httpGet:
              path: /health    
              port: 8080
            periodSeconds: 5
            failureThreshold: 2
            successThreshold: 1

7 Service服务访问

7.1 集群内部app-gateway服务访问app服务
cat ./app/deployments/base/service.yaml 

apiVersion: v1
kind: Service
metadata:
  name: app
spec:
  type: ClusterIP # Service类型
  ports:
    - port: 80 # # 该Service的HTTP监听端口
        targetPort: 8080
    - port: 50051 # 该Service的gRPC监听端口
        targetPort: 50051
  selector:
    app: app

7.2 集群外部访问app-gateway服务
apiVersion: v1
kind: Service
metadata:
  name: app-gateway
spec:
  type: NodePort     # Service类型
  ports:
  - port: 80               # ClusterIP的端口号
    targetPort: 8080
# 指定worker node的端口号,通过worker node的30123端口可以访问该Service
    nodePort: 30123 
  selector:
    app: app-gateway

8 Pod优雅终止

cat ./app/deployments/overlays/app-test/container_lifecycle.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      terminationGracePeriodSeconds: 60
      containers:
        - name: app
          lifecycle:
            preStop:
              exec:
                command:
                  - sh
                  - c
                  - "sleep 30"

9 附录

10 参考资料