DevOps平台搭建过程详解--Gitlab+Jenkins+Docker+Harbor+K8s集群搭建CICD平台

一、环境说明

1.1CI/CD

CI即为持续集成(Continue Integration,简称CI),用通俗的话讲,就是持续的整合版本库代码编译后制作应用镜像。建立有效的持续集成环境可以减少开发过程中一些不必要的问题、提高代码质量、快速迭代等;(Jenkins)

CD即持续交付Continuous Delivery和持续部署Continuous Deployment,用通俗的话说,即可以持续的部署到生产环境给客户使用,这里分为两个阶段,持续交付我理解为满足上线条件的过程,但是没有上线,持续部署,即为上线应用的过程;(k8s)

1.2 系统架构

研发人员通过Git将代码上传至Gitlab,项目管理员审核代码后合并代码;

Jenkins通过webhook获取Gitlab上的项目代码,并通过maven打包构建镜像,如果构建报错,则可以通过邮件或钉钉等通知相关人员;

镜像构建完成后,Jenkins自动将镜像pull到Harbor镜像仓库;

Harbor镜像仓库通过将镜像push到k8s集群运行,k8s通过编排管理,实现镜像服务的伸缩和高可用。

1.3 软硬件环境

角色 主机名 ip地址 备注
master k8s-master 192.168.250.217 k8s主节点、8核CPU、4GB(CD)
node k8s-node1 192.168.250.218 k8s从节点、8核CPU、4GB
node k8s-node2 192.168.250.219 k8s从节点、8核CPU、4GB
Gitlab+Jenkins+Docker jenkins 192.168.250.188 8核CPU、12GB,Gitlab最少需要4G(CI)
docker镜像仓库:harbor harbor 192.168.250.220 8核CPU、4GB

|---------|----------------------------------|
| 软件 | 版本 |
| linux | centos7 |
| docker | 26.1.3 |
| k8s | 1.22.2 |
| harbor | 2.0.6 |
| Jenkins | 2.457(尽量别用latest版本安装 可能导致插件安装失败) |
| gitlab | 10.7.5 |

二、环境准备

在所有节点操作

2.1 关闭NetworkManager

NetworkManager会和network启动是发生冲突,导致network启动失败,不能远程访问虚拟机;

systemctl stop NetworkManager #临时关闭

systemctl disable NetworkManager #永久关闭网络管理命令

systemctl start network.service #开启网络服

2.2 设置静态ip

2.2.1查看网络配置

ifconfig #查看网络配置

2.2.2 修改网络配置文件

vi /etc/sysconfig/network-scripts/ifcfg-ens33

1)选择动态分配或者静态分配

BOOTPROTO=static #dhcp:自动分配ip ,static:静态ip

2)开启自动打开网卡

ONBOOT=yes #开启启动必须是yes

TYPE=Ethernet

PROXY_METHOD=none

BROWSER_ONLY=no

BOOTPROTO=static #dhcp:自动分配ip ,static:静态ip

DEFROUTE=yes

IPV4_FAILURE_FATAL=no

IPV6INIT=yes

IPV6_AUTOCONF=yes

IPV6_DEFROUTE=yes

IPV6_FAILURE_FATAL=no

IPV6_ADDR_GEN_MODE=stable-privacy

NAME=ens33

UUID=9c922cc8-b3ed-419a-88bd-6fd756e04880

DEVICE=ens33

ONBOOT=yes #开启启动必须是yes

IPADDR=192.168.163.152 #静态ip

NETMASK=255.255.255.0 #

GATEWAY=192.168.163.2 #网关

DNS1=192.168.163.0 #DNS

DNS2=114.114.114.114

2.2.3重启服务

systemctl restart network

2.2.4查看网络状态

systemctl status network.service

图示:

ifconfig

2.3 修改主机名

hostnamectl set-hostname k8s-master #k8s-master 为主机名称

2.4 所有机器关闭防火墙

systemctl stop firewalld #关闭

systemctl disable firewalld #开机不自启

systemctl status firewalld #查看状态

2.5 所有机器关闭selinux

sed -i 's/enforcing/disabled/' /etc/selinux/config

setenforce 0

systemctl status firewalld

2.6 所有机器关闭swap

swapoff -a # 临时关闭

sed -ri 's/.*swap.*/#&/' /etc/fstab #永久关闭

swapon -s #查看swapon分区

2.7 为所有节点安装docker

yum install wget.x86_64 -y

rm -rf /etc/yum.repos.d/*

wget -O /etc/yum.repos.d/centos7.repo http://mirrors.aliyun.com/repo/Centos-7.repo

wget -O /etc/yum.repos.d/epel-7.repo http://mirrors.aliyun.com/repo/epel-7.repo

wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

yum install docker-ce-20.10.11 -y

systemctl start docker

systemctl enable docker

docker version

配置docker加速器

mkdir -p /etc/docker

tee /etc/docker/daemon.json <<-'EOF'

{

"registry-mirrors": ["https://2tefyfv7.mirror.aliyuncs.com"]

}

EOF

systemctl daemon-reload

systemctl restart docker

三、部署k8s集群

3.1 添加主机名与ip的对应关系(k8s-master、k8s-node1、k8s-node2)

bash 复制代码
cat >> /etc/hosts << EOF
192.168.163.151 k8s-master
192.168.163.152 k8s-node1
192.168.163.153 k8s-node2
EOF

source /etc/profile

3.2 将桥接的ipv4流量传递到iptables的链(k8s-master、k8s-node1、k8s-node2)

cat >> /etc/sysctl.d/k8s.conf << EOF

net.bridge.bridge-nf-call-ip6tables = 1

net.bridge.bridge-nf-call-iptables = 1

EOF

3.3 安装kubeadm、kubelet、kubectl(k8s-master、k8s-node1、k8s-node2)

cat <<EOF > /etc/yum.repos.d/kubernetes.repo

[kubernetes]

name=Kubernetes

baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/

enabled=1

gpgcheck=1

repo_gpgcheck=1

gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

EOF

yum install kubelet-1.22.2 kubeadm-1.22.2 kubectl-1.22.2 -y

systemctl enable kubelet && systemctl start kubelet

kubectl version

3.4 修改docker的配置(k8s-master、k8s-node1、k8s-node2)

#镜像加速 registry-mirrors

cat > /etc/docker/daemon.json <<EOF

{

"exec-opts": ["native.cgroupdriver=systemd"],

"registry-mirrors": ["https://2tefyfv7.mirror.aliyuncs.com"]

}

EOF

systemctl daemon-reload

systemctl restart docker.service

systemctl restart kubelet.service

systemctl status kubelet.service

这里从节点的kubelet.service状态报code=exited, status=1/FAILURE是正常的 集群没有初始化导致的

3.5 部署master节点(主节点k8s-master)

3.5.1 集群初始化

kubeadm init \

--apiserver-advertise-address=192.168.163.151 \

--image-repository registry.aliyuncs.com/google_containers \

--kubernetes-version v1.22.2 \

--control-plane-endpoint k8s-master \

--service-cidr=172.16.0.0/16 \

--pod-network-cidr=10.244.0.0/16
这段命令是用于将一个工作节点(worker node)加入到已存在的 Kubernetes 集群中的过程。

kubeadm init 是用来初始化 Kubernetes 集群的命令。下面是一些常用的参数及其说明:

--apiserver-advertise-address: 指定用于通告的 API 服务器的 IP 地址。

--apiserver-bind-port: 指定 API 服务器绑定的端口。

--control-plane-endpoint: 指定控制平面的端口。

--image-repository: 设置 Kubernetes 镜像仓库的地址。

--kubernetes-version: 设置 Kubernetes 版本。

--pod-network-cidr: 设置 Pod 网络的 CIDR 范围。

--service-cidr: 设置服务的 CIDR 范围。

1).遇到报错:

2).解决办法:关闭swap

swapoff -a # 临时关闭

sed -ri 's/.*swap.*/#&/' /etc/fstab #永久关闭

1).遇到报错:

Here is one example how you may list all Kubernetes containers running in docker:

  • 'docker ps -a | grep kube | grep -v pause'

Once you have found the failing container, you can inspect its logs with:

  • 'docker logs CONTAINERID'

error execution phase wait-control-plane: couldn't initialize a Kubernetes cluster

To see the stack trace of this error execute with --v=5 or higher

2).解决办法:

rm -rf /etc/containerd/config.toml

systemctl restart containerd

如果初始化失败,可以重新初始化

kubeadm reset

此命令将删除当前集群的状态信息,并使其回到初始状态

初始化成功

记下红框中内容,添加节点时需要

3.5.2 按照指示执行

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown (id -u):(id -g) $HOME/.kube/config

初始化时 该命令有输出

3.5.3 查看kubelet.service状态

systemctl status kubelet.service

3.5.4 查看节点状态为notready

kubectl get nodes

3.5.5 安装网络插件

官方文档:https://github.com/flannel-io/flannel

最好手动提前拉取所需镜像

docker pull quay.io/coreos/flannel:v0.14.0

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

kubectl apply -f kube-flannel.yml

kubectl get pods --all-namespaces

3.5.6 添加node节点

在k8s-node1和k8s-node1节点执行

docker pull quay.io/coreos/flannel:v0.14.0

kubeadm join k8s-master:6443 --token yt11th.b5wzq4lkjxcsljpg \

--discovery-token-ca-cert-hash sha256:f36824a14f1acb9413246e8f5f0cdf5f6060066f7e4eec6d27edd69004499f9f

在主节点k8s-master查看节点状态为notready

四、部署Gitlab(192.168.163.155)

4.1 配置docker加速器

mkdir -p /etc/docker

tee /etc/docker/daemon.json <<-'EOF'

{

"registry-mirrors": ["https://2tefyfv7.mirror.aliyuncs.com"]

}

EOF

systemctl daemon-reload

systemctl restart docker

4.2 安装并配置Gitlab

docker pull beginor/gitlab-ce

4.2.1 创建共享卷目录

mkdir -p /data/gitlab/etc/ /data/gitlab/log/ /data/gitlab/data

chmod 777 /data/gitlab/etc/ /data/gitlab/log/ /data/gitlab/data/

4.2.2 创建 gitlab 容器

docker run -itd --name=gitlab --restart=always --privileged=true -p 8443:443 -p 80:80 -p 222:22 -v /data/gitlab/etc:/etc/gitlab -v /data/gitlab/log:/var/log/gitlab -v /data/gitlab/data:/var/opt/gitlab beginor/gitlab-ce

docker ps

切记:这里的端口要设置成80,要不push项目会提示没有报错,如果宿主机端口被占用,需要把这个端口腾出来

4.2.3 关闭容器修改配置文件

docker stop gitlab
cat /data/gitlab/etc/gitlab.rb |grep external_url

sed -i "/external_url 'GENERATED_EXTERNAL_URL'/a external_url\t'http://192.168.163.155' " /data/gitlab/etc/gitlab.rb

cat /data/gitlab/etc/gitlab.rb |grep external_url

external_url 'http://192.168.163.155'​

gitlab_rails['gitlab_ssh_host'] = '192.168.163.155''

cat /data/gitlab/etc/gitlab.rb |grep gitlab_ssh_host

sed -i "/gitlab_ssh_host/a gitlab_rails['gitlab_ssh_host'] = '192.168.163.155' " /data/gitlab/etc/gitlab.rb

cat /data/gitlab/etc/gitlab.rb |grep gitlab_ssh_host

gitlab_rails[gitlab_shell_ssh_port] = 222

cat /data/gitlab/etc/gitlab.rb | grep gitlab_shell_ssh

sed -i "/gitlab_shell_ssh_port/a gitlab_rails['gitlab_shell_ssh_port'] = 222" /data/gitlab/etc/gitlab.rb

cat /data/gitlab/etc/gitlab.rb | grep gitlab_shell_ssh

vim /data/gitlab/data/gitlab-rails/etc/gitlab.yml

4.2.4 修改完配置文件之后。直接启动容器

docker start gitlab

docker ps

​在宿主机所在的物理机访问,http://192.168.163.155/ ,会自动跳转到修改密码(root用户),如果密码设置的没有满足一定的复杂性,则会报500,需要从新设置

4.2.5 新建SSH密钥

1.进入gitlab容器

docker exec -it gitlab /bin/sh

2.生成密钥

ssh-keygen

一路回车就可以完成 创建SSH 密钥,可以看到 ~/.ssh目录下生成了 id_rsa 和 id_rsa.pub 两个文件

3.查看密钥

cat ~/.ssh/id_rsa.pub

4.gitlab配置密钥

5.推出容器

exit

五、部署harbor(192.168.163.156)

5.1 安装docker-compose

yum install -y docker-compose

配置docker加速器

mkdir -p /etc/docker

tee /etc/docker/daemon.json <<-'EOF'

{

"registry-mirrors": ["https://2tefyfv7.mirror.aliyuncs.com"]

}

EOF

systemctl daemon-reload

systemctl restart docker

5.2 使用安装包安装 harbor

harbor安装包:harbor

解压安装harbor

tar -zxvf harbor-offline-installer-v2.0.6.tgz

docker load -i harbor/harbor.v2.0.6.tar.gz

5.3 修改配置文件

cd harbor/

cp harbor.yml.tmpl harbor.yml

vim harbor.yml

harbor.yml:设置IP和用户名密码 注释写https

5.4 执行./prepare && ./install.sh 初始化harbor

./prepare

./install.sh

[root@harbor ~]# cd harbor/

[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml

[root@harbor harbor]# vim harbor.yml

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]# ./prepare

prepare base dir is set to /root/harbor

ERROR:root:Error: The protocol is https but attribute ssl_cert is not set

Error happened in config validation...

[root@harbor harbor]# ls

common common.sh harbor.v2.0.6.tar.gz harbor.yml harbor.yml.tmpl input install.sh LICENSE prepare

[root@harbor harbor]# prepare

bash: prepare: 未找到命令...

[root@harbor harbor]# ./prepare

prepare base dir is set to /root/harbor

Error happened in config validation...

ERROR:root:Error: The protocol is https but attribute ssl_cert is not set

[root@harbor harbor]# vim harbor.yml

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]# ./prepare

prepare base dir is set to /root/harbor

Error happened in config validation...

ERROR:root:Error: The protocol is https but attribute ssl_cert is not set

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]# vim harbor.yml

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]# clear

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]# ./prepare

prepare base dir is set to /root/harbor

WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https

Generated configuration file: /config/log/logrotate.conf

Generated configuration file: /config/log/rsyslog_docker.conf

Generated configuration file: /config/nginx/nginx.conf

Generated configuration file: /config/core/env

Generated configuration file: /config/core/app.conf

Generated configuration file: /config/registry/config.yml

Generated configuration file: /config/registryctl/env

Generated configuration file: /config/registryctl/config.yml

Generated configuration file: /config/db/env

Generated configuration file: /config/jobservice/env

Generated configuration file: /config/jobservice/config.yml

Generated and saved secret to file: /data/secret/keys/secretkey

Successfully called func: create_root_cert

Generated configuration file: /compose_location/docker-compose.yml

Clean up the input dir

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]#

[root@harbor harbor]# ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 26.1.3

[Step 1]: checking docker-compose is installed ...

Note: docker-compose version: 1.18.0

[Step 2]: loading Harbor images ...

Loaded image: goharbor/notary-server-photon:v2.0.6

Loaded image: goharbor/clair-photon:v2.0.6

Loaded image: goharbor/clair-adapter-photon:v2.0.6

Loaded image: goharbor/harbor-portal:v2.0.6

Loaded image: goharbor/harbor-core:v2.0.6

Loaded image: goharbor/harbor-db:v2.0.6

Loaded image: goharbor/harbor-jobservice:v2.0.6

Loaded image: goharbor/redis-photon:v2.0.6

Loaded image: goharbor/notary-signer-photon:v2.0.6

Loaded image: goharbor/harbor-log:v2.0.6

Loaded image: goharbor/harbor-registryctl:v2.0.6

Loaded image: goharbor/trivy-adapter-photon:v2.0.6

Loaded image: goharbor/chartmuseum-photon:v2.0.6

Loaded image: goharbor/prepare:v2.0.6

Loaded image: goharbor/nginx-photon:v2.0.6

Loaded image: goharbor/registry-photon:v2.0.6

[Step 3]: preparing environment ...

[Step 4]: preparing harbor configs ...

prepare base dir is set to /root/harbor

WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https

Clearing the configuration file: /config/log/logrotate.conf

Clearing the configuration file: /config/log/rsyslog_docker.conf

Clearing the configuration file: /config/nginx/nginx.conf

Clearing the configuration file: /config/core/env

Clearing the configuration file: /config/core/app.conf

Clearing the configuration file: /config/registry/passwd

Clearing the configuration file: /config/registry/config.yml

Clearing the configuration file: /config/registryctl/env

Clearing the configuration file: /config/registryctl/config.yml

Clearing the configuration file: /config/db/env

Clearing the configuration file: /config/jobservice/env

Clearing the configuration file: /config/jobservice/config.yml

Generated configuration file: /config/log/logrotate.conf

Generated configuration file: /config/log/rsyslog_docker.conf

Generated configuration file: /config/nginx/nginx.conf

Generated configuration file: /config/core/env

Generated configuration file: /config/core/app.conf

Generated configuration file: /config/registry/config.yml

Generated configuration file: /config/registryctl/env

Generated configuration file: /config/registryctl/config.yml

Generated configuration file: /config/db/env

Generated configuration file: /config/jobservice/env

Generated configuration file: /config/jobservice/config.yml

Creating harbor-log ... done

Generated configuration file: /compose_location/docker-compose.yml

Clean up the input dir

Creating harbor-db ... done

Creating harbor-core ... done

Creating network "harbor_harbor" with the default driver

Creating nginx ... done

Creating harbor-portal ...

Creating redis ...

Creating registryctl ...

Creating registry ...

Creating harbor-db ...

Creating harbor-core ...

Creating harbor-jobservice ...

Creating nginx ...

✔ ----Harbor has been installed and started successfully.----

[root@harbor harbor]#

5.5 查看相关镜像

docker ps

5.6 访问测试

http://192.168.163.156

5.7 CI服务器的docker配置(jenkins:192.168.163.155)

这里因为我们要在192.168.163.155(CI服务器)上push镜像到192.168.163.156(私仓),所有需要修改CI服务器上的Docker配置。

cat /etc/docker/daemon.json

vim /etc/docker/daemon.json

[root@jenkins ~]# cat /etc/docker/daemon.json

{

"registry-mirrors": ["https://2tefyfv7.mirror.aliyuncs.com"],

"insecure-registries": ["192.168.163.156"]

}

[root@jenkins ~]#

加载使其生效

systemctl daemon-reload

systemctl restart docker

CI机器简单测试一下

docker login 192.168.163.156

测试上传镜像

docker tag beginor/gitlab-ce 192.168.163.156/library/gitlab-ce #beginor/gitlab-ce为本地镜像 可以

自定义

docker images

docker push 192.168.163.156/library/gitlab-ce

5.8 CD服务器的docker配置(k8s-master、k8s-node1、k8s-node2)

cat /etc/docker/daemon.json

vim /etc/docker/daemon.json

cat /etc/docker/daemon.json

加载使其生效

systemctl daemon-reload

systemctl restart docker

CI机器简单测试一下

5.9 harbor开机启动

编辑/lib/systemd/system/harbor.service

vim /lib/systemd/system/harbor.service

[Unit]

Description=Harbor

After=network.service docker.service systemd-networkd.service systemd-resolved.service

Requires=docker.service

Documentation=http://github.com/vmware/harbor

[Service]

Type=simple

Restart=on-failure

RestartSec=5

ExecStart=/usr/bin/docker-compose -f /root/harbor/docker-compose.yml up

ExecStop=/usr/bin/docker-compose -f /root/harbor/docker-compose.yml down

[Install]

WantedBy=multi-user.target

重载配置

chmod 755 /lib/systemd/system/harbor.service

systemctl restart harbor

systemctl status harbor

systemctl enable harbor

六、安装配置jenkins(jenkins:192.168.163.155)

6.1 镜像jenkins拉取

docker pull jenkins/jenkins:2.457

6.2 创建共享卷,修改所属组和用户,和容器里相同

mkdir /jenkins

chown 1000:1000 /jenkins

这里为什么要改成 1000,是因为容器里是以 jenkins 用户的身份去读写数据,而在容器里jenkins 的 uid 是 1000

6.3 创建 jenkins 容器

docker run -dit -p 8080:8080 -p 50000:50000 --name jenkins --privileged=true --restart=always -v /jenkins:/var/jenkins_home jenkins/jenkins:2.457

docker ps | grep jenkins

访问jenkins http://192.168.163.155:8080

关闭Jenkins容器,因为要修改配置

docker stop jenkins

6.4 配置jenkins环境

更换国内清华大学镜像,Jenkins下载插件特别慢,更换国内的清华源的镜像地址会快不少

cat /jenkins/hudson.model.UpdateCenter.xml

sed -i 's#updates.jenkins.io/update-center.json#mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json#g ' /jenkins/hudson.model.UpdateCenter.xml

cat /jenkins/hudson.model.UpdateCenter.xml

"https://www.google.com/" 替换为 "https://www.baidu.com/"

yum install -y jq

cat /jenkins/updates/default.json | jq '.connectionCheckUrl'

cat /jenkins/updates/default.json | jq 'keys'

替换

sed -i s#https://www.google.com/#https://www.baidu.com/#g /jenkins/updates/default.json

重启docker,获取登录密匙

docker start jenkins

cat /jenkins/secrets/initialAdminPassword

需要修改jenkins绑定的docker的启动参数,ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock

vim /lib/systemd/system/docker.service

修改镜像库启动参数后需要重启docker

systemctl daemon-reload

systemctl restart docker

6.5 配置Jenkins 安装插件

安装和配置docker插件

依此点击Manage Jenkins->Manage Plugins->AVAILABLE->Search 搜索docker、docker-build-step

需要修改harbor(192.168.163.156)的docker的启动参数,ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock

vim /lib/systemd/system/docker.service

修改镜像库启动参数后需要重启docker

systemctl daemon-reload

systemctl restart docker

以上docker配置是为了Build / Publish Docker Image时使用,定义了用那个服务器的docker执行docker命令

jenkins 安全设置

后面 gitlab 要和 jenkins 进行联动,所以必须要需要对 jenkins 的安全做一些设置,依次点击 系统管理-全局安全配置-授权策略,勾选"匿名用户具有可读权限"

七、Jenkins发布打包成Docker的spring boot项目到K8s集群

7.1 创建spring boot 项目

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.3.7.RELEASE</version>

</parent>

<groupId>com.example</groupId>

<artifactId>demo</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>demo</name>

<description>demo</description>

<properties>

<java.version>1.8</java.version>

<java.version>1.8</java.version>

<!--换成你的harbor仓库地址-->

<docker.repostory>192.168.163.156</docker.repostory>

<!--换成你的仓库项目名称-->

<docker.registry.name>demo</docker.registry.name>

<docker.image.tag>0.0.1</docker.image.tag>

<docker.maven.plugin.version>1.4.10</docker.maven.plugin.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

<build>

<finalName>demo</finalName>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

<configuration>

<excludes>

<exclude>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

</exclude>

</excludes>

</configuration>

</plugin>

<plugin>

<groupId>com.spotify</groupId>

<artifactId>dockerfile-maven-plugin</artifactId>

<version>${docker.maven.plugin.version}</version>

<!--以下配置依赖docker环境 maven编译打包时会生成docker镜像 本地编译时先注释掉 上传git时在打开-->

<executions>

<execution>

<id>default</id>

<goals>

<goal>build</goal>

<goal>push</goal>

</goals>

</execution>

</executions>

<configuration>

<contextDirectory>${project.basedir}</contextDirectory>

<useMavenSettingsForAuth>true</useMavenSettingsForAuth>

<repository>{docker.repostory}/{docker.registry.name}/${project.artifactId}</repository>

<!--换成你的harbor仓库账号密码-->

<username>admin</username>

<password>root123456</password>

<tag>${docker.image.tag}</tag>

<buildArgs>

<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>

</buildArgs>

</configuration>

</plugin>

</plugins>

<resources>

<!-- 指定 src/main/resources下所有文件及文件夹为资源文件 -->

<resource>

<directory>src/main/resources</directory>

<targetPath>${project.build.directory}/classes</targetPath>

<includes>

<include>**/*</include>

</includes>

<filtering>true</filtering>

</resource>

</resources>

</build>

</project>

创建测试接口

package com.example.demo.api;

import lombok.AllArgsConstructor;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**

* @author lgp

* @description: 测试PI

* @date 2023/9/6

*/

@RestController

@AllArgsConstructor

@RequestMapping("/api")

public class testApi {

@GetMapping("/test")

public String test() {

return "测试1112233552219122120911!!";

}

}

启动项目

访问测试接口

添加Dockerfile文件

该文件时docker创建容器的文件,名称不可改变

#添加依赖环境,前提是将Java8的Docker镜像从官方镜像仓库pull下来,然后上传到自己的Harbor私有仓库中

FROM 192.168.163.156/library/java:8

#指定镜像制作作者,可自己随意设置

MAINTAINER admin

#运行目录

VOLUME /tmp

#将本地的文件拷贝到容器,一般在项目的target目录下,要根据项目自己修改

ADD target/*jar app.jar

#启动容器后自动执行的命令

ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]

添加demo.yaml文件

该文件是k8s创建pod的配置文件

apiVersion: apps/v1

kind: Deployment

metadata:

name: demo

labels:

app: demo

spec:

replicas: 1

selector:

matchLabels:

app: demo

template:

metadata:

labels:

app: demo

spec:

imagePullSecrets: #使用imagePullSecrets参数指定镜像拉取秘钥

  • name: harbor-registry #使用我们的secret,即harbor-registry

containers:

  • name: demo

image: 192.168.163.156/demo/demo:0.0.1

ports:

  • containerPort: 8080 #修改成你项目的端口

imagePullPolicy: Always #镜像拉取策略:每次都拉去最新的镜像


apiVersion: v1

kind: Service

metadata:

name: demo

labels:

app: demo

spec:

ports:

  • name: http

port: 8080 #修改成你项目的端口

nodePort: 30001 ##容器暴露的访问端口,要确定无冲突,否则需修改

type: NodePort

selector:

app: demo

项目上传到gitlab

7.2 拉取java8镜像

在jenkins服务器(192.168.163.155)上拉取java8镜像,然后推送至harbor仓库,一会打包构建docker镜像的时候会用到。

docker pull java:8

docker tag java:8 192.168.163.156/library/java:8

docker login 192.168.163.156

docker push 192.168.163.156/library/java:8

7.3 配置 jenkins容器到其他服务的ssh免密登录

jenkins执行构建命令时,需要ssh访问jenkins容器所在服务器(192.168.163.155)和k8s主节点服务器(192.168.163.151),所以需要配置ssh免密登录

在jenkins容器所在服务器(192.168.163.155)上进入jenkins容器

docker exec -it jenkins bash

生产密钥

ssh-keygen -t rsa

将公钥复制到jenkins容器所在服务器(192.168.163.155)

ssh-copy-id root@192.168.163.155

将公钥复制到k8s主节点服务器(192.168.163.151)

7.4 k8s 创建私有镜像仓库Secret(k8s主节点服务器192.168.163.151)

k8s需要从harbor私有进行仓库拉取镜像时,需要创建Secret,配置harbor私有镜像仓库地址、账号密码

#docker-registry是关键字 harbor-registry是自定义的名称与demo.yaml中的imagePullSecrets.name值一致

kubectl -n default create secret docker-registry harbor-registry --docker-email=baidu.com@example --docker-username=root --docker-password=root123456 --docker-server=192.168.163.156

kubectl get secret harbor-registry #查看secret

7.5 安装jdk和maven(jenkins:192.168.163.155)

安装mvn

cd /usr/local/

wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz

tar -zxvf apache-maven-3.6.3-bin.tar.gz

安装jdk

yum install -y java-1.8.0-openjdk-devel

配置环境变量

vim /etc/profile

MAVEN_HOME=/usr/local/apache-maven-3.6.3

JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64 ##这里的路径注意使用你安装的jdk的版本号

CLASS_PATH=.:$JAVA_HOME/lib

PATH=MAVEN_HOME/bin:JAVA_HOME/bin:$PATH

刷新环境变量

source /etc/profile

检查是否安装成功

mvn -v

java -version

7.6 使用jenkins构建发布项目

#使用jenkins宿主机的maven打包 /jenkins/workspace是jenkins 拉取git项目的目录 创建jenkins容器时已经做好了映射

ssh -tt root@192.168.163.155 'docker rmi 192.168.163.156/demo/demo:0.0.1

/usr/local/apache-maven-3.6.3/bin/mvn -f /jenkins/workspace/demo/pom.xml clean install -Dmaven.test.skip=true'

ssh -tt root@192.168.163.155 'docker login 192.168.163.156

docker push 192.168.163.156/demo/demo:0.0.1'

scp /var/jenkins_home/workspace/demo/demo.yaml root@192.168.163.151:/

ssh -tt root@192.168.163.151 '/usr/bin/kubectl delete -f /demo.yaml' #第一次执行时 由于没有该pod 会报错 所以第一次先注释掉

ssh -tt root@192.168.163.151 '/usr/bin/kubectl apply -f /demo.yaml'

镜像仓库

查看k8s pod

kubectl get pod --all-namespaces

访问应用:192.168.163.151:30001/api/test

方式二 构建 (比较麻烦 依赖于 6.5中的安装和配置docker插件)

分为三步:

1.执行 shell maven编译生成jar包

2.Build / Publish Docker Image 生成镜像并上传至镜像仓库

3.执行 shell 远程k8s更新pod

以上项目部署CI/CD 还需要手动在jenkins中构建项目,下面整合Jenkins和gitlab,使用gitlab的webhook功能,实现代码提交到gitlab后 自动构建部署项目

7.7 配置 gitlab 和 jenkins 的联动

Jenkins安装gitlab插件

修改项目构建配置

gitlab配置

回到需要自动构建的项目

保存后测试

返回200说明成功

验证下自动构建是否成功

现在是第39次构建,修改代码提交gitlab

提交后开始自动构建

访问应用:192.168.163.151:30001/api/test

至此,搭建Gitlab+Jenkins+Docker+Harbor+K8s集群搭建CICD平台完成!

相关推荐
萨格拉斯救世主2 小时前
jenkins使用slave节点进行node打包报错问题处理
运维·jenkins
A ?Charis11 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab
秋说18 小时前
开源代码管理平台Gitlab如何本地化部署并实现公网环境远程访问私有仓库
gitlab·源代码管理
大卡尔20 小时前
Reviewbot 开源 | 为什么我们要打造自己的代码审查服务?
devops·code review·静态检查·工程效率
极小狐1 天前
驭码上新,AI Code Review、基于代码库的知识问答,让研发起飞
gitlab·devsecops·devops·极狐gitlab·安全合规
Narutolxy1 天前
精准优化Elasticsearch:磁盘空间管理与性能提升技巧20241106
大数据·elasticsearch·jenkins
蚊子不吸吸1 天前
DevOps开发运维简述
linux·运维·ci/cd·oracle·kubernetes·gitlab·devops
思码逸研发效能2 天前
度量数据是人工凭感觉录入的,产生的偏差如何解决?
研发效能·devops·研发效能度量·研发管理
晨欣2 天前
Elasticsearch里的索引index是什么概念?(ChatGPT回答)
大数据·elasticsearch·jenkins
铭毅天下3 天前
基于 Canal + Elasticsearch 的业务操作日志解决方案
大数据·elasticsearch·搜索引擎·全文检索·jenkins