在之前的几篇中,我分别介绍了基础环境的配置,skywaling+nacos的配置,nexus3的配置,围绕sonarqube的配置和构建镜像的配置。
这一篇中,基于构建的镜像进行清单编排。我们需要一种工具来管理配置清单。
阅读此篇,你将了解如下列表中简单的实现方式:
- jenkins和gitlab触发(已实现)
- jenkins凭据使用(已实现)
- juit配置(已实现)
- sonarqube简单扫描(已实现)
- sonarqube覆盖率(已实现)
- 打包基于java的skywalking agent(上一章已实现)
- sonarqube与gitlab关联 (上一章已实现)
- 配置docker中构建docker (上一章已实现)
- mvn打包(上一章已实现)
- sonarqube简单分支扫描(上一章已实现)
- 基于gitlab来管理kustomize的k8s配置清单(本章实现)
- kubectl部署(本章实现)
- kubeclt deployment的状态跟踪(本章实现)
- 钉钉消息的构建状态推送
没错,我移情别恋了,在Helm和kustomize中,我选择后者。最大的原因是因为kustomize简单,易于维护。无论从那个角度,我都找不到不用kustomize的理由。这倒不是因为kustomize是多么优秀,仅仅是因为kustomize的方式让一切变得都简单。
- Helm和kustomize
helm几乎可以完成所有的操作,但是helm的问题是学习有难度,对于小白不友好,配置一旦过多调试将会更复杂。也是因为这种限制,那么使用helm的范围就被缩小了,不管在什么条件下,它都不在是优选。
kustomize更直白,无论是开发,还是运维新手,都可以快速上手进行修改添加等基础配置。
kustomize
kustomize用法在官网的github上已经有所说明了,并且这里温馨的提供了中文示例。讨论如何学习kustomize不在本章的重点
遵循kustmoize的版本,在https://github.com/kubernetes-sigs/kustomize/releases找到一个版本,通过http://toolwa.com/github/加速下载
Kubectl 版本 | 自定义版本 |
---|---|
< v1.14 | 不适用 |
v1.14-v1.20 | v2.0.3 |
v1.21 | v4.0.5 |
v1.22 | v4.2.0 |
[root@k8s-01 linuxea]# kustomize version
{Version:kustomize/v4.5.5 GitCommit:daa3e5e2c2d3a4b8c94021a7384bfb06734bcd26 BuildDate:2022-05-20T20:25:40Z GoOs:linux GoArch:amd64}
创建必要的目录结构
阅读示例中的示例:devops和开发配合管理配置数据有助于理解kustomize配置方法
场景:在生产环境中有一个基于 Java 由多个内部团队对于业务拆分了不通的组并且有不同的项目的应用程序。
这些服务在不同的环境中运行:development、 testing、 staging 和 production,有些配置需要频繁修改的。如果只是维护一个大的配置文件是非常麻烦且困难的 ,而这些配置文件也是需要专业运维人员或者devops工程师来进行操作的,这里面包含了一些片面且偏向运维的工作是开发人员不必知道的。例如:
- 生产环境的敏感数据
- 关键的登录凭据等
这些在kustomize中被分成了不通的类
因此,kustomize提供了混合管理办法
基于相同的 base 创建 n 个 overlays 来创建 n 个集群环境的方法
我们将使用 n==2,例如,只使用 development 和 production ,这里也可以使用相同的方法来增加更多的环境。
运行 kustomize build
基于 overlay 的 target 来创建集群环境。
为了让这一切开始运行,准备如下
- 创建kustomize目录结构
- 创建并配置kustomize配置文件
- 最好创建gitlab项目,将配置存放在gitlab
开始
此前我写了一篇kustomize变量传入有过一些介绍,我们在简单补充一下。
kustomize在1.14版本中已经是Kubectl内置的命令,并且支持kubernetes的原生可复用声明式配置的插件。它引入了一种无需模板的方式来自定义应用程序配置,从而简化了现成应用程序的使用。
Kustomize 遍历 Kubernetes 清单以添加、删除或更新配置选项。它既可以作为独立的二进制文件使用,也可以作为kubectl
来使用
更多的背景可参考它的白皮书,这些在github的Declarative application management in Kubernetes存放。
因为总的来说,这篇不是让你如何去理解背后的故事,而是一个最简单的示例
- 常见操作
在项目中为所有 Kubernetes 对象设置贯穿性字段是一种常见操作。 贯穿性字段的一些使用场景如下:
- 为所有资源设置相同的名字空间
- 为所有对象添加相同的前缀或后缀
- 为对象添加相同的标签集合
- 为对象添加相同的注解集合
- 为对象添加相同的资源限制以及以及副本数
这些通过在overlays目录下不同的配置来区分不通的环境所用的清单信息
安装
遵循github版本对应规则
Kubectl version | Kustomize version |
---|---|
< v1.14 | n/a |
v1.14-v1.20 | v2.0.3 |
v1.21 | v4.0.5 |
v1.22 | v4.2.0 |
我的集群是1.23.1,因此我下载4.5.4
PS E:\ops\k8s-1.23.1-latest\gitops> kustomize version
{Version:kustomize/v4.5.4 GitCommit:cf3a452ddd6f83945d39d582243b8592ec627ae3 BuildDate:2022-03-28T23:12:45Z GoOs:windows GoArch:amd64}
java-demo
我这里已经配置了一个已经配置好的环境,我将会在这里简单介绍使用方法和配置,我不会详细说明deployment控制器的配置清单,也不会说明和kustomize基本使用无关的配置信息,我只会尽可能的在这个简单的示例中说明整个kustomize的在本示例中的用法。
简述:
kustomize需要base和Overlays目录,base可以是多个,overlays也可以是多个,overlays下的文件最终会覆盖到base的配置之上,只要配置是合理的,base的配置应该将有共性的配置最终通过overlays来进行配置,以此应对多个环境的配置。
java-demo是一个无状态的java应用,使用的是Deployment控制器进行配置,并且创建一个service,于此同时传入skywalking的环境变量信息。
1. 目录结构
目录结构如下:
# tree ./
./
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
├── overlays
│ ├── dev
│ │ ├── env.file
│ │ ├── kustomization.yaml
│ │ └── resources.yaml
│ └── prod
│ ├── kustomization.yaml
│ ├── replicas.yaml
│ └── resources.yaml
└── README.md
4 directories, 11 files
其中两目录如下:
./
├── base
├── overlays
└── README.md
- base: 目录作为基础配置目录,真实的配置文件在这个文件下
- overlays: 目录作为场景目录,描述与 base 应用配置的差异部分来实现资源复用
而在overlays目录下,又有两个目录,分别是dev和prod,分别对应俩个环境的配置,这里可以任意起名来区分,因为在这两个目录下面存放的是各自不通的配置
./
├── base
├── overlays
│ ├── dev
│ └── prod
└── README.md
1.1 imagePullSecrets
除此之外,我们需要一个拉取镜像的信息
使用cat ~/.docker/config.json |base64
获取到base64字符串编码,而后复制到.dockerconfigjson: >-
下即可
apiVersion: v1
data:
.dockerconfigjson: >-
ewoJImkh0dHBIZWFkZXJzIjogewoJCSJVc2VyLUFnZW50IjogIkRvY2tlci1DbGllbnQvMTkuMDMuMTIgKGxpbnV4KSIKCX0KfQ==
kind: Secret
metadata:
name: 156pull
namespace: java-demo
type: kubernetes.io/dockerconfigjson
2. base目录
base目录下分别有三个文件,分别如下
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
在deployment.yaml中定义必要的属性
- 不定义场景的指标,如标签,名称空间,副本数量和资源限制
- 定义名称,镜像地址,环境变量名
这些不定义的属性通过即将配置的overlays中的配置进行贯穿覆盖到这个基础配置之上
必须定义的属性表明了贯穿的属性和基础的配置是一份
这里的环境变量用的是configmap的方式,值是通过后面传递过来的。
如下
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-demo
spec:
selector:
matchLabels:
template:
metadata:
labels:
spec:
containers:
- image: harbor.marksugar.com/java/linuxea-2022
imagePullPolicy: IfNotPresent
name: java-demo
ports:
- containerPort: 8080
env:
- name: SW_AGENT_NAME
valueFrom:
configMapKeyRef:
name: envinpod
key: SW_AGENT_NAME
- name: SW_AGENT_TRACE_IGNORE_PATH
valueFrom:
configMapKeyRef:
name: envinpod
key: SW_AGENT_TRACE_IGNORE_PATH
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
valueFrom:
configMapKeyRef:
name: envinpod
key: SW_AGENT_COLLECTOR_BACKEND_SERVICES
imagePullSecrets:
- name: 156pull
restartPolicy: Always
service.yaml
apiVersion: v1
kind: Service
metadata:
name: java-demo
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 31180
kustomization.yaml
kustomization.yaml引入这两个配置文件
resources:
- deployment.yaml
- service.yaml
执行 kustomize build /base
,得到的结果如下,这就是当前的原始清单
apiVersion: v1
kind: Service
metadata:
name: java-demo
spec:
ports:
- nodePort: 31180
port: 8080
targetPort: 8080
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-demo
spec:
selector:
matchLabels: null
template:
metadata:
labels: null
spec:
containers:
- env:
- name: SW_AGENT_NAME
valueFrom:
configMapKeyRef:
key: SW_AGENT_NAME
name: envinpod
- name: SW_AGENT_TRACE_IGNORE_PATH
valueFrom:
configMapKeyRef:
key: SW_AGENT_TRACE_IGNORE_PATH
name: envinpod
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
valueFrom:
configMapKeyRef:
key: SW_AGENT_COLLECTOR_BACKEND_SERVICES
name: envinpod
image: harbor.marksugar.com/java/linuxea-2022:202207091551
imagePullPolicy: IfNotPresent
name: java-demo
ports:
- containerPort: 8080
imagePullSecrets:
- name: 156pull
restartPolicy: Always
3. overlays目录
首先,在overlays目录下是有dev和prod目录的,我们先看在dev目录下的kustomization.yaml
kustomization.yaml中的内容,包含一组资源和相关的自定义信息,如下
更多用法参考官方文档或者github社区
kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesStrategicMerge:
- resources.yaml # 当如当前的文件
namespace: java-demo # 名称空间
images:
- name: harbor.marksugar.com/java/linuxea-2022 # 镜像url必须保持和base中一致
newTag: '202207072119' # 镜像tag
bases:
- ../../base # 引入bases基础文件
# configmap变量
configMapGenerator:
- name: envinpod # 环境变量名称
env: env.file # 环境变量位置
# 副本数
replicas:
- name: java-demo # 名称必须保持一致
count: 5
# namePrefix: dev- # pod前缀
# nameSuffix: "-001" # pod后缀
commonLabels:
app: java-demo # 标签
# logging: isOk
# commonAnnotations:
# oncallPager: 897-001
删掉那些注释后如下
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesStrategicMerge:
- resources.yaml
namespace: java-demo
images:
- name: harbor.marksugar.com/java/linuxea-2022
newTag: '202207071059'
bases:
- ../../base
configMapGenerator:
- name: envinpod
env: env.file
replicas:
- name: java-demo
count: 5
commonLabels:
app: java-demo
resources.yaml
resources.yaml 中的name必须保持一致
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-demo
spec:
template:
spec:
containers:
- name: java-demo
resources:
limits:
cpu: "1"
memory: 2048Mi
requests:
cpu: "1"
memory: 2048Mi
env.file
env.file定义的变量是对应在base中的,这些是skwayling中的必要信息,参考kubernetes中skywalking9.0部署使用,env的用法参考kustomize变量引入
SW_AGENT_NAME=test::java-demo
SW_AGENT_TRACE_IGNORE_PATH=GET:/health,GET:/aggreg/health,/eureka/**,xxl-job/**
SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap.skywalking:11800
查看 kustomize build overlays/dev/
后的配置清单。如下所示:
apiVersion: v1
data:
SW_AGENT_COLLECTOR_BACKEND_SERVICES: skywalking-oap.skywalking:11800
SW_AGENT_NAME: test::java-demo
SW_AGENT_TRACE_IGNORE_PATH: GET:/health,GET:/aggreg/health,/eureka/**,xxl-job/**
kind: ConfigMap
metadata:
labels:
app: java-demo
name: envinpod-74t9b8htb6
namespace: java-demo
---
apiVersion: v1
kind: Service
metadata:
labels:
app: java-demo
name: java-demo
namespace: java-demo
spec:
ports:
- nodePort: 31180
port: 8080
targetPort: 8080
selector:
app: java-demo
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: java-demo
name: java-demo
namespace: java-demo
spec:
replicas: 5
selector:
matchLabels:
app: java-demo
template:
metadata:
labels:
app: java-demo
spec:
containers:
- env:
- name: SW_AGENT_NAME
valueFrom:
configMapKeyRef:
key: SW_AGENT_NAME
name: envinpod-74t9b8htb6
- name: SW_AGENT_TRACE_IGNORE_PATH
valueFrom:
configMapKeyRef:
key: SW_AGENT_TRACE_IGNORE_PATH
name: envinpod-74t9b8htb6
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
valueFrom:
configMapKeyRef:
key: SW_AGENT_COLLECTOR_BACKEND_SERVICES
name: envinpod-74t9b8htb6
image: harbor.marksugar.com/java/linuxea-2022:202207071059
imagePullPolicy: IfNotPresent
name: java-demo
ports:
- containerPort: 8080
resources:
limits:
cpu: "1"
memory: 2048Mi
requests:
cpu: "1"
memory: 2048Mi
imagePullSecrets:
- name: 156pull
restartPolicy: Always
base作为基础配置,Overlays作为覆盖来区分。base是包含kustomization.yaml
文件的一个目录,其中包含一组资源及其相关的定制。 base可以是本地目录或者来自远程仓库的目录,只要其中存在kustomization.yaml
文件即可。 Overlays 也是一个目录,其中包含将其他 kustomization 目录当做bases
来引用的kustomization.yaml
文件。 base不了解Overlays的存在,且可被多个Overlays所使用。 Overlays则可以有多个base,且可针对所有base中的资源执行操作,还可以在其上执行定制。
通过sed替换Overlays下的文件内容或者kustomize edit set
,如:在Overlays下执行kustomize edit set image harbor.marksugar.com/java/linuxea-2022:202207091551:202207071059:1.14.b
替换镜像文件。一切符合预期后,使用kustomize.exe build .\overlays\dev\ | kubectl apply -f -
使其生效。
4. 部署到k8s
命令部署两种方式
- kustomize
kustomize build overlays/dev/ | kubectl apply -f -
- kubectl
kubectl apply -k overlays/dev/
使用kubectl apply -k生效,如下
PS E:\ops\k8s-1.23.1-latest\gitops> kubectl.exe apply -k .\overlays\dev\
configmap/envinpod-74t9b8htb6 unchanged
service/java-demo created
deployment.apps/java-demo created
如果使用的域名是私有的,需要在本地hosts填写本地解析
172.16.100.54 harbor.marksugar.com
并且需要修改/etc/docker/daemon.json
{ "data-root": "/var/lib/docker", "exec-opts": ["native.cgroupdriver=systemd"], "insecure-registries": ["harbor.marksugar.com"], "max-concurrent-downloads": 10, "live-restore": true, "log-driver": "json-file", "log-level": "warn", "log-opts": { "max-size": "50m", "max-file": "1" }, "storage-driver": "overlay2" }
查看部署情况
PS E:\ops\k8s-1.23.1-latest\gitops\kustomize-k8s-yaml> kubectl.exe -n java-demo get all
NAME READY STATUS RESTARTS AGE
pod/java-demo-6474cb8fc8-6xs8t 1/1 Running 0 41s
pod/java-demo-6474cb8fc8-9z9sd 1/1 Running 0 41s
pod/java-demo-6474cb8fc8-jfqv6 1/1 Running 0 41s
pod/java-demo-6474cb8fc8-p5ztd 1/1 Running 0 41s
pod/java-demo-6474cb8fc8-sqt7b 1/1 Running 0 41s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/java-demo NodePort 10.111.26.148 <none> 8080:31180/TCP 41s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/java-demo 5/5 5 5 41s
NAME DESIRED CURRENT READY AGE
replicaset.apps/java-demo-6474cb8fc8 5 5 5 42s
与此同时,skywalking也加入成功
创建git项目
在gitlab创建了一个组,在组织里面创建了一个项目,名称以项目命名,在项目内每个应用对应一个分支
如: devops组内内新建一个k8s-yaml的项目,项目内创建一个java-demo分支,java-demo分支中存放java-demo的配置文件
现在创建key,将密钥加入到项目中
ssh-keygen -t ed25519
将文件推送到git上
$ git clone git@172.16.100.47:devops/k8s-yaml.git
Cloning into 'k8s-yaml'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
$ cd k8s-yaml/
$ git checkout -b java-demo
Switched to a new branch 'java-demo
$ ls -ll
total 1024
-rw-r--r-- 1 Administrator 197121 12 Jul 7 21:09 README.MD
drwxr-xr-x 1 Administrator 197121 0 Jun 28 20:15 base/
-rw-r--r-- 1 Administrator 197121 774 Jul 6 18:05 imagepullsecrt.yaml
drwxr-xr-x 1 Administrator 197121 0 Jun 28 20:15 overlays/
$ git add .
$ git commit -m "first commit"
[java-demo a9701f7] first commit
11 files changed, 185 insertions(+)
create mode 100644 base/deployment.yaml
create mode 100644 base/kustomization.yaml
create mode 100644 base/service.yaml
create mode 100644 imagepullsecrt.yaml
create mode 100644 overlays/dev/env.file
create mode 100644 overlays/dev/kustomization.yaml
create mode 100644 overlays/dev/resources.yaml
create mode 100644 overlays/prod/kustomization.yaml
create mode 100644 overlays/prod/replicas.yaml
create mode 100644 overlays/prod/resources.yaml
$ git push -u origin java-demo
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Delta compression using up to 8 threads
Compressing objects: 100% (15/15), done.
Writing objects: 100% (17/17), 2.90 KiB | 329.00 KiB/s, done.
Total 17 (delta 2), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for java-demo, visit:
remote: http://172.16.100.47/devops/k8s-yaml/-/merge_requests/new?merge_request%5Bsource_branch%5D=java-demo
remote:
To 172.16.100.47:devops/k8s-yaml.git
bb67227..a9701f7 java-demo -> java-demo
Branch 'java-demo' set up to track remote branch 'java-demo' from 'origin'.
添加到流水线
首先,kustomize是配置文件是存放在gitlab上,因此,这个git需要我们拉取下来,而后修改镜像名称,应用kustomize的配置后,在push到gitlab上
在这里的是kustomize是仅仅来管理yaml清单文件,在后面将使用argocd来做
我们在流水线里面配置一个环境变量,指向kustomize配置文件的git地址,并切除git拉取后的目录地址
尽可能的在gitlab和jenkins上的项目名称保持一直,才能做好流水线取值或者切出值的时候方便
def kustomize_Git="git@172.16.100.47:devops/k8s-yaml.git"
def JOB_NAMES=sh (script: """echo ${kustomize_Git.split("/")[-1]} | cut -d . -f 1""",returnStdout: true).trim()
但是kustomize是不能直接去访问集群的,因此还必须用kubectl,那就以为这需要config文件
我们使用命令指定配置文件位置
kubectl --kubeconfig /var/jenkins_home/.kube/config-1.23.1-dev
另外,如果你的jenkins的docker镜像没有kustomize,或者kubectl,需要挂载进去,因此我的就变成了
environment {
def tag_time = new Date().format("yyyyMMddHHmm")
def IPATH="harbor.marksugar.com/java/${JOB_NAME}:${tag_time}"
def kustomize_Git="git@172.16.100.47:devops/k8s-yaml.git"
def JOB_NAMES=sh (script: """echo ${kustomize_Git.split("/")[-1]} | cut -d . -f 1""",returnStdout: true).trim()
def Projects_Area="dev"
def apps_name="java-demo"
def projectGroup="java-demo"
def PACK_PATH="/usr/local/package"
}
并且在容器内生成一个密钥,而后加到gitlab中,以供git拉取和上传
bash-5.1# ssh-keygen -t rsa
而后在复制到/var/jenkins_home下,并且挂载到容器内
- /data/jenkins-latest/jenkins_home/.ssh:/root/.ssh
第一次拉取需要输入yes,我们规避它
echo '
Host *
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null' >>/root/.ssh/config
如果你使用的是宿主机运行的Jenkins,这一步可省略
因为资源不足的问题,我们手动修改副本数为1
流水线阶段,步骤大致如下:
1.判断本地是否有git的目录,如果有就删除
2.拉取git,并切换到分支
3.追加当前的镜像版本到一个buildhistory的文件中
4.cd到目录中修改镜像
5.修改完成后上传修改你被人
6.kustomize和kubectl应用配置清单
代码快如下:
stage('Deploy') {
steps {
sh '''
[ ! -d ${JOB_NAMES} ] || rm -rf ${JOB_NAMES} }
git clone ${kustomize_Git} && cd ${JOB_NAMES} && git checkout ${apps_name}
echo "push latest images: $IPATH"
echo "`date +%F-%T` imageTag: $IPATH buildId: ${BUILD_NUMBER} " >> ./buildhistory-$Projects_Area-${apps_name}.log
cd overlays/$Projects_Area
${PACK_PATH}/kustomize edit set image $IPATH
cd ../..
git add .
git config --global push.default matching
git config user.name zhengchao.tang
git config user.email usertzc@163.com
git commit -m "image tag $IPATH-> ${imageUrlPath}"
git push -u origin ${apps_name}
${PACK_PATH}/kustomize build overlays/$Projects_Area/ | ${PACK_PATH}/kubectl --kubeconfig /var/jenkins_home/.kube/config-1.23.1-dev apply -f -
'''
}
}
观测状态
配置清单被生效后,不一定符合预期,此时有很多种情况出现,特别是在使用原生的这些命令和脚本更新的时候
我们需要追踪更新后的状态,以便于我们随时做出正确的动作。
我此前写过一篇关于kubernetes检测pod部署状态简单实现,如果感兴趣可以查看
仍然使用此前的方式,如下
stage('status watch') {
steps {
sh '''
${PACK_PATH}/kubectl --kubeconfig /var/jenkins_home/.kube/config-1.23.1-dev -n ${projectGroup} rollout status deployment ${apps_name} --watch --timeout=10m
'''
}
}
构建一次
到服务器上查看
[root@linuxea-11 ~]# kubectl -n java-demo get pod
NAME READY STATUS RESTARTS AGE
java-demo-66b98564f6-xsc6z 1/1 Running 0 9m24s
评论