前言
基于Gitlab,Gitlab-Runner和Gitlab集成的CICD的DevOps工作流部署容器应用到测试或生产环境,可以快速方便的通过代码迭代自动部署到相应环境中,我已经提前准备好了容器内环境的Gitlab和Gitlab-Runner,有需要的同学可以鉴别参考,以及准备好Harbor私有镜像仓用来镜像的存储和转移,以此为前提进行我们的实践。
参考
gitlab-runner + k8s 实现自动部署_慕课手记 (imooc.com)
一、打通Gitlab和K8S的工作流
这里我会介绍两个办法,一个是通过安装好Kubectl软件的镜像来导入k8s-api-config去和我们的K8S集群进行互动。另一个则是在Gitlab-Runner的镜像去直接导入。
1.配置文件变量导入镜像法
(1)构建镜像
构建一个Kubectl镜像来方便我们部署的时候进行操作,下面我们用一个dockerfile来构建
FROM alpine:latest
ARG KUBE_LATEST_VERSION=v1.23.10
# 使用alpine:latest作为基础镜像
# 下载kubectl二进制文件并设置可执行权限
RUN apk add --update -t deps curl && \
curl -L https://storage.googleapis.com/kubernetes-release/release/${KUBE_LATEST_VERSION}/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl && \
chmod +x /usr/local/bin/kubectl
# 安装必要的依赖(curl),并下载kubectl二进制文件到/usr/local/bin目录,并赋予可执行权限
# 清理安装过程中的临时文件和缓存
RUN apk del --purge deps && \
rm /var/cache/apk/*
# 删除已安装的依赖包及其依赖,以及清理apk缓存,减小镜像体积
使用docker build来构建,构建完后,打上标签,然后登录harbor仓库给推送过去方便我们的统一管理和维护性迭代。
docker build --build-arg KUBE_LATEST_VERSION="v1.23.10" -t kubectl:v1.23.10 .
docker login $HARBOR_URL -u $HARBOR_USERNAME
docker tag kubectl:v1.23.10 $HARBOR_URL/library/kubectl:v1.23.10
docker push $HARBOR_URL/library/kubectl:v1.23.10
(2)准备K8S配置文件并写入Gitlab管理的环境变量内
-
配置文件也可以集成在镜像里面,但是不太灵活,一旦配置有变或者有多个集群,镜像就得修改或者准备多个版本,因此通过 gitlab ci/cd 环境变量传递
-
首先取得配置信息,通过命令
kubectl config view --raw -o yaml
得到配置信息,复制到 gitlab 的 ci/cd 环境变量中 -
这里要注意的是,命令必须带参数
--raw
,为了将 certificate-authority-data 的值输出,否则只能看到 DATA+OMITTED。另外,环境变量必须选择文件类型,否则最后输出格式不对,导致mapping values are not allowed in this context
错误,当然选择-o json
,使用 json 格式,就不用担心格式问题 -
记得修改其中lb.kubernetes.local为master节点的IP地址
这里因为流水线都会用到这个kube_config文件,所以我直接在全局设置的变量中填入,这里也有我提前做好的harbor的相关环境变量。
到这一步别忘了也给你的gitlab在harbor配置一个专用的账户和存储变量哦
(3)使用Gitlab-CI流水线测试该镜像是否可以成功管理K8S集群
重要前提:之前我们的Gitlab-runner中已经映射了主机的docker给Gitlab-runner,所以这里是可以直接使用docker命令的。
在Gitlab项目中编辑流水线编辑器如图所示:
stages:
- pull
- test
push:
stage: pull
script:
- docker images
- docker login $HARBOR_URL -u $HARBOR_USERNAME -p $HARBOR_PASSWORD
- docker pull $HARBOR_URL/library/kubectl:v1.23.10
test:
stage: test
image: $HARBOR_URL/library/kubectl:v1.23.10
script:
- mkdir $HOME/.kube && cat $KUBE_CONFIG > $HOME/.kube/config
- kubectl get pods -n gitlab
提交后看到流水线如图所示就代表已成功搭建该工作流
这样我们就算是完成了这一步啦。
2.Runner配置法
前面提到的Gitlab-runner其实可以直接配置helper和主机的映射关系,首先创建k8s服务账户给Gitlab-runner授权。
kubectl create secrete generic -n gitlab --from-file ~/.kube/config
在Gitlab-runner的配置中有:(为了方便观看,这里用的是Kubesphere的Web管理平台展示)
我们把这里的注释改掉,并且将上方默认的指定镜像的参数改成我们harbor里面已经打包好了的基于alpine的kubectl镜像(没有的话用dockerfile去打包一个也很容易的)。
这样我们可以直接省略掉.gitlab-ci文件中的
二、一个简单的CICD项目演示
项目介绍
我这里用了我自己平时图方便做的v2rayReporter的v2ray订阅发布程序来作为一个示例
这里的代码文件结构主要是 源代码+dockerfile+k8s-app.yml+.gitlab-ci.yml
dockerfile用于编译我的代码构建运行时镜像
k8s-app.yml用于连接k8s集群时所部署的应用的配置
.gitlab-ci是我们cicd的主要工程配置
代码和配置
dockerfile
# 第一个阶段:使用Golang镜像构建可执行文件
FROM $HARBOR_URL/library/golang:1.20.7 AS builder
# 设置工作目录
WORKDIR /app
# 复制代码
COPY ./app /app/
# 编译可执行文件 netgo标签是为了能够在alpine上运行
RUN go build -o v2rayReporter --tags netgo ./main.go
# 第二个阶段:使用Alpine Linux镜像作为最终镜像
FROM alpine:latest
# 设置工作目录
WORKDIR /app
# 从第一个阶段中复制可执行文件到Alpine镜像中
COPY --from=builder /app/v2rayReporter /app/
# 声明运行时的命令
CMD ["./v2rayReporter"]
下面是部署Deployment的yaml文件,我们要记得在template里面加上一个时间戳用于实现滚动更新的效果,镜像因为版本用的latest可以试试将拉取策略改为一直拉取
apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
name: v2rayreporter
namespace: network
labels:
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
annotations:
servicemesh.kubesphere.io/enabled: 'true'
spec:
selector:
matchLabels:
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
addOwnerRef: true
componentKinds:
- group: ''
kind: Service
- group: apps
kind: Deployment
- group: apps
kind: StatefulSet
- group: networking.k8s.io
kind: Ingress
- group: servicemesh.kubesphere.io
kind: Strategy
- group: servicemesh.kubesphere.io
kind: ServicePolicy
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: network
labels:
version: v1
app: v2rayreporter-svc
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
name: v2rayreporter-svc-v1
annotations:
servicemesh.kubesphere.io/enabled: 'true'
spec:
replicas: 1
selector:
matchLabels:
version: v1
app: v2rayreporter-svc
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
template:
metadata:
labels:
version: v1
app: v2rayreporter-svc
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
annotations:
kubesphere.io/imagepullsecrets: '{"v2rayreporter":"harbor"}'
sidecar.istio.io/inject: 'true'
kubectl.kubernetes.io/restartedAt: "{{ .RunCreatedAt }}" #由此来触发滚动更新
spec:
containers:
- name: v2rayreporter
imagePullPolicy: Always
image: '$HARBOR_URL/library/v2rayreporter:latest'
ports:
- name: http-0
protocol: TCP
containerPort: 8001
volumeMounts:
- name: host-time
mountPath: /etc/localtime
readOnly: true
serviceAccountName: default
terminationGracePeriodSeconds: 30
initContainers: []
volumes:
- hostPath:
path: /etc/localtime
type: ''
name: host-time
imagePullSecrets:
- name: harbor
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
---
apiVersion: v1
kind: Service
metadata:
namespace: network
labels:
version: v1
app: v2rayreporter-svc
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
annotations:
kubesphere.io/serviceType: statelessservice
servicemesh.kubesphere.io/enabled: 'true'
name: v2rayreporter-svc
spec:
sessionAffinity: None
selector:
app: v2rayreporter-svc
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
ports:
- name: http-0
protocol: TCP
port: 80
targetPort: 8001
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: network
labels:
app.kubernetes.io/version: v1
app.kubernetes.io/name: v2rayreporter
name: v2rayreporter-ingress-pybd68
annotations:
nginx.ingress.kubernetes.io/upstream-vhost: v2rayreporter-svc.network.svc.cluster.local
spec:
rules:
- host: v2ray.povison-pro.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: v2rayreporter-svc
port:
number: 80
tls: []
cicd工程配置如下
主要分为简单的build流程和deploy流程
build是利用dockerfile构建好应用运行时的镜像并推送到仓库
deploy是利用v2rayreport.yml在k8s集群中部署应用
variables: #编辑容器内环境变量
IMAGE_NAME: v2rayreporter #镜像名称
stages:
- build
- deploy
build: #没有指定image时用runner配置中指定的默认镜像
stage: build
script:
- docker build -f dockerfile -t harbor.povison-pro.com/library/$IMAGE_NAME . #构建镜像
- docker login $HARBOR_URL -u $HARBOR_USERNAME -p $HARBOR_PASSWORD #登录镜像仓库
- docker push $HARBOR_URL/library/$IMAGE_NAME #推送镜像
- docker rmi $HARBOR_URL/library/$IMAGE_NAME #删除镜像(镜像清理原则)
- docker image prune -a -f #清理无用镜像
deploy:
stage: deploy
image: $HARBOR_URL/library/kubectl:v1.23.10 #部署到K8S集群需要用到这个工具镜像 这个要看用的哪个方法做的和K8S互动
script:
- mkdir $HOME/.kube && cat $KUBE_CONFIG > $HOME/.kube/config #链接K8S集群用
- kubectl apply -f v2rayreporter.yml
效果展示
到这里这个简单思路的实践就完成啦!
文章写的比较粗糙,有问题欢迎交流学习!