gitlab集成k8s的所有方法
1.相关文档
官方关于集成k8s的简介:Integrate Kubernetes to your DevOps Lifecycle
- Deploy software from GitLab to Kubernetes
- Use Kubernetes to manage runners attached to your GitLab instance
- Run the GitLab application and services on a Kubernetes cluster
总体上可以整理出三种集成k8s的方案:
- certificate-based,此功能在14.5之后已经不推荐使用
- kas
- gitlab runner install in kubernetes
在这里我们分别使用三种方案集成一个k8s cluster,并分别对应test,stage,production三个环境,然后分别基于这三种集成方式发布一个测试应用,架构如下图:
2.使用certificate-based集成k8s
gitlab基于证书集成k8s可以在三个level配置:
- 实例级别:Menu > Admin > Kubernetes
- group级别:进入group选择 Kubernetes
- project级别:进入project依次选择Infrastructure > Kubernetes clusters
2.1获取集成集群所需要的所有参数
Kubernetes cluster name:自定义的一个集群名称
Environment scope :这个集群所关联的gitlab environment
API URL:连接这个k8s集群的api-server Endpoint
可以通过如下命令获取:
kubectl cluster-info | grep -E 'Kubernetes master|Kubernetes control plane' | awk '/http/ {print $NF}'
如果是从公网连接还需要把地址修改成公网ip
CA certificate :
可以通过如下命令获取:
kubectl get secrets $(kubectl get secret|awk '/default/{print$1}') -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
Token:
这里使用serviceaccount的token来连接k8s集群,所以这个token拥有哪些权限gitlab就对这个集群具有对应的权限。这里使用cluster-admin的role来创建token:
创建serviceaccount:
kubectl apply -f - << eof
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gitlab-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: gitlab
namespace: kube-system
eof
获取这个serviceaccount的token:
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab | awk '{print $1}')|awk '/token:/{print$NF}'
将上面获取到的参数在添加集群时填入对应的位置:
最后在添加集群之后,能够看到集群的信息了,就表示添加成功:
2.2理解这种模式的原理
这种基于证书连接k8s集群的方式是如何工作的呢?
首先每个k8s集群一定要指定一个Environment scope,即使在创建时没有指定,之后关联gitlab ci中的deploy job时也必须指定一个,因为deploy job就是通过environment的name和k8s集群关联上的,名字一样的job会和对应的k8s集群关联上。
一旦job和k8s集群关联上就会自动注入下面的环境变量,job和k8s集群的交互就是通过这些变量实现的,所以如果不配置基于证书的集成,手动配置这些变量也是可以让某个job关联上对应的k8s集群的。
KUBE_URL |
Equal to the API URL. |
---|---|
KUBE_TOKEN |
The Kubernetes token of the environment service account. Prior to GitLab 11.5, KUBE_TOKEN was the Kubernetes token of the main service account of the cluster integration. |
KUBE_NAMESPACE |
The namespace associated with the project’s deployment service account. In the format <project_name>-<project_id>-<environment> . For GitLab-managed clusters, a matching namespace is automatically created by GitLab in the cluster. If your cluster was created before GitLab 12.2, the default KUBE_NAMESPACE is set to <project_name>-<project_id> . |
KUBE_CA_PEM_FILE |
Path to a file containing PEM data. Only present if a custom CA bundle was specified. |
KUBE_CA_PEM |
(deprecated) Raw PEM data. Only if a custom CA bundle was specified. |
KUBECONFIG |
Path to a file containing kubeconfig for this deployment. CA bundle would be embedded if specified. This configuration also embeds the same token defined in KUBE_TOKEN so you likely need only this variable. This variable name is also automatically picked up by kubectl so you don’t need to reference it explicitly if using kubectl . |
KUBE_INGRESS_BASE_DOMAIN |
From GitLab 11.8, this variable can be used to set a domain per cluster. See cluster domains for more information. |
比如现在有这样一个已经集成好的k8s集群:
某个job想要关联这个集群.gitlab-ci.yml则应该写成:
deploy_to_public:
stage: deploy
when: manual
environment:
name: test-public
url: http://<url>
image:
name: bitnami/kubectl:latest
entrypoint: ['']
script:
- echo $KUBE_URL
tags:
- docker
这里还有一个特别需要注意的点:在environment字段下面还可以指定k8s的namespace,类似:
environment:
name: production
url: https://example.com
kubernetes:
namespace: test
这里需要注意在添加k8s集群时是否勾选了GitLab-managed cluster,如果勾选了则会由gitlab去k8s中创建对应的namespace,如果没有勾选则需要自己手动去k8s集群中创建对应的namespace。这里建议不要勾选由自己手动去创建namespace,因为如果让gitlab去管理这个配置,一旦配置出错就会导致ci/cd的job出错,报错类似下图:
2.3部署测试应用
在k8s中创建pull镜像的secret:
kubectl create secret docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_DEPLOY_USER" --docker-password="$CI_DEPLOY_PASSWORD" -o yaml --dry-run=client | kubectl apply -f -
在项目中创建一个用于部署deployment的测试文件:
这就是一个很简单deployment,利用NodePort暴露服务,可根据实际情况进行修改。
kube-deployment.yaml:
apiVersion: v1
kind: Service
metadata:
labels:
app: test
name: test
spec:
ports:
- name: tcp
port: 5000
protocol: TCP
targetPort: 5000
nodePort: 30618
selector:
app: test
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test
name: test
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
imagePullSecrets:
- name: gitlab-registry
containers:
- image: <your_image>
name: test
imagePullPolicy: Always
定义pipeline中的deploy job:
deploy_to_test:
stage: deploy
when: manual
environment:
name: test-public
url: http://<url>
kubernetes:
namespace: test
image:
name: bitnami/kubectl:latest
entrypoint: ['']
script:
- sed "s/CI_ENVIRONMENT_SLUG/$CI_ENVIRONMENT_SLUG/g" kube-deployment.yaml|kubectl apply -f -
tags:
- docker
这里只需要环境名称和k8s集群的环境名称相同即可,runner的话可以任意选择,只有能运行kubectl的镜像即可,这样就能根据gitlab默认生成的kubeconfig调用api-server了。
3.使用kas集成k8s
注意:在14.5以前kas是属于Premium的功能,14.5以后免费开放。
在kas中有两种workflow:
-
GitOps workflow:也被称为pull-based workflow,它是由agent实时去监控manifest所在的git repo,一旦其中的manifest发生变化,就主动的将配置pull并应用到k8s集群中。所以gitops workflow中不需要ci/cd,也能发布和更新k8s中的应用。
-
CI/CD workflow:也被称为push-based workflow,它需要借助ci/cd,每次的配置变更由ci/cd主动的将配置推送到k8s集群中。
3.1在gitlab中启用kas
可以使用gitlab-ctl status
查看是否启用了gitlab-kas这个组件,如果没有启用,可以按照下面的步骤启用。
vim /etc/gitlab/gitlab.rb
gitlab_kas['enable'] = true
gitlab-ctl reconfigure
3.2在k8s中安装agent
3.2.1前提条件
- 安装helm
- Gitlab server需要是以https的方式暴露
3.2.2配置GitOps workflow
在需要向k8s部署应用的仓库相同的组下面创建一个名为agentk
的项目仓库。
在这个仓库中创建agent的配置文件,在其中定义GitOps workflow,配置文件的路径始终满足以下规则:.gitlab/agents/<agent-name>/config.yaml
gitops:
manifest_projects:
- id: "<group>/<project>"
default_namespace: <k8s namespace>
paths:
- glob: '/**/*.{yml,yaml,json}'
ci_access:
projects:
- id: <group>/<project>
groups:
- id: <project>
理解这个配置文件:
gitops: 定义了gitops workflow中需要监控哪些仓库下的哪些文件,并将这些文件的manifest同步到k8s中。
- manifest_projects:定义用于存放k8s manifest的仓库
- id: 仓库的路径
- default_namespace:当manifest里面没有指定namespace时,默认部署的namespace
- paths:指明manifest文件在仓库中具体的路径
ci_access: 定义了ci/cd workflow中哪些project和group能够访问并使用当前这个agent(前提是这些project和group要和agent在同一个group下面)
- projects: 项目的path
- groups:组的path
在agentk
仓库注册agent:
在项目中依次选择:Infrastructure > Kubernetes clusters > Connect a cluster (agent)
输入刚才已经创建配置文件的agent名称:,然后点击register,此时会弹出在k8s中安装agent的命令,直接复制运行即可:
需要注意的是,按照这个命令运行直接安装的是最新版本的gitlab-agent
,但是我们最好安装和gitlab server相同的版本,所以可以先使用如下命令:helm search repo -l gitlab/gitlab-agent
查找需要的版本,再使用指定版本进行安装。
helm upgrade --install gitlab-agent gitlab/gitlab-agent --version 0.6.1 \
--namespace gitlab-agent \
--create-namespace \
--set config.token=y3QhfBmhezBsXBsjLWVpLuzYqBbJhypWA9y-gC8-kPTKsni5-w \
--set config.kasAddress=wss://<gitlab_url>/-/kubernetes-agent/
最后可以看到agent的状态
注意:
一个agent只能被和它在相同group下的project和同group下的subgroup所引用。也就是说其实每个group下面我们只需要配置一个agent就可以了,然后其它project就能自由在pipeline中调用。
3.3使用GitOps workflow部署测试应用(仅专业版以上可用)
创建一个public的group(k8s-public),在里面创建一个public的project(manifest)用于存放manifest
kube-deployment
apiVersion: v1
kind: Service
metadata:
labels:
app: test
name: test
spec:
ports:
- name: tcp
port: 8080
protocol: TCP
targetPort: 8080
nodePort: 30618
selector:
app: test
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test
name: test
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
imagePullSecrets:
- name: gitlab-registry
containers:
- image: <your_image>
name: test
imagePullPolicy: Always
env:
- name: CI_ENVIRONMENT
value: GitOps
然后修改agentk repo的配置文件,将这个仓库加入到gitops中:
gitops:
manifest_projects:
- id: "<group>/<project>"
default_namespace: <k8s namespace>
paths:
- glob: '/**/*.{yml,yaml,json}'
- id: "k8s-public/manifest"
default_namespace: <k8s namespace>
paths:
- glob: '/**/*.{yml,yaml,json}'
reconcile_timeout: 10s
ci_access:
projects:
- id: <group>/<project>
groups:
- id: <project>
保存并提交配置之后,去查看k8s中agent的日志就可以看到,agent中新增了一个worker,监视的是k8s-public/manifest这个仓库,并且会在k8s中部署manifest中的资源。然后可以尝试修改k8s-public/manifest中的配置,看看同步的效果!
3.4部署测试应用(使用ci/cd workflow)
在和agent相同的group下面创建一个测试的项目。项目的pipeline脚本中通过指定context即可和对应的agent所在的k8s集群进行交互。
示例:
deploy_to_stage:
stage: deploy
when: manual
environment:
name: stage
url: http://<url>
image:
name: bitnami/kubectl:latest
entrypoint: ['']
script:
- kubectl config get-contexts
- kubectl config use-context /path/to/project:agent-name
- sed "s/CI_ENVIRONMENT_SLUG/$CI_ENVIRONMENT_SLUG/g" kube-deployment.yaml|kubectl -n ${CI_ENVIRONMENT_SLUG} apply -f -
tags:
- docker
context的命名由agent所在的project path加agent的name组成。
这里依然使用前面所创建的测试manifest部署应用。
4.使用gitlab runner集成k8s
4.1在k8s集群中安装gitlab runner
helm repo add gitlab-jh https://charts.gitlab.cn
helm fetch gitlab-jh/gitlab-runner --version 0.40.0
tar -xf gitlab-runner-0.40.0.tgz
cd gitlab-runner/
vim values.yaml 配置runner
gitlabUrl:
runnerRegistrationToken:
config: |
[[runners]]
name = "k8s"
executor = "kubernetes"
[runners.kubernetes]
image = "bitnami/kubectl:latest"
image_pull_secrets = ["gitlab-registry"]
privileged = true
pull_policy = ["if-not-present"]
memory_limit = "1Gi"
service_cpu_limit = "1"
service_memory_limit = "1Gi"
helper_cpu_limit = "500m"
helper_memory_limit = "100Mi"
poll_interval = 5
poll_timeout = 3600
service_account = "gitlab-runner"
[[runners.kubernetes.volumes.empty_dir]]
name = "docker-certs"
mount_path = "/certs/client"
medium = "Memory"
rbac:
create: false
serviceAccountName: gitlab-runner
创建所需的k8s资源,并部署runner:
kubectl create ns gitlab-runner
kubectl -n gitlab-runner create sa gitlab-runner
kubectl create clusterrolebinding gitlab-runner-cluster-admin --clusterrole=cluster-admin --serviceaccount=gitlab-runner:gitlab-runner
helm -n gitlab-runner install gitlab-runner . --set runners.tags="k8s\,prod"
部署测试应用(依然使用上面的manifest):
pipeline的job:
deploy_to_pruduction:
stage: deploy
when: manual
environment:
name: pruduction
url: http://<url>
image:
name: bitnami/kubectl:latest
entrypoint: ['']
script:
- sed "s/CI_ENVIRONMENT_SLUG/$CI_ENVIRONMENT_SLUG/g" kube-deployment.yaml|kubectl -n ${CI_ENVIRONMENT_SLUG} apply -f -
tags:
- k8s