什么是 CI/CD
CI(持续集成)是指持续地集成代码到主干。持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。
CD (持续交付) 是指持续地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就可以部署到生产环境。
在云原生环境下,交付物是 Docker 镜像。
我们需要一份源代码来实践 CI/CD。
gohttpserveropen in new window 是一个简单的用 Go 编写的服务。首先将该项目 fork 到自建的 GitLab 仓库。
读者只需要关注 .gitlab-ci.yml 文件如何编写,以及 k8s 清单文件如何编写即可。
我们先来看下完整的 .gitlab-ci.yml 文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
before_script:
- export
stages:
- build
- deploy
build:
stage: build
tags:
- k8s
image:
name: 10.7.20.31:5000/executor:debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo $AUTH
- echo $CI_REGISTRY
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$AUTH\"}}}" > /kaniko/.docker/config.json
- >-
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile" #
--destination "$CI_REGISTRY_IMAGE:${CI_COMMIT_TAG}" #CI_COMMIT_TAG 未版本号
--destination "$CI_REGISTRY_IMAGE:latest" # CI_REGISTRY_IMAGE 192.168.120.12:5000/hxf1/gohttpserver
--insecure --skip-tls-verify # 这个是针对http的registry
--verbosity debug
rules:
- if: $CI_COMMIT_TAG
deploy:
stage: deploy
tags:
- k8s
image: ongres/kubectl:latest
dependencies:
- build
script:
- kubectl version
- sed -i "s/latest/$CI_COMMIT_TAG/g" deploy/deploy.yaml
- kubectl apply -f deploy/
rules:
- if: $CI_COMMIT_TAG
|
注意这个 auth ,可以通过本地 docker login 拿到 auth,在 cat ~/.docker/config.json,取出里面的 config 即可。
使用 Kaniko 构建 Docker 镜像
Kanikoopen in new window 是一种在容器或 Kubernetes 集群内使用 Dockerfile 构建容器镜像的工具。它解决了 Docker-in-Docker 构建方法的两个问题:
- Docker-in-Docker 需要特权模式才能运行,这是一个重要的安全问题。
- Docker-in-Docker 通常会导致性能下降,而且速度可能非常慢。
我们需要使用容器镜像仓库的身份验证信息来创建 Docker config.json
文件,格式如下:
使用新镜像部署应用
构建好 Docker 镜像后,就可以使用新镜像重新部署应用了。部署方式有多种,这里演示的是使用 kubectl 命令来部署应用。
和一般教程不同的是,我们的 kubectl 镜像使用的不是 bitnami/kubectl,而是 ongres/kubectl,这是因为作者的 k8s 集群是部署在一台 ARM64 架构的 Mac 电脑上。作者到 Docker Hub 上找了个替代品。
这部分的脚本很简单,首先更改 docker 镜像的 tag,然后使用 kubectl 命令来部署应用。
1
2
3
|
script:
- sed -i "s/latest/$CI_COMMIT_TAG/g" deploy/deploy.yaml
- kubectl apply -f deploy/
|
值得注意的是,我们需要在清单文件中,指定 namespace 的值为 default,尽管 namespace 的值默认就是 default。
1
2
3
4
5
|
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: gohttpserver
|
这是因为我们的 gitlab-runner 是跑在 gitlab 名字空间的,默认会将应用部署到 gitlab 名字空间下。
1
2
3
4
5
6
7
|
Running with gitlab-runner 16.6.1 (f5da3c5a)
on gitlab-gitlab-runner-7bcf44dc44-scks4 UTm5ei-4, system ID: r_V7O5QSg29YMB
Preparing the "kubernetes" executor
00:00
Using Kubernetes namespace: apps-gitlab
Using Kubernetes executor with image ongres/kubectl:latest ...
Using attach strategy to execute scripts...
|
部署会报错说权限不够
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$ sed -i "s/latest/$CI_COMMIT_TAG/g" deploy/deploy.yaml
$ kubectl apply -f deploy/
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "apps/v1, Resource=deployments", GroupVersionKind: "apps/v1, Kind=Deployment"
Name: "gohttpserver", Namespace: "default"
from server for: "deploy/deploy.yaml": deployments.apps "gohttpserver" is forbidden: User "system:serviceaccount:apps-gitlab:default" cannot get resource "deployments" in API group "apps" in the namespace "default"
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "/v1, Resource=services", GroupVersionKind: "/v1, Kind=Service"
Name: "gohttpserver", Namespace: "default"
from server for: "deploy/deploy.yaml": services "gohttpserver" is forbidden: User "system:serviceaccount:apps-gitlab:default" cannot get resource "services" in API group "" in the namespace "default"
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "networking.k8s.io/v1, Resource=ingresses", GroupVersionKind: "networking.k8s.io/v1, Kind=Ingress"
Name: "gohttpserver", Namespace: "default"
from server for: "deploy/ingress.yaml": ingresses.networking.k8s.io "gohttpserver" is forbidden: User "system:serviceaccount:apps-gitlab:default" cannot get resource "ingresses" in API group "networking.k8s.io" in the namespace "default"
ERROR: Job failed: command terminated with exit code 1
|
解决这个 serviceaccount 权限不够使用如下 yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: apps-gitlab
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: default-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: deployment-reader
subjects:
- kind: ServiceAccount
name: default
namespace: apps-gitlab
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: deployment-reader
rules:
- apiGroups: [''] #"" indicates the core API group
resources: ['*']
verbs: ['*']
- apiGroups: ['networking.k8s.io']
resources: ['ingresses']
verbs: ['*']
- apiGroups: ['apps']
resources: ['deployments']
verbs: ['*']
|
这个权限绑定,会保证账户拥有创建 deployment 的权限。
最后执行查看部署命令的 log
参考文档:
https://todoit.tech/k8s/gitlab-ci/#%E4%BD%BF%E7%94%A8%E6%96%B0%E9%95%9C%E5%83%8F%E9%83%A8%E7%BD%B2%E5%BA%94%E7%94%A8