1. 故事背景

如果你在使用gitlab-ci,也在使用k8s,但不知道怎么集成(就是通过gitlab-ci调用k8s),那你可以看看。 没过CET-4的我,通过google、官网和my homie,终于通了!

2. 提前准备

  • 本次试验是在CentOS 7.4 64位系统,root用户下进行
  • Gitlab环境
  • 拥有Runner executordocker的Gitlab-Runner(有Docker执行环境即可)
  • Kubernetes(k8s)集群

3. 集成

3.1 新建项目

Gitlab-CI与Kubernetes的集成是项目级,每个项目都需要,为了测试,我们先新建一个项目。 这里我建的项目名叫opendata,是一个空项目,只建一个文件.gitlab-ci.yml,仅仅为了测试集成效果。 文件内容编辑好后,先提交一把,这个时候,gitlab-ci是肯定失败的,先忽略。

内容如下:

test:
  image: domsn/kubectl-deployer
  tags:
    - docker
  environment:
    name: staging
    url: https://your-domain.com
  script:
    - kubectl version
    - kubectl get pods

关键解释:

Key Description
image 指定镜像,主要是装了kubectl
tags 通过这个命中Runner executor为docker的Gitlab-Runner(一般是在注册Runner的时候,填的tag)
environment 必须要设置,值不太重要,参考官网

3.2 配置Kubernetes

在gitlab里打开项目opendata,在路径CI/CD -> Kubernetes下,选择自建Kubernetes的模式。

需要配置5项内容:

  • Kubernetes集群名称(Kubernetes cluster name
  • API地址(API URL
  • CA证书(CA Certificate
  • Token
  • 项目命名空间(Project namespace (optional, unique)

整个集成最重要最麻烦的地方就在于填这五项内容,下面我会一项项说明:

Kubernetes集群名称(Kubernetes cluster name

这里和项目名称一样,填opendata

API地址(API URL

这里需要填k8s默认服务Kubernetes的Endpoint,而Endpoint一般是内网地址。因为我所有的机器都在阿里云的ECS,所以内网是可以直接通的。如果你不是这种情况,你也许在这里可以找到答案

登录k8s集群的机器上,执行👇命令

# 获取Endpoint
> kubectl get endpoints kubernetes -o json | jq -r '.subsets[0].ports[0].name + "://" + .subsets[0].addresses[0].ip + ":" + (.subsets[0].ports[0].port | tostring)'
https://172.32.174.43:6443

# 如果这种拿不到正常的结果,这样应该没问题 
> kubectl get endpoints kubernetes
NAME         ENDPOINTS            AGE
kubernetes   172.32.174.43:6443   95d

# 如果还不行,最后一招,没辙了
> kubectl describe svc kubernetes
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.96.0.1
Port:              https443/TCP
TargetPort:        6443/TCP
Endpoints:         172.32.174.43:6443
Session Affinity:  None
Events:            <none>

综上所述,这里填https://172.32.174.43:6443

CA证书、Token、项目命名空间

因为这三项关系比较紧密,所以放在一起说明

按照我的认识,每个项目(或者同一类项目)会定义一个namespace,而不放在默认的命名空间default里。对于两个系统的集成,特别是服务提供商(k8s)都会对接口进行一系列的权限管理,不可以直接调用。

因此,我们需要做两件事。

  1. 在k8s里创建namespace,这里定为项目名opendata
  2. 在k8s里创建一个账号,提供给gitlab-ci集成使用

新建文件01-namespace.yml,内容如下:

---
apiVersion: v1
kind: Namespace
metadata:
  name: opendata
  labels:
    name: opendata

创建namespace

> kubectl apply -f 01-namespace.yml
serviceaccount/opendata created

新建文件02-account.yml,内容如下:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: opendata
  namespace: opendata
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: opendata
  namespace: opendata
subjects:
  - kind: ServiceAccount
    name: opendata
    namespace: opendata
roleRef:
  kind: ClusterRole
  name: cluster-admin

注:这里赋予的角色是cluster-admin,权限很高,在实际的使用场景,最好根据自己的权限需要,定义自己需要的Role。譬如:我的需求是发布或者替换新的镜像,这样的话,我赋予deployment的操作权限即可,其他操作一概不允许,可以提高k8s集群的安全性。

创建ServiceAccountClusterRoleBinding

> kubectl apply -f 02-account.yml
serviceaccount/opendata created

命名空间和账号已准备就绪,找出TA的CA证书和Token吧

# 找出账号秘钥的名称
> kubectl get serviceaccount opendata -n=opendata -o json | jq -r '.secrets[0].name'
opendata-token-tzntp

# 根据上面的秘钥名称,找到CA证书
> kubectl get secret opendata-token-tzntp -n=opendata -o json | jq -r '.data["ca.crt"]' | base64 -d
-----BEGIN CERTIFICATE-----
MIICyDCCAbCgAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
cm5ldGVzMB4XDTE4MDcwNTA2MTgxMFoXDTI4MDcwMjA2MTgxMFowFTETMBEGA1UE
AxMKa3ViZXJuZXRlczCCASIwQQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL0+
mJslbWHoZehZdpRgPE9t4TWeHBij4WLa7SMuPAz5AHnsoLqVepovdTU6XQDpS86e
LFcGJKW2+eYOQi23G9zeluySo+CTQC9CVNSoJtn5eDOKs9QVRAXi0JsccY0G7YLd
1p6nv65H4IHRsBTEg6UWWiOlvTHo+9NPnjdANIi4+b65Iid6AbON4n8xMmzEyFVY
iTgl7wRRNaQWOvjOyFgy5gRVVVFzXJ0P5JuwxyUczY91TH5zd8WrFEvaE2GzbW1b
HCIe1eZHRIGERaFT10sNp9mYSaPNuzMPuI5Fm1zx5Yvn7j+vjYpRZhzdgiAs095I
VvMK2rmfbnxVaXhJJ8ECAwEAAaMjMCAwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHz0weT+Ztit6wMTZSmlkQtiO8qF
iHXNMbUN6fDSDEmZI8SL4YYeHgD5JXQOIkNdOQAG1nLUIgHEfWBU2b2zkwFmHB9x
fF/O4JAXwcR23mSGtBGf19Bonf5XalnwS0aBXIM1qD3fNY45NWFPC2zq5CsiM2pE
EjEpSQFqKLr35attktIT9UmnQJ/tkmYcDB7SMGhOy6zg7uwJzz5kV7gNJBvhUkrb
tXPI/P7Ua1t/L/j5idTaX3Bir9G93JAtkZr3RFUrwKgBVLvRIfc79JY6mm5knML0
/Tq+qC1BKcX/dest9WJXoGV1hjKma0UWoJmfBSdYMoNOtHOjoi0TQtZVm44=
-----END CERTIFICATE-----

# 根据上面的秘钥名称,找到Token
> kubectl get secret opendata-token-tzntp -n=opendata -o json | jq -r '.data.token' | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdMJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJvcGVuZGF0YSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJvcGVuZGF0YS10b2tlbi10em50cCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJvcGVuZGF0YSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjdlMDk1ZmQxLWFiNjktMTFlOC05YzQ4LTAwMTYzZTBjNWQyYyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpvcGVuZGF0YTpvcGVuZGF0YSJ2.vujCCWoogqMtPt0N6FwXOqPC9GTcAXngmdPBdOLULWAj3qsOVdLshy8Ztv88fwp_8XtfWlP9Nw78E3XLFU_rRHMI55EHbpsixy9je2Yd7Swe44qsFMA-1YoBsf78Eatlppy9CY1NWLhXICgO4czfs4UnhLfY8Wh7pjgBm8Q4AxQT9ag2wHYAz_T-2ZQj8QwFUMnesk0rPgdZ3RnqQ2Dif7nVJujyCcerp0U_yh0OACTPq62A2chZyE2yd-4G67JIYNI2ybvwfIQD1PgfUciD_t5IytbndcM-_951niYqObscvFZh2yQGL_a2Rrvn7NimmhDIWnDHi2AXPjwZLG7odw

所有的选项都已经找到值,填好,保存。

3.3 测试

条件已具备,测试一把,我们修改一下.gitlab.yml,提交。

test:
  image: domsn/kubectl-deployer
  tags:
    - docker
  environment:
    name: staging
    url: https://your-domain.com
  script:
    - kubectl version
    - kubectl get pods
    - kubectl get pods --all-namespaces

如无意外,结果类似如下:

成功的模样