基于Gitlab-CI的容器应用DevOps工作流简单实践

前言

        基于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

效果展示 

到这里这个简单思路的实践就完成啦! 


文章写的比较粗糙,有问题欢迎交流学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值