.NET DevOps 接入指南 | 发布到Kubernetes

引言

完成前面章节的镜像构建,离自动部署到Kubernetes 就更近一步。这一节就来详解GitLab如何集成Kubernetes,以及如何配置流水线发布到Kubernetes。

集成 Kubernetes

为了方便后续配置CI/CD流水线并部署至Kubernetes,首先要集成Kubernetes至GitLab。主要分为以下几步:

  1. 获取Kubernetes ApiServer地址,可通过执行kubectl cluster-info获取。下图中红框所示即为ApiServer地址。
image
  1. kube-system命名空间下创建gitlabServiceAccount。可直接使用Lens按下图步骤创建:
image
  1. 创建命名为gitlab-cluster-adminClusterRoleBinding。同样直接使用Lens创建,步骤如下图所示:
image

对于以上2、3两步,也可通过以下脚本创建:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: gitlab-cluster-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: gitlab
    namespace: kube-system
  1. 获取证书和令牌,可以通过找到创建的命名为gitlab``ServiceAccount对应的Secret中获取,Secret命名格式为:gitlab-token-xxx,可在Lens中按以下步骤获取:
image
  1. 打开集成界面,如下图所示:
    image
  2. 配置参数,点击连接现有集群,参考下图进行配置。其中:

  • API地址:即为上面第1步获取的Api服务器地址

  • CA证书:对应第4步中命名为ca.crt的值

  • 服务令牌:对应第4步中命名为token的值

image
  1. 点击Kubernets菜单,即可看到集成的Kubernetes集群,如下图所示:
    image

配置镜像拉取凭证

在部署到集成的Kubernetes平台前,还有一点至关重要,那就是配置镜像拉取凭证(imagePullSecert)。这样自有的Kubernetes平台才能够从GitLab Registry中拉取镜像,创建Pod。创建镜像拉取凭证也相对简单,仅需两步,第一步创建一个个人访问令牌,要求必须包含read_registrywrite_registry两个权限范围,如下图所示,其中令牌名称访问令牌将分别作为访问镜像仓库的凭证的用户名和密码。

image

有了访问令牌,即可创建一个类型为docker-registrysecret即可,具体命令如下,该命令暂无需执行,后续阶段Job中会使用。

$: kubectl create secret docker-registry \
gitlab-registry-secret \ # 指定secret 名称
--docker-server=https://registry.shengjie.dev \ # 指定 docker镜像仓库地址
--docker-username=container-registry-token \ # 指定凭证名称
--docker-password=T93Q3HbBaixAhxWZk5fy \ # 指定为凭证令牌
--docker-email=ysjshengjie@live.cn \ # 指定邮箱
-n gitlab # 指定命名空间

准备部署文件

准备工作做完了,接下来就要准备好部署文件以便执行部署。对于一个ASP.NET Core Web 项目而言,需要准备DeploymentServiceIngress三个部署文件。其中Deployment用于管理Pod运行容器,Service负责暴露服务,Ingress负责配置外部可访问的服务地址等。一个基本的Deployment定义如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment # deploy名称
  labels:
    app: nginx # deploy标签
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx  # 匹配标签
  template:
    metadata:
      labels:
        app: nginx #pod 标签
    spec:
      containers:
      - name: nginx # 容器名称
        image: nginx:1.14.2 # 镜像
        ports:
        - containerPort: 80 # 容器端口号

因此,可以直接将上面的nginx 替换为自己应用的名称,然后替换image即可。由于每次构建镜像的Tag可能不一样,因此这个image值需要动态替换。于是乎,可以定义一个通用的Deployment如下,然后在项目根目录创建一个名为.gitlab-ci的文件夹,并在文件夹下创建名为app.deployment.yaml的文件保存。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: __AppName__-deployment # deploy名称
  labels:
    app: __AppName__ # deploy标签
  annotations:
    app.gitlab.com/app: __AppName__   #定义App注解
    app.gitlab.com/env: __Environment__   #定义环境注解

spec:
  replicas: 3  # 指定三副本
  selector:
    matchLabels:
      app: __AppName__  # 匹配标签
  template:
    metadata:
      labels:
        app: __AppName__ #pod 标签
    spec:
        imagePullSecrets:
      - name: gitlab-registry-secret # 指定上面定义的镜像拉取凭证
      containers:
      - name: __AppName__ # 容器名称
        image: __AppImage__ # 镜像
        ports:
        - containerPort: 80 # 容器端口号

同理可以创建一个通用的Service如下所示,然后创建一个名为app.service.yaml的文件保存。

apiVersion: v1
kind: Service
metadata:
  name: __AppName__-service
spec:
  selector:
    app: __AppName__
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

最后,也创建一个通用的Ingress,保存到app.ingress.yaml文件中。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: __AppName__-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: __AppHost__
      http:
        paths:
          - path: __AppHostPath__
            pathType: Prefix
            backend:
              service:
                name:  __AppName__-service
                port:
                  number: 80

保存后,如下图所示:
image

配置自动发布Job

完成了准备工作,接下来回到流水线编辑器来创建自动发布到Kubernetes的Job。对于发布,首先需要kubectl命令,因此可以通过使用包含kubectl命令的镜像进行发布,其二,就是为当前命名空间创建镜像拉取凭证,第三,进行占位符替换,第四执行kubectl apply -f命令进行部署。具体定义的deploy-job,如下所示:

variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE/$CI_PROJECT_PATH_SLUG:$CI_COMMIT_SHORT_SHA # 定义全局标签,方便后续复用   

deploy-job:
    stage: deploy
    image: bitnami/kubectl:1.19
    environment:
        name: development
    variables:
      AppHost: demo.shengjie.dev # 注意替换为自己的域名
      AppHostPath: /
    before_script:
        - kubectl create secret docker-registry gitlab-registry-secret --docker-server="$CI_REGISTRY" --docker-username="$CI_DEPLOY_USER" --docker-password="$CI_DEPLOY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"  -o yaml --dry-run=client | kubectl apply -f -
    script: 
        - echo $IMAGE_TAG
        - cd .gitlab-ci 
        - sed -i "s#__AppName__#$CI_PROJECT_PATH_SLUG#g" app.deployment.yaml app.service.yaml app.ingress.yaml
        - sed -i "s#__AppImage__#$IMAGE_TAG#g" app.deployment.yaml
        - sed -i "s#__Environment__#$CI_ENVIRONMENT_SLUG#g" app.deployment.yaml
        - sed -i "s#__AppHost__#$AppHost#g" app.ingress.yaml
        - sed -i "s#__AppHostPath__#$AppHostPath#g" app.ingress.yaml
        - cat app.deployment.yaml        
        - kubectl apply -f app.deployment.yaml #部署deploy
        - cat app.service.yaml
        - kubectl apply -f app.service.yaml # 部署service
        - cat app.ingress.yaml 
        - kubectl apply -f app.ingress.yaml # 部署ingress
        - echo 'succeed' 
    cache: [] # 无需使用缓存
    needs:
        - job: publish-job
      - job: build-docker-job # 指定仅镜像构建成功后才进行部署

推荐阅读更多精彩内容