GitOps实战

作者: robintics | 来源:发表于2020-12-21 15:33 被阅读0次

    简介

    GitOps是一种开发运维实践,其核心思想是将整个应用环境以文件形式保存在Git仓库中,并通过Git的相关工具对应用进行更新、回滚等操作。

    OneDev(https://github.com/theonedev/onedev)是一个开源的自带持续集成和部署功能的Git仓库管理软件,和GitLab类似,但更简单,机器要求低,性能好。

    这篇文章介绍使用OneDev对基于Kubernetes的应用实现GitOps。

    创建Kubernetes集群

    首先我们需要一个Kubernetes集群,您可以使用现成的,也可以新建一个。这里我们使用阿里云的ACK。登录到阿里云ACK控制台,并创建费用较低的ACK托管版集群。相关选项:

    1. 集群规格:选择较便宜的标准版即可
    2. 配置SNAT:必须勾选
    3. 公网访问:必须勾选
    4. Worker配置:两个节点即可。每个节点内存至少为4G。使用默认操作系统。登录方式为简单起见选择密码并设置
    5. 组件配置:除了勾选“安装Ingress组件“,其余组件均不需要

    集群创建成功后,将连接信息里的公网访问凭据复制到本地文件$HOME/.kube/config并运行如下命令确认能够连接到集群(如果本地还没有kubectl,可以参照此文先进行安装):

    $ kubectl cluster-info 
    

    由于国内访问官方Docker Registry太慢,我们还需要使用阿里的容器镜像服务。访问容器镜像服务,并在合适的命名空间内创建镜像仓库gitops-demo。为方便配置,仓库类型选择公开。代码源选择本地仓库。镜像仓库创建后,详情页里查看所在阿里云区域的docker registry(比如http://registry.cn-shanghai.aliyuncs.com),并确保在命令行里能用合适的用户名和密码登录该registry。

    部署OneDev

    为方便对集群里的应用进行控制,我们将OneDev部署到Kubernetes集群里。

    1.运行下面的命令设置默认的storageclass。因为OneDev的部署需要申请储存卷(详见下步):

    kubectl patch storageclass alicloud-disk-ssd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
    

    2.下载OneDev的K8s资源定义, 解压并运行如下命令(OneDev部署会创建两个存储卷:100G的用来存储Git仓库,20G的用来存储MySQL数据库,存储卷的大小可以在文件k8s-resources/production/disk-settings.yaml中进行修改):

    $ cd k8s-resources/production
    $ kubectl apply -k .
    

    3.部署完成后,运行下面的命令获取OneDev服务的external ip(如果external ip还未分配,等待片刻后再重试):

    $ kubectl get services -n onedev
    

    4.在浏览器内访问地址http://<OneDev external ip>并按提示配置OneDev(除了创建管理员账号外,其余均用默认设置)。如果网页无法访问,等待片刻再重试。

    创建示例应用

    接着我们配置一个示例应用:

    1.在OneDev Projects页面中创建一个名为gitops-demo的项目
    2.在命令行下运行如下命令创建一个react项目并push到OneDev(该步骤需要node.js运行环境,具体参照react文档:

    $ npx create-react-app gitops-demo 
    $ cd gitops-demo
    $ git remote add origin http://<OneDev external ip>/gitops-demo
    $ git push --set-upstream origin master 
    (使用之前创建的OneDev管理员作为push的账号)
    

    3.刷新OneDev示例项目的Files页面,并按下图所示点击Add build spec链接:

    2020-12-16_08-54-11.png

    4.在build spec编辑页面中,点击Edit Source(注意之前不要增加任何Job),然后将build spec的源代码替换为如下内容:

    version: 1
    jobs:
    - name: CI
      image: node:15.4-alpine
      commands:
      - set -e
      - ''
      - apk add --update jq
      - buildVersion=`jq -r '.version' package.json`
      - echo "##onedev[SetBuildVersion '$buildVersion']"
      - ''
      - yarn install
      - ''
      - export CI=true
      - yarn test
      triggers:
      - !BranchUpdateTrigger {}
      retrieveSource: true
      cloneCredential: !DefaultCredential {}
      cpuRequirement: 250m
      memoryRequirement: 128m
      retryCondition: never
      maxRetries: 3
      retryDelay: 30
      caches:
      - key: npm-cache
        path: /root/.npm
      timeout: 3600
    

    5.保存并提交改动。如下图所示,OneDev将自动对示例项目进行构建:

    2020-12-16_09-15-37.png

    实施GitOps

    我们已经能够构建示例应用,下面着手将它部署到Kubernetes中:

    1.要部署到Kubernetes中,我们首先需要构建示例应用的docker image。在示例项目的根目录创建文件Dockerfile,内容如下:

    FROM nginx:1.19.5 
    COPY build /usr/share/nginx/html 
    EXPOSE 80
    

    文件提交后OneDev会自动构建,这时不必理会。

    2.继续在根目录创建用来描述部署的Kubernetes资源文件k8s.yaml。内容如下。注意需要将<docker repository>替换为容器仓库的地址,比如registry.cn-shanghai.aliyuncs.com/test/gitops-demo,具体地址在前述阿里云容器镜像仓库的详情页里有显示。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gitops-demo
      labels:
        tier: gitops-demo
    spec:
      selector:
        matchLabels:
          tier: gitops-demo
      strategy:
        type: Recreate
      template:
        metadata:
          name: gitops-demo
          labels:
            tier: gitops-demo
        spec:
          containers:
          - name: gitops-demo
            image: <docker repository>:imageTag
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: gitops-demo
      labels:
        tier: gitops-demo
    spec:
      type: LoadBalancer
      ports:
      - name: http
        port: 80
        targetPort: 80
        protocol: TCP
      selector:
        tier: gitops-demo
    

    3.为了能够将示例应用的image发布到阿里云的docker registry,OneDev需要知道docker registry的密码。在示例项目里增加一个job secret,给它一个名字,比如docker-registry-password,并将值设置为docker registry的访问密码。如下图所示:

    2020-12-16_10-31-39.png

    4.因为需要在构建时将示例应用部署到Kubernetes,OneDev需要额外的集群权限。在本机创建文件gitops-demo-role.yaml并包含如下内容:

    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: gitops-demo
    rules:
    - apiGroups: [""]
      resources: ["services"]
      verbs: ["get", "create"]
    - apiGroups: ["apps"]
      resources: ["deployments"]
      verbs: ["get", "patch", "create"]
    

    然后在命令行下运行如下命令:

    $ kubectl apply -f gitops-demo-role.yaml
    

    接着在OneDev的管理页面里删除原有的auto-discover job executor,并新建一个Kubernetes Executor。设置名字,并将字段Cluster Role设置为gitops-demo。其他内容保持不变,然后保存。具体如下所示:

    2020-12-16_11-05-06.png

    5.最后在OneDev里回到示例项目页面,在文件根目录中点击.onedev-buildspec.yml查看详情,然后进行编辑。将image字段设置为docker:19.03.5,并将commands字段设置为如下内容。注意需要将<docker-registry-login>替换为前述阿里云docker registry的登录名,将<docker repository>替换为容器仓库的地址(例如registry.cn-shanghai.aliyuncs.com/test/gitops-demo),以及将<docker registry>替换为所在阿里云区域的docker registry(例如registry.cn-shanghai.aliyuncs.com)。这些属性均可在前述容器镜像仓库的详情内查看。

    set -e
    apk add --update npm jq curl
    buildVersion=`jq -r '.version' package.json`
    echo "##onedev[SetBuildVersion '$buildVersion']"
    
    npm install -g yarn
    yarn install
    export CI=true
    yarn test
    yarn build
    
    docker build -t <docker repository>:@commit_hash@ .
    
    docker login -u <docker-registry-login> -p @secrets:docker-registry-password@ <docker registry>
    
    docker push <docker repository>:@commit_hash@
    
    curl -o /usr/local/bin/kubectl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
    
    chmod +x /usr/local/bin/kubectl
    sed -i "s/imageTag/@commit_hash@/g" k8s.yaml
    kubectl apply -f k8s.yaml -n default
    

    6.保存并提交改动。OneDev就会开始构建并部署示例应用。构建成功后,运行下面的命令查看示例应用的external ip:

    kubectl get service gitops-demo
    

    然后就可以用浏览器打开地址http://<gitops-demo-external-ip-address>来访问部署好的示例应用了。

    恭喜!现在您已经成功配置了一个简单的GitOps流程:当有新的commit提交到主分支时(无论是通过push还是通过pull request合并),OneDev的CI任务会自动触发来构建、测试并重新部署示例项目。当需要回滚到前一个部署时,只需要运行git revert master命令,并将改动提交到主分支即可。

    管理多个部署环境

    在上面的部署中,我们将示例应用直接部署到了集群的默认名字空间中。在实际项目中,我们可能需要创建多个名字空间来对应多个部署环境。下面我们创建productiontest名字空间,分别对应我们的生产和测试环境:

    $ kubectl create namespace test
    $ kubectl create namespace production
    

    编辑build spec将Commands字段的最后一行替换为如下内容:

    if [ "@branch@" = "master" ]; then 
        kubectl apply -f k8s.yaml -n production
    else
        kubectl apply -f k8s.yaml -n @branch@ 
    fi;
    

    这告诉OneDev将所有提交到主分支的改动部署到生产环境,并将其他分支的改动部署到和分支名相同的命名空间中。

    改动提交到主分支后,示例应用将会被部署到生产环境中。接着我们在OneDev里创建test分支,可以看到该分支创建后,示例应用也被部署到测试环境中。

    2020-12-19_11-06-46.png

    可以在命令行下运行如下命令查看特定部署环境的external ip。注意需要将<namespace>替换为对应环境的集群名字空间:

    kubectl get service -n <namespace>
    

    这样在OneDev的commits页面里,我们就可以一目了然的查看和控制各个环境的部署情况了。

    2020-12-16_15-53-35.png

    感谢阅读!

    相关文章

      网友评论

        本文标题:GitOps实战

        本文链接:https://www.haomeiwen.com/subject/igirnktx.html