本章节主要讲的是 springboot 项目发到 gitlab 仓库,触发 gitlab ci/cd 实现项目自动集成和部署,其中部署是以 k8s 方式部署
关于 gitlab-runner 安装和注册可以参考我的另一篇博客 Docker安装gitlab-runner 实现自动 CI/CD (持续集成/持续部署) 配置
关于 k8s 集群搭建可以参考我的另一篇博客 k8
s 集群之使用 kubeadm 在 Centos8 上部署 kubernetes 1.20
先创建 springboot 项目 push 到 gitlab 远程仓库,这里项目名称是 springboot-ci-cd-demo
新建一个 Controller 用于测试,如下
@RestController
@RequestMapping("/demo")
public class DemoController {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);
@GetMapping
public String demo() throws UnknownHostException {
String hostAddress = InetAddress.getLocalHost().getHostAddress();
LOGGER.info("{} : Hello, 2021 Happy New Year", hostAddress);
return hostAddress + " : Hello, 2021 Happy New Year";
}
}
gitlab-runner 安装好之后,注册 gitlab-runner 可使用如下命令,url 和 registration-token 在 gitlab 页面获取(注册如有不理解可以参考我的另一篇博客 Docker安装gitlab-runner 实现自动 CI/CD (持续集成/持续部署) 配置)
docker run -it --rm -v /srv/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner register \
--non-interactive \
--executor "docker" \
--docker-privileged \
--docker-image docker:latest \
--url "https://gitlab.com/" \
--registration-token "2xAmgi-WmzWh9evSH*****" \
--description "ci-runner" \
--tag-list "" \
--run-untagged="true" \
--locked="false" \
--access-level="not_protected";
部分变量需要在 gitlab 上配置,如下图
REG_USERNAME 和 REG_PASSWORD 是镜像仓库的用户名和密码
K8S_ADMIN_CONF :value 的值取之 k8s 集群环境 master 节点的 admin.conf 配置文件,拷贝文件里边的内容放到 value 里
K8S_DEMO_YAML:value 的值如下(值里边的变量需要在当前页面定义或者在,gitlab-ci.yml文件里边定义)
---
apiVersion: v1
kind: Service
metadata:
name: $DEPLOYMENT_NAME
namespace: demo
labels:
app: ci-cd-demo
spec:
type: NodePort
ports:
- name: ci-cd-demo
port: 8080
protocol: TCP
nodePort: 30080
selector:
app: ci-cd-demo
---
apiVersion: apps/v1
kind: Deployment #对象类型
metadata:
name: $DEPLOYMENT_NAME #名称
labels:
app: ci-cd-demo #标注
spec:
replicas: 1 #运行容器的副本数,修改这里可以快速修改分布式节点数量
selector:
matchLabels:
app: ci-cd-demo
template:
metadata:
labels:
app: ci-cd-demo
spec:
containers: #docker容器的配置
- name: $DEPLOYMENT_NAME
image: $PROJECT_IMAGE
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
env:
- name: JAVA_OPTS
value: -Xms256m -Xmx256m
imagePullSecrets:
- name: regsecret
编写 Dockerfile 文件,放在项目根目录
FROM openjdk:8-jdk
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]
编写 .gitlab-ci.yml 文件,放在项目根目录
# 因为我们Runner执行器设置为docker, 所以这里需要指定docker的版本
image: docker:stable
variables:
MAVEM_IMAGE: registry.cn-hangzhou.aliyuncs.com/sanchar/maven:1.0 # maven 打包使用的镜像
K8S_IMAGE: registry.cn-hangzhou.aliyuncs.com/sanchar/kubectl:v1.20.1 # k8s 部署使用的镜像
PROJECT_IMAGE_SERVER: registry.cn-hangzhou.aliyuncs.com # 阿里云镜像地址
PROJECT_IMAGE: registry.cn-hangzhou.aliyuncs.com/sanchar/springboot-ci-cd-demo:1.0 # 项目镜像链接
MAVEN_OPTS: -Dmaven.repo.local=/.m2 # 指定 maven 本地仓库路径,以便做缓存
PACKAGE_CACHE_REF_NAME: springboot-ci-cd-demo-cache
DEPLOYMENT_NAME: springboot-ci-cd-demo # 项目在 k8s 中部署的名称
K8S_NS: demo # k8s 命名空间
stages:
- package
- build
- deploy
# 打包
package:
stage: package
# 打包用到了maven, 所有需要拉取maven镜像, 这是我自己构建的阿里云maven私服的maven镜像
image: $MAVEM_IMAGE
script:
- echo "=============== mvn package ==============="
- mvn $MAVEN_OPTS clean package -Dmaven.test.skip=true
# 只作用在master分支
only:
- master
# 使用缓存速度更快,如果希望在gitlab-ci页面上可以下载jar包,可以使用下边的 artifacts 方式
cache:
key: $PACKAGE_CACHE_REF_NAME
paths:
- target/*.jar
# 这里可以将maven 打包好的文件传递给下一个 stage ,然后下一步的docker 就可以根据 这个 jar 包 和Dockerfile 构建镜像
# artifacts:
# # 指定下过期时间和路径
# # expire_in: 1 days
# paths:
# - target/*.jar
# 构建docker镜像并推送到镜像仓库
build:
stage: build
cache:
key: $PACKAGE_CACHE_REF_NAME
policy: pull
paths:
- target/*.jar
script:
- echo "=============== docker build image ==============="
- docker build -t $PROJECT_IMAGE .
- docker login --username $USERNAME --password $PASSWORD $PROJECT_IMAGE_SERVER
- docker push $PROJECT_IMAGE
only:
- master
# 使用 k8s 部署
deploy:
stage: deploy
image: $K8S_IMAGE
# 构建 k8s 可执行环境
before_script:
- mkdir -p /etc/kubernetes
- mv $K8S_ADMIN_CONF /etc/kubernetes/admin.conf
- echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
- source ~/.bash_profile
script:
- echo "=============== deploy ==============="
- if [ "$(kubectl get deployment -n $K8S_NS | grep $DEPLOYMENT_NAME | awk '{print $1}')" ]; then
- kubectl set image deploy $DEPLOYMENT_NAME $DEPLOYMENT_NAME=$PROJECT_IMAGE -n $K8S_NS
- kubectl scale deployment $DEPLOYMENT_NAME --replicas=0 -n $K8S_NS
- kubectl scale deployment $DEPLOYMENT_NAME --replicas=1 -n $K8S_NS
- else
- mv $K8S_DEMO_YAML $DEPLOYMENT_NAME.yaml
- kubectl apply -f $DEPLOYMENT_NAME.yaml -n $K8S_NS
- fi
only:
- master
镜像是私有的,在发布代码跑 CI/CD 之前,k8s 需要配置 imagePullSecrets,在集群环境 master 节点下执行如下命令生成 regsecret
[root@master ~]# kubectl create secret docker-registry regsecret --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=用户名 --docker-password=密码 -n 命名空间
配置里镜像仓库的 secret 之后,本地修改的代码推送到远程仓库,gitlab 会自动跑 CI/CD,如下图
CI/CD 跑成功之后,可在 k8s 集群中查看发布的 pod 状态
[root@master ~]# kubectl get pod -n demo
NAME READY STATUS RESTARTS AGE
springboot-ci-cd-demo-5694574854-8xxh9 1/1 Running 0 29m
页面访问接口 http://192.168.1.25:30080/demo
如上显示说明项目已经部署成功
`
k8s 默认容器如果重建,则容器中的数据文件将会丢失,所以需要将一些数据文件挂载到外部目录,可以参考我的另一篇博客 k8s 集群之使用 nfs 网络存储挂载外部目录和文件