完成初始化集群的环境:
(vms21)192.168.26.21——master1
(vms22)192.168.26.22——worker1
(vms23)192.168.26.23——worker2
(vms51)192.168.26.51——harbor镜像仓库
(vms31)192.168.26.31——devops主机:docker客户端 + gitlab仓库 + jenkins
实际工作中:
程序员将开发好的应用构建打包成镜像,推送到公司的私有仓库中,运维将最新的镜像部署到k8s环境中,在这个过程中,就是容易发生程序员和运维之间的推诿扯皮(程序bug问题等等)
devops——一种运维+开发的理念,目的是为了协调程序员和运维之间的工作
具体的实施,需要安装一系列的devops工具
gitlib——代码仓库
CI/CD——持续集成、持续部署、持续交付,如jenkins
CI服务器:持续集成工具,将代码构建、打包成镜像
CD服务器:持续部署、持续交付
docker客户端——安装了nerdctl或docker客户端工具的机器,jenkins需要调用外部的docker客户端,将打包的镜像推送到镜像仓库
程序员将代码推送到gitlab代码仓库中,同时触发持续集成工具jenkins,jenkins将代码构建、打包成镜像后推送到镜像仓库中,然后使用新的镜像部署到k8s环境中,这样一来,程序员只要一提交代码,就自动去完成后续的打包、部署等操作
实验环境:
实验中为了节约机器,将gitlab以容器的方式运行,jenkins以容器的方式运行
将一台虚拟机作为harbor服务器:(vms51)192.168.26.51
将一台虚拟机作为devops主机,里面包括docker客户端、gitlab容器、jenkins容器:(vms31)192.168.26.31
(参考:一、容器基础章节内容)
搭建好harbor后,登录并创建一个名为“cka”的公开项目(仓库)
因为将vms51作为了镜像仓库,所以要在所有worker节点上(vms22、vms23)配置containerd镜像源,才可以从vms51镜像仓库中拉取镜像
#1.修改/etc/containerd/config.toml
vim /etc/containerd/config.toml
#2.输入“/”,搜索“mirrors”,在下面加上:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.26.51"]
endpoint = ["http://192.168.26.51"]
#3.重启containerd生效
systemctl restart containerd
1.安装docker
yum install docker-ce -y
2.启动docker
systemctl enable docker --now
3.修改docker启动脚本
通过systemctl status docker查看到Loaded,得知启动脚本为/usr/lib/systemd/system/docker.service
vim /usr/lib/systemd/system/docker.service
此时vms31这台宿主机上安装好了docker,对于jenkins来说,需要借助外部的docker客户端来进行推送镜像,因此需要设置允许别人远程连接到这个docker上,并且docker能够访问harbor仓库,以http的方式访问
在docker的启动脚本文件中的修改如下:
ExecStart=/usr/bin/dockerd 后增加:
a:“–insecure-registry=192.168.26.51”——harbor仓库地址
b:“-H tcp://0.0.0.0:2376”——开放2376端口允许别人连接进来
修改后为:
ExecStart=/usr/bin/dockerd --insecure-registry=192.168.26.51 -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock
4.配置docker加速器
#编辑配置文件,没有则vim手动生成一份
cat /etc/docker/daemon.json
#插入:
{
"registry-mirrors": ["https://tcvfiu1v.mirror.aliyuncs.com"]
}
5.重新加载脚本并重启docker生效
systemctl daemon-reload ; systemctl restart docker
1.拉取gitlab镜像
docker pull beginor/gitlab-ce
2.创建gitlab容器,同时在创建时需要设置一系列的数据卷
/data/gitlab/etc:/etc/gitlab——用来存储gitlab配置文件
/data/gitlab/log:/var/log/gitlab——用来存储gitlab日志
/data/gitlab/data:/var/opt/gitlab——往gitlab推送代码时所需要的数据
#首先在vms31上创建所需要的数据卷目录
mkdir -p /data/gitlab/etc /data/gitlab/log /data/gitlab/data
#赋予权限
chmod 777 /data/gitlab/etc /data/gitlab/log /data/gitlab/data
#创建容器同时添加数据卷
#--privileged=true 以特权方式运行
docker run -dit --name=gitlab --restart=always -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 --privileged=true beginor/gitlab-ce
创建好后,可以看到宿主机数据卷下都生成了相应的文件
ls /data
#输出:
gitlab
ls /data/gitlab/
#输出:
data etc log
ls /data/gitlab/data
#输出:
backups git-data gitlab-ci gitlab-rails gitlab-shell postgresql redis trusted-certs-directory-hash
ls /data/gitlab/log
#输出:
gitlab-rails gitlab-shell postgresql reconfigure redis sshd
ls /data/gitlab/etc
#输出:
gitlab.rb ssh_host_ecdsa_key ssh_host_ed25519_key ssh_host_rsa_key trusted-certs
gitlab-secrets.json ssh_host_ecdsa_key.pub ssh_host_ed25519_key.pub ssh_host_rsa_key.pub
3.修改gitlab配置文件(gitlab.rb、gitlab.yml),因有了数据卷,因此直接修改宿主机下的配置文件,就可以生效到容器中
#先停止gitlab进程
docker stop gitlab
vim /data/gitlab/etc/gitlab.rb
#取消以下属性的注释并修改为:
#修改外部访问的地址为本地IP
external_url 'http://192.168.26.31'
#ssh_host改为本地IP
gitlab_rails['gitlab_ssh_host']='192.168.26.31'
#ssh_port端口改为222(创建容器时映射的宿主机端口为222)
gitlab_rails['gitlab_shell_ssh_port']=222
vim /data/gitlab/data/gitlab-rails/etc/gitlab.yml
#将gitlab.host改为本地IP
production: &base
gitlab:
host: 192.168.26.31
port: 80
https: false
...
#启动gitlab
docker start gitlab
4.访问gitlab
浏览器访问:http://192.168.26.31/
设置密码(密码需要一定复杂度,否则会失败)
使用root用户登录
创建一个新项目,项目名称p1,可见等级选择公开
从gitlab拉取时,可以使用http方式拉取,也可以使用ssh方式拉取
若使用ssh方式拉取,则首先需要生成密钥
#vms31上生成密钥
ssh-keygen -N ""
#然后回车,会在.ssh/目录下生成id_rsa.pub公钥,cat输出密钥内容
cat .ssh/id_rsa.pub
在gitlab上点击右上角设置-SSH密钥,将密钥内容复制上去添加密钥
1.使用gitlab进行代码管理时需要下载git
#vms31上下载git
yum install git
2.克隆项目到vms31上
git clone ssh://git@192.168.26.31:222/root/p1.git
3.查看项目
ls
#输出:
p1
当然也可以通过http方式克隆,但是在推送代码时会要求输入密码
4.进入项目下,随便编辑一个文件
cd p1/
vim index.html
5.提交代码时,首先设置一个用户,作为这个用户去提交
git config --global user.name "ctyFL"
git config --global user.email xxx邮箱
git config --global push.default simple
#可以通过list查看做过哪些用户设置
git config --list
提交
git add .
git commit -m "备注"
git push
1.下载jenkins镜像
docker pull jenkins/jenkins:2.289.2-lts-centos7
2.查看jenkinds镜像的结构
可以看到配置了数据卷/var/jenkins_home、变量JENKINS_SLAVE_AGENT_PORT=50000、ARG agent_port=50000 、ARG http_port=8080 、ARG gid=1000、ARG uid=1000
docker history jenkins/jenkins:2.289.2-lts-centos7
#输出:
...
VOLUME [/var/jenkins_home]
...
ENV JENKINS_SLAVE_AGENT_PORT=50000
...
ARG agent_port=50000
ARG http_port=8080
ARG gid=1000
ARG uid=1000
3.根据镜像结构中的信息,创建一个宿主机下目录,作为数据卷挂载点映射容器中/var/jenkins_home
mkdir /jenkins ; chown 1000.1000 /jenkins
4.结合镜像结构中的信息,创建jenkins容器
docker run -dit -p 8080:8080 -p 50000:50000 --name jenkins --privileged=true --restart=always -v /jenkins:/var/jenkins_home jenkins/jenkins:2.289.2-lts-centos7
创建容器后,可以看到数据卷目录下生成了很多文件
ls /jenkins
#输出:
config.xml identity.key.enc logs plugins secrets users
copy_reference_file.log jenkins.telemetry.Correlator.xml nodeMonitors.xml secret.key updates war
hudson.model.UpdateCenter.xml jobs nodes secret.key.not-so-secret userContent
5.修改jenkins配置文件
首先停止jenkins进程
docker stop jenkins
hudson.model.UpdateCenter.xml——安装插件、更新jenkins时会从什么地方下载,默认为国外地址,修改为国内镜像
vim /jenkins/hudson.model.UpdateCenter.xml
#url修改为:
http://mirrors.tuna.tsinghua.edu.cn/jenkins
修改/updatesdefault.json内容,将s/google/baidu/替换为/jenkins/updates/default.json
sed -i 's/google/baidu/' /jenkins/updates/default.json
启动jenkins
docker start jenkins
1.浏览器中访问jenkins:http://192.168.26.31:8080
会出现解锁jenkins的界面,“在/var/jenkins_home/secrets/initialAdminPassword中找到密码”
有了数据卷,我们直接到宿主机的挂载点下找到密码
cat /jenkins/secrets/initialAdminPassword
将密码复制上登录
根据提示,选择“安装推荐的插件”
根据提示,创建第一个管理员用户,保存并完成
实例配置,使用默认设置,保存并完成
2.安装jenkins所需插件及相关配置
(1)若是旧版本,会有 “Manage Jenkins” 这个菜单
点击 “Manage Jenkins” ——管理jenkins
当前安装的下列组件已有警告发布——jenkins版本太旧
点击 “新版本的 Jenkins (2.346.3) 可以下载 (变更记录)” 下载最新版本的war包
并上传到宿主机中替换容器中旧版war包
docker cp jenkins.war jenkins:/usr/share/jenkins/jenkins.war
导入后重启
docker restart jenkins
重新登录jenkins,此时就是最新版的了,后续升级也是同样的方式
(2)点击 “系统管理” 菜单
找到 “系统配置” 下的 “插件管理”
选择 “可选插件”
在搜索框中输入 “docker”
在列表中选中 “Docker”、“docker-build-step” 这两个插件进行安装
安装完成后,回到 “系统管理”,找到 “系统配置” 下的 “节点管理”
点击进入,找到左边菜单的 “Configure Clouds”
在 “Add a new cloud” 下来选中选择 “Docker” 进行添加
点击 “Docker Cloud details…”,在这里就是配置jenkins调用docker的地址,即vms31上的docker客户端,URI中输入 “tcp://192.168.26.31:2376”
点击 “Test Connection”,能够出现版本信息即代表测试连接成功
然后点击最下面的 “Save” 保存配置
回到 “系统管理”,找到 “系统配置” 下的 “系统配置”
找到下面的 “Docker Builder” ,在 “Docker URI” 中输入 “tcp://192.168.26.31:2376” ,点击 “Test Connection”,显示 “Connected to tcp://192.168.26.31:2376” 即表示测试连接成功
然后点击最下面的 “保存”
3.配置jenkins的安全策略
因为推送最新的代码到gitlab后,需要去触发jenkins进行后续工作,因此我们需要去配置一些安全策略
点击 “系统管理” 菜单,找到 “安全” 下的 “全局安全配置”
找到 “授权策略”,将 “登录用户可以做任何事” 和下面的 “匿名用户具有可读权限” 勾上
找到 “跨站请求伪造保护”,这里无法关闭,因此我们通过修改jenkins容器中的运行脚本来实现
先点击最下面的 “保存”
通过docker top jenkins
,可以看到/usr/local/bin/jenkins.sh脚本运行了一个java指令(java -Duser.home…)
docker top jenkins
#输出:
UID PID PPID C STIME TTY TIME CMD
tom 17041 17021 0 16:57 pts/0 00:00:00 /sbin/tini -- /usr/local/bin/jenkins.sh
tom 17068 17041 1 16:57 pts/0 00:00:32 java -Duser.home=/var/jenkins_home -Djenkins.model.Jenkins.slaveAgentPort=50000 -jar /usr/share/jenkins/jenkins.war
在vms31上以root用户进入jenkins容器,编辑/usr/local/bin/jenkins.sh这个脚本文件
docker exec -it -u root jenkins bash
vi /usr/local/bin/jenkins.sh
#在文件的最下面可以看到这一行“exec java -Duser.home="$JENKINS_HOME" "${java_opts_array[@]}" -jar ${JENKINS_WAR} "${jenkins_opts_array[@]}" "$@"”
#添加这个参数“-Dhudson.security.csrf.GlobalCrumblssuerConfiguration.DISABLE_CSRF_PROTECTION=true”
#意味关闭跨站点请求伪造保护
#修改后为:
exec java -Duser.home="$JENKINS_HOME" -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true "${java_opts_array[@]}" -jar ${JENKINS_WAR} "${jenkins_opts_array[@]}" "$@"
fi
#退出容器
exit
#重启jenkins生效
docker restart jenkins
再次登录到jenkins WEB端,可以看到 “跨站请求伪造保护” 已经被关闭掉了
1.jenkins新建任务前环境准备
新建关于代码提交到gitlab后触发jenkins后续该做的任务
(1)首先在k8s环境中创建一个命名空间 “ns1”,并且切换到该命名空间下
#在master上新建命名空间ns1
kubectl create ns ns1
#切换到该命名空间下
kubens ns1
(2)master上在ns1命名空间下创建一个deployment,yaml如下(web1.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web1
name: web1
spec:
replicas: 1
selector:
matchLabels:
app: web1
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web1
spec:
terminationGracePeriodSeconds: 0
containers:
- image: nginx
name: c1
imagePullPolicy: IfNotPresent
status: {}
(3)master上创建这个deployment
kubectl apply -f web1.yaml
(4)查看IP等信息
kubectl get pods -o wide
#输出:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web1-667b8f7dd8-4rg94 1/1 Running 0 5s 10.244.70.73 vms23.rhce.cc <none> <none>
(5)master上为这个deployment创建一个svc
kubectl expose --name=svc1 deploy web1 --port 80 --type NodePort
查看
kubectl get svc
#输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc1 NodePort 10.104.194.31 <none> 80:30965/TCP 5s
(6)master上创建一个kubeconfig认证文件kc1(参考十五、安全管理:验证与授权中的创建kubeconfig认证文件实验)
然后将kc1拷贝至vms31上
scp kc1 192.168.26.31:~
然后将kc1认证文件拷贝至jenkins容器中根目录下
docker cp kc1 jenkins:/
(7)vms31上安装k8s客户端工具,以二进制的形式安装
curl -LO https://dl.k8s.io/release/v1.24.2/bin/linux/amd64/kubectl
然后将kubectl拷贝至jenkins容器中根目录下
docker cp kubectl jenkins:/
进入jenkins容器,给kubectl、kc1文件赋予可执行权限
docker exec -it -u root jenkins bash
chmod +x kubectl
chmod 644 kc1
(8)测试,在容器中,使用kc1作为kubeconfig认证文件,使用kubectl命令行,输入“get nodes”
./kubectl --kubeconfig=./kc1 get nodes
若提示没有权限,则在master上给用户(这里为john)授权
kubectl create clusterrolebinding rbindx --clusterrole=cluster-admin --user=john
再次在jenkins中测试使用kubectl命令行工具
2.来到jenkins网页端新建任务
(1)随便输入名称如“devops001”
(2)选择 “构建一个自由风格的软件项目”,点击确定
(3)因为需要gitlab去触发jenkins,所以在 “构建触发器” 这项下,勾选 “触发远程构建”,并在下面的 “身份验证令牌” 处随便写个口令如 “123123”
并且可以看到输入口令的下面就有jenkins地址的信息 “Use the following URL to trigger build remotely: JENKINS_URL/job/devops001/build?token=TOKEN_NAME 或者 /buildWithParameters?token=TOKEN_NAME Optionally append &cause=Cause+Text to provide text that will be induded in the recorded build cause.”
选中这行复制并将token值改为刚刚设置的口令: JENKINS_URL/job/devops001/build?token=123123
然后将JENKINS_URL替换为jenkins网页端的IP和端口即http://192.168.26.31:8080/
因此完整的jenkins地址就是:http://192.168.26.31:8080/job/devops001/build?token=123123,将这个地址准备好备用
(4)因为jenkins需要从gitlab中拉取代码进行构建,在 “构建” 这项下 “增加构建步骤” 并选择 “执行shell”
在命令行输入框中输入:
(删除vms31家目录中的p1,然后重新从仓库克隆)
cd ~
rm -rf p1
git clone http://192.168.26.31/root/p1.git
(5)又因为当jenkins构建完镜像后还要推送到harbor仓库中,因此还需 “增加构建步骤”,并选中 “Build/Publish Docker Image”
在 “Directory for Dockerfile” 项目中输入:/var/jenkins_home/p1
(为镜像存储路径,这里写容器里的目录)
(6)“Cloud” 这项选中 “dokcer”
(7)要将镜像推送到harbor上,我们先来harbor网页端,进入之前创建的“cka”项目中
点击 “推送命令” 可以查看推送命令
复制“在项目中标记镜像”这项下的 “192.168.26.51/cka/”,在 “Image” 这项下配置的镜像名即以这个为前缀,镜像名为nginx,但是标签tag不能写死,因为使用变量“
B
U
I
L
D
N
U
M
B
E
R
”,完整的即为:
‘
192.168.26.51
/
c
k
a
/
n
g
i
n
x
:
{BUILD_NUMBER}”,完整的即为:`192.168.26.51/cka/nginx:
BUILDNUMBER”,完整的即为:‘192.168.26.51/cka/nginx:{BUILD_NUMBER}`
(8)勾选 “Push image”
(9)“Registry Credentials” 这下点击 “添加”,选中 “Jenkins”
在用户名密码中输入harbor的管理员用户名密码“admin/root”,点击 “添加”,添加后选中刚刚添加的用户(这里配置向harbor推送镜像时的登录用户)
(10)因为推送的镜像需要去部署并替换旧的应用,因此再次 “增加构建步骤”,选择 “执行shell”
在命令行输入框中输入:
export KUBECONFIG=/kc1
#容器名为c1,并且在命名空间ns1下
/kubectl set image deployment/web1 c1="192.168.26.31:5000/cka/nginx:${BUILD_NUMBER}" -n ns1
做完以上后点击“保存”
3.来到gitlab网页端
(1)点击上面的锁图标 “管理区域”,来到 “设置”
拉到最下面找到 “Outbound requests”,点击 “展开”,勾选 “允许钩子和服务访问本地网络”,点击 “保存修改”
(2)点击左上角 “项目——您的项目”,进到项目中
点击左边的 “设置”,点击 “集成”
在链接(URL)处填上之前准备的jenkins地址 “http://192.168.26.31:8080/job/devops001/build?token=123123”,最后点击下面的 “增加 Web 钩子” 按钮
可以在下面的 “Web 钩子” —— “Test” ——“Push events” 进行测试
整个devops框架便搭建完成了,接下来进行测试
1.来到vms31上,拉取所需的nginx镜像
docker pull nginx
2.在vms31上git clone下来的p1里,创建Dockerfile,内容如下:
cd p1/
vim Dockerfile
#插入:
FROM docker.io/nginx
MANITAINER ctyFL
ADD index.html /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
3.提交
git add .
git commit -m "测试1"
git push
4.过一会后,在harbor仓库中即可以看到刚推送的镜像
后期若有修改,重新推送后,仓库中镜像的tag同时也会递增