CI/CD每一个任务都是一个独立的容器,互不干扰,我们可以创建以下几个任务阶段:

  • 项目构建阶段,安装依赖以及构建项目
  • 容器构建阶段,对构建好的项目打包成Docker镜像
  • 部署K8S环境
  • 部署最终环境

上面说过,执行CI/CD时是通过一个独立的容器去执行的,我们没有办法能够直接CI/CD的文件复制到宿主机上,所以我们需要打包阶段来构建镜像,其次我们在CI/CD的容器中,也没有办法直接对宿主机的K8S集群创建pod和service,在这里我们还需要额外制作一个能够在宿主机上创建pod和service的镜像。

创建“宿主机执行者”容器

先来普及以下,kubectl能够操作K8S集群,是根据配置和证书而来的,我们通过MINIKUBE启动一个集群的时候,自动就已经帮忙我们做好了这些事,默认我们通过kubectl就是操作当前服务器下的K8S集群,如果我们拿到远程K8S集群的证书和信息,那么我们也可以在本地对远端的K8S集群做操作。

我们创建的这个容器,就是包含了该K8S集群的信息,这样CI/CD的时候就可以使用这个容器对宿主机创建pod和service。

让我们来编写Dockerfile:

FROM alpine:latestRUN mkdir -p /root/.minikubeCOPY kubectl /usr/bin/COPY kube/config /root/.kube/COPY minikube/* /root/.minikube/

我们把kubectl命令复制到容器中,方便使用,同时把~/.kube/config和~/.minikube/下的ca.crtclient.crtclient.key文件复制到容器中。

最后使用命令docker build -t ${imagename}来打包镜像。

对于构建好的Docker镜像如果不希望直接发布到外网,可自建一个Docker仓库,这里推荐使用harbor,harbor的安装并没有什么坑点,依照官方文档一般都可以顺利安装,这里也不会对harbor的使用做详细说明。

镜像制作完成后我们需要推送到私有仓库,推送以前我们需要先给镜像打上tag。

要推送到harbor的话,tag需要遵循server/group/imagename的规则,既比如我们的harbor访问地址是harbor.mydocker.com,项目分组是frontend,那么这个标签就应该写成:harbor.mydocker.com/frontend/imagename

接着我们登陆docker:

$ docker login harbor.mydocker.com> 输入用户名和密码> 显示成功$ docker push harbor.mydocker.com/frontend/imagename

最终等镜像推送成功后,我们应该可以在harbor中查看到镜

配置CI/CD脚本

这里不对gitlab-ci的配置展开详细说明,官方文档的介绍已经非常详细。

下面我们尝试对开头我们描述的5个阶段进行Demo配置:

# 这里就是我们的 宿主机执行者 镜像image: harbor.com/frontend/gaia_builder:0.0.1# 对应开头所说的4个阶段stages:  - build_project  - build_docker  - deploy_k8s  - deploy_serverbuild_project:  # 我们构建项目时所用到的环境以及工具  # 比如nodejs版本,yarn等工具,都由这个镜像提供  # 这个镜像后面会说到具体的制作方法  image: harbor.com/frontend/frontend_toolkit:0.0.1  # 执行时机改为手动,我们并不希望每次commit的时候都会自动构建出一个环境  when: manual  stage: build_project  # 将打包资源作为附件往下个阶段传递  artifacts:    paths:      - dist  # 希望使用Runner的Tag  tags:    - fek8s  script:    # 执行具体的构建脚本,根据实际情况做调整即可    # 最终我们会删除node_modules以减少我们服务镜像的体积    - yarn install --forzen-lockfile    - yarn build    - rm -rf node_modules/build_docker:  image: docker:latest  when: manual  # 开头我们配置的Runner就是在Docker下执行的,所以这里当我们要打包Docker镜像的时候,相当于是在Docker下执行Docker  # 下面的配置可以理解为标配  variables:    DOCKER_DRIVER: overlay2    DOCKER_TLS_CERTDIR: ''    DOCKER_HOST: tcp://127.0.0.1:2375    # 导出一些通用的环境变量,方便后面重复使用    DOCKER_IMAGE_NAME: $GITLAB_USER_LOGIN-$CI_BUILD_REF_NAME    DOCKER_IMAGE_TAG: harbor.com/myproject/$GITLAB_USER_LOGIN-$CI_BUILD_REF_NAME:latest  services:    # dind是docker in docker的缩写    # 通过--insecure-registry参数指定,我们私有仓库的代码是合法的    - name: docker:dind      command: ["--insecure-registry=harbor.com"]  stage: build_docker  dependencies:    - build_project  tags:    - fek8s  script:    # 这个镜像后面会说到,它是服务的基础镜像    - export CACHE_IMAGE=harbor.com/frontend/gaia_nginx:latest    # 拉取镜像,并抑制因stderr的输出导致ci/cd执行失败    - docker pull $CACHE_IMAGE || true    # 构建服务镜像    - docker build --cache-from $CACHE_IMAGE -t $DOCKER_IMAGE_TAG -f gaia/Dockerfile .    # 登录私有化Docker服务    # 考虑到不同的用户,登录账号密码都不同,所以将其做成变量    # 可通过Gitlab项目设置中CI/CD中添加变量来保护    - docker login -u $DOCKER_USERNAME -p $DOCKER_PWD harbor.com    # 最终推送服务镜像到服务器    - docker push $DOCKER_IMAGE_TAGdeploy_k8s:  when: manual  stage: deploy_k8s  tags:    - fek8s  script:    # 由于service的名字无法使用下划线,而我们的分支名经常会使用到下划线,所以将其替换为横线防止错误    - export K8S_SVC_BRANCH=$(echo $CI_BUILD_REF_NAME | sed 's/_/-/g')    # 为了减少环境构建成本,服务名固定为`${username}-${branch}-svc`的格式    - export SVC_NAME=$GITLAB_USER_LOGIN-$K8S_SVC_BRANCH-svc    # 删除老的服务    - kubectl delete svc $SVC_NAME --ignore-not-found --namespace=default    # 删除老的部署    - kubectl delete deploy $SVC_NAME --ignore-not-found --namespace=default    # 创建新的服务    - kubectl run $SVC_NAME --image=harbor.com/myproject/$GITLAB_USER_LOGIN-$CI_BUILD_REF_NAME:latest --namespace=default    # 部署服务,并暴露80端口,方便K8S服务器队其转发    - kubectl expose deploy $SVC_NAME --port=80 --namespace=defaultdeploy_server:  image: curlimages/curl:latest  stage: deploy_server  tags:    - fek8s  needs: ["deploy_k8s"]  script:    # 调用宿主机(也就是K8S服务器)的服务,来重载nginx转发    # 这类的服务后面会进行说明    - curl -X POST 10.10.10.10:3500/svc

至此我们的ci脚本已配置完毕,接下来我们完成本文遗留下来的一些基础镜像和服务。

使用K8S搭建前端测试环境 - 前言
使用K8S搭建前端测试环境 - K8S环境搭建
使用K8S搭建前端测试环境 - Gitlab集成K8S
使用K8S搭建前端测试环境 - 创建CI/CD
使用K8S搭建前端测试环境 - 基础服务搭建
使用K8S搭建前端测试环境 - 总结