程序员

GitOps实战

2020-12-21  本文已影响0人  robintics

简介

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

感谢阅读!

上一篇下一篇

猜你喜欢

热点阅读