ci&cd通过k8s完整部署
# 操作步骤
在开始之前,我们需要在 Kubernetes
集群内再加一台 Node
,起名为 node2
。具体流程请参考之前的章节。 Node2
的主要用途是用于部署 MySQL
使用。
# 1. 项目仓库
先来看下这次项目部署所需要的仓库:https://gitee.com/organizations/juejin-cicd/projects。
其中,k8s-demo-frontend
是前端项目,k8s-demo-backend
是后端项目。
# 2. 构建 & 部署前端应用
第一步我们先部署前端应用,先将前端跑起来。
我们前往 Jenkins
,新建一个任务,起名为 demo-frontend
。接着配置任务的Git代码源,让 Jenkins 可以拉取代码。因为我们目前是公开项目,所以还不需要配置私有仓库认证。
按照之前的方式,勾选 构建环境
=> Provide Node & npm bin/ folder to PATH
选项,给你执行的任务增加 Nodejs
运行环境
继续添加构建脚本,让 Jenkins
构建镜像。找到 构建
=> 添加构建步骤
=> Excute Shell
,填写以下脚本:
脚本首先使用 npm run build
对代码进行编译打包,随后使用 docker build
命令构建镜像。最后推送镜像到镜像库内。
#!/bin/sh -l
time=$(date "+%Y%m%d%H%M%S")
npm install --registry=https://registry.npm.taobao.org
npm run build
docker build -t 172.16.81.7:8082/frontend-app:$time .
docker login -u $DOCKER_LOGIN_USERNAME -p $DOCKER_LOGIN_PASSWORD 172.16.81.7:8082
docker push 172.16.81.7:8082/frontend-app:$time
2
3
4
5
6
7
8
因为推送镜像需要 docker login
,我们还需要在 Jenkins
端配置下 docker
登录信息。配置文件方式如下图,和之前的章节无异。
保存后执行,即可生成前端镜像。
镜像生成后,我们还需要去k8s集群内部署下这个镜像。
前往集群节点,新建一个文件。叫做 demo-frontend.yaml
,输入以下内容。镜像地址换成刚才 Jenkins 构建后的镜像地址。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-frontend
spec:
selector:
matchLabels:
app: demo-frontend
replicas: 1
template:
metadata:
labels:
app: demo-frontend
spec:
imagePullSecrets:
- name: private-registry
containers:
- name: frontend-app
imagePullPolicy: Always
image: 172.16.81.7:8082/frontend-app:20210117162137
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo-frontend-service
spec:
selector:
app: demo-frontend
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
保存后退出,使用 kubectl apply
命令部署前端服务。部署完毕后,使用 kubectl get svc
命令来获取下服务的端口。
可以看到,此时前端已经部署成功了。使用浏览器打开即可看到页面。
# 3. 部署 & 初始化MySQL
我们在开头时,添加了一台全新的 Node
节点,这台节点机器用于部署MySQL服务。我们可以给节点加污点,让除了特定的服务,其他服务都不可以部署上去。
这里添加一条污点, key
等于 MySQL
, value
等于 true
。
kubectl taint nodes node2 mysql=true:NoSchedule
添加完毕后,我们就可以放心部署 MySQL
了。不过在开始部署之前,我们还需要去 Node2
节点给 MySQL
的数据创建一个文件夹。我们会将本地的文件夹挂载进 MySQL
容器内,以方便 MySQL
数据可以持久化。
mkdir /var/lib/mysql && mkdir /var/lib/mysql/data
还需要给 MySQL
容器添加挂在访问密码。这里我们将密码存入 secret
内保存。
kubectl create secret generic demo-mysql-auth \
--from-literal=password=367734
2
此时我们就可以开始部署MySQL了。新建一个YAML文件,输入以下内容。这里给 MySQL
容器添加了污点对应的容忍度,密码也挂载了进去,设置了默认端口 3306
。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-mysql
spec:
replicas: 1
selector:
matchLabels:
app: demo-mysql
template:
metadata:
labels:
app: demo-mysql
spec:
tolerations:
- key: "mysql"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: demo-mysql
image: mysql:5.6
imagePullPolicy: IfNotPresent
args:
- "--ignore-db-dir=lost+found"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: "/var/lib/mysql"
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: demo-mysql-auth
key: password
volumes:
- name: mysql-data
hostPath:
path: /var/lib/mysql
type: Directory
---
apiVersion: v1
kind: Service
metadata:
name: demo-mysql-service
spec:
type: NodePort
ports:
- port: 3306
protocol: TCP
targetPort: 3306
selector:
app: demo-mysql
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
部署成功后,我们可以使用 Navicat
等工具访问数据库了。数据库的 host
是 service
的地址,用户是 root
,密码则是我们挂载进去的密码。可以访问数据库后,使用我们的初始化 sql
文件,初始化以下数据库和表结构。这里的 sql
创建了一个名称为 demo-backend
的数据库,数据库内创建了 user
表。并加入了4个数据库字段。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
CREATE DATABASE IF NOT EXISTS `demo-backend` DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
USE `demo-backend`;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) NOT NULL COMMENT '姓名',
`age` int(11) NOT NULL COMMENT '年龄',
`sex` varchar(255) NOT NULL COMMENT '性别;1男 2女',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sql
执行成功后,代表数据库初始化成功。
# 4. 构建 & 部署后端应用
最后一步就是部署后端服务了。首先第一步,也是在 Jenkins
端新建项目,具体流程和前端应用一样。构建脚本需要进行修改:
因为这里没有静态资源需要构建,所以直接将源码目录拷贝进容器即可:
#bin/bash
time=$(date "+%Y%m%d%H%M%S")
npm install --registry=https://registry.npm.taobao.org
docker build -t 172.16.81.7:8082/backend-app:$time .
docker push 172.16.81.7:8082/backend-app:$time
2
3
4
5
执行任务,镜像 push
完成代表成功。
镜像准备好后,我们需要在k8s端部署下服务。在部署之前,我们先将数据库相关信息存入 configmap
,然后挂载进后端服务:
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
host: 'demo-mysql-service'
port: 3306
username: 'root'
database: 'demo-backend'
2
3
4
5
6
7
8
9
存好后就可以部署后端服务了,以下是配置文件。内容拉取了一个后端服务镜像,并将数据库账号和端口服务地址通过 configmap
传入了进去。
这里的镜像地址要更换 Jenkins 构建出来的镜像地址。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-backend
spec:
selector:
matchLabels:
app: demo-backend
replicas: 1
template:
metadata:
labels:
app: demo-backend
spec:
imagePullSecrets:
- name: private-registry
containers:
- name: backend-app
imagePullPolicy: Always
image: [镜像地址]
ports:
- containerPort: 7001
env:
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: mysql-config
key: host
- name: MYSQL_PORT
valueFrom:
configMapKeyRef:
name: mysql-config
key: port
- name: MYSQL_USER
valueFrom:
configMapKeyRef:
name: mysql-config
key: username
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: mysql-config
key: database
---
apiVersion: v1
kind: Service
metadata:
name: demo-backend-service
spec:
selector:
app: demo-backend
ports:
- protocol: TCP
port: 7001
targetPort: 7001
type: NodePort
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
保存后,使用 kubectl apply
即可让服务生效。
接着访问下前端界面,功能正常代表部署成功。
# 5. 集成 Jenkins
在前面的服务部署成功后,我们还需要使用 Jenkins
直接一键执行构建和部署。
我们在前面部署镜像时,都是在集群内直接操作。可是一般情况下,Jenkins 和 k8s 并不在一台机器上。那我们如何远程操作集群呢?
这里可以使用 kubectl 的 --kubeconfig
命令,传入集群的配置文件即可远程操作。只要保证Jenkins和k8s集群网络互通即可。配置文件的路径也很好找,位于集群机器的 ~/.kube/config
文件。
这样,我们在 Jenkins
端添加一个全局配置文件,方便任务使用。
找到 Manage Jenkins
=> Managed files
。选择右边的 Add a new Config
:
选择普通配置,给配置文件起好名称,将 kubernetes
配置文件内容拷贝进 Content
内即可:
随后,我们还需要在 Jenkins
机器上安装 kubectl
,只安装 kubectl
即可。
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubectl
2
3
4
5
6
7
8
9
10
11
回到任务编辑界面,找到 绑定
一栏,选择我们刚刚配置的配置文件。填写 target
一栏,让配置文件输出为文件。
找到命令界面。以前端任务为例,我们在 docker push
的命令后,加一条 kubectl
执行命令。在这里,直接使用 kubectl --kubeconfig
制定配置文件,即可远程操作
kubectl --kubeconfig=k8s-config.yaml set image deployment/demo-frontend demo-frontend=172.16.81.7:8082/frontend-app:$time
我们可以使用
kubectl set image
命令快速设置镜像地址版本格式为:kubectl set image deployment/[deployment名称] [容器名称]=[镜像版本]
保存后执行,提示 deployment.apps/[deployment名称] image updated
代表更新完毕。