云原生架构系列之NodeJS自动CI/CD

本文以NodeJS开发框架为例,讲解如何组合Kubernetes、GitLab、Docker、Docker Registry等技术,实现CI/CD的自动化。

NodeJS 示例

本文假设开发机器已经安装nodejs、express、express generator、docker

通过以下命令产生一个基本框架

express --no-view --git

然后运行nodejs,在浏览器中访问http://localhost:3000/即可看到express的页面。

npm start

在Kubernetes集群中创建Gitlab账户

创建gitlab-service-account.yaml文件

该文件中创建了一个gitlab-service-account账户,并做了角色绑定。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab-service-account
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: gitlab-service-account-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: gitlab-service-account
    namespace: default

Kubernetes中创建账户和角色绑定

kubectl apply -f gitlab-service-account.yaml

部署Docker Registry

本示例选择在CentOS 7上安装VMware Harbor,如何部署请参阅网上其他文章,或看稍后的文章。

GitLab 配置

GitLab的部署在本篇中也不详述,请参与其他部分-。

为了使用CI/CD,我们需要在GitLab中设置环境变量。

位置:项目设置->CI/CD->环境变量,展开后即可设置。

注意:为了安全,REGISTRY_PASSWORD, K8S_USER_TOKEN, K8S_CA_PEM 应该予以保护。

REGISTRY_SERVER: Docker Registry的URL,!!!如果是Docker Hub,则需要修改本文件

REGISTRY_USER: 登录Docker Registry的用户名

REGISTRY_PASSWORD: 登录Docker Registry的密码

K8S_SERVER: Kubernetes API Server

K8S_USER_TOKEN: 链接Kubernetes集群的用户令牌。

获取用户TOKEN的方式:

kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}')

K8S_CA_PEM : Kubernetes集群的CA证书

获取方式:

kubectl get secret  -o jsonpath="{['data']['ca\.crt']}"

通过 GitLab 构建 Docker

接下来,我们在看在GitLab中如何构建Docker

创建.gitlab-ci.yml文件

image: docker:latest
services:
  - docker:dind

stages:
  - build
  - deploy

variables:
  CONTAINER_IMAGE: testapp:${CI_COMMIT_SHORT_SHA}
  DOCKER_HOST: tcp://localhost:2375/
  DOCKER_DRIVER: overlay2
  REGISTRY_IMAGE: ${REGISTRY_SERVER}/library/testapp:${CI_COMMIT_SHORT_SHA}

build:
  stage: build
  script: 
    - docker login -u ${REGISTRY_USER} -p ${REGISTRY_PASSWORD} ${REGISTRY_SERVER}
    - docker build -t ${CONTAINER_IMAGE} .
    - docker tag ${CONTAINER_IMAGE} ${REGISTRY_IMAGE}
    - docker push ${REGISTRY_IMAGE}
    - docker tag ${CONTAINER_IMAGE} testapp:latest

其中docker:latest是来自于Docker Hub的镜像,并使用Docker-in-Docker(dind)技术。

${CI_COMMIT_SHORT_SHA}:GitLab在提交代码时会生成一个简短的SHA码,这是该环境变量;

DOCKER_HOSTDOCKER_DRIVER必须如此设置,否则将会出现无法打开socket的错误提示。

REGISTRY_IMAGE 是组合后的本地Registry的URL

其中的Build脚本对应几个步骤:

  1. 登录本地Registry;
  2. 构建Docker
  3. 标记Docker为本地Registry
  4. 推送Docker到本地Registry
  5. 标记本地Docker为最新版本。这条实际上没有用。

创建 Dockerfile

FROM node:10

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install --registry 
RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 3000
CMD ["npm", "start"]

部署到Kubernetes集群中

创建deployment.yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: testapp
  labels:
    app: testapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: testapp
      tier: frontend
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: testapp
        tier: frontend
    spec:
      containers:
        - name: testapp
          image: docker.shmtu.edu.cn/library/testapp:
          ports:
            - containerPort: 3000
          livenessProbe:
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 2
            periodSeconds: 2
          readinessProbe:
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 2
            periodSeconds: 2
      imagePullSecrets:
        - name: local-registry    

其中有几个需要说明的地方:

1、因为需要选用本地Registry的镜像,所以需要先创建secret:

kubectl create secret docker-registry local-registry \
--docker-server=docker.shmtu.edu.cn \
--docker-username= \
--docker-password=

创建完成后,可以查看是否正确:

kubectl get secret local-registry --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d

2、作为App监控的livenessProbe和readinessProbe最好也配置上。

其余参数不做讲解。

部署Service

由于deployment.yaml每次都会执行,其中的pod都会创建,这样就需要我们把service部署文件放在外面,第一次部署之前执行一次即可。

apiVersion: v1
kind: Service
metadata:
  name: testapps-svc
  namespace: gitlab-managed-apps
  labels:
    app: testapp-svc
spec:
  type: NodePort
  ports:
  - port: 3000
    nodePort: 30300
  selector:
    app: testapp
    tier: frontend

修改 .gitlab-ci.yml 文件

在 .gitlab-ci.yml 文件中,添加deploy阶段的内容

deploy:
  stage: deploy
  image: docker.shmtu.edu.cn/library/helm-kubectl:1.14.1
  script:
    - kubectl version
    - kubectl config set-cluster k8s --server="${K8S_SERVER}"
    - kubectl config set clusters.k8s.certificate-authority-data "${K8S_CA_PEM}"
    - kubectl config set-credentials gitlab --token="${K8S_USER_TOKEN}"
    - kubectl config set-context default --cluster=k8s --user=gitlab
    - kubectl config use-context default
    - sed -i "s//${CI_COMMIT_SHORT_SHA}/g" deployment.yaml
    - cat deployment.yaml
    - kubectl apply -f deployment.yaml

注意:

1、目前dtzar/helm-kubectl Docker镜像支持到kubectl v1.13.4,而我们的集群是v1.14.0,所以我们自行Build了这个Docker,并推送到本地的Docker Registry中。

2、其中的cat deployment.yaml并不必要,仅仅是为了排错使用,可以去掉该命令。

你可能感兴趣的:(云原生架构系列之NodeJS自动CI/CD)