使用到的工具如下:
- Jenkins
- Gitee
- Docker
- DockerHub仓库
- 阿里云个人镜像仓库
本次的持续集成,使用到了两台服务器,一台安装jenkins,从码云上拉去代码进行镜像打包,在打包完成后将微服务镜像docker push到阿里云registry,有时间的同学可以自己尝试去搭建一个registry,另一台服务器我们用来进行微服务镜像的部署,运行我们的业务代码。
本次持续集成所使用到的工具统统使用docker进行安装部署。所以我们首先需要做的是在两台服务器上进行docker环境的安装。
关于docker的安装教程,网络上有很多,在这里贴出一条个人觉得写的不错的教程连接:
Centos7安装Docker_玩物丧志的快乐的博客-优快云博客
当然了,最好的教程在docker官网哈,不过有些文章可以辅助我们理解官网的操作步骤(对于像我一样英文不是特别好的朋友还是挺有帮助的)
文章中有一点补充一下,对于安装过docker的环境,最好执行一下rm -rf /var/lib/docker,将前docker操作产生的镜像、容器和其他一些文件删除,避免重新安装docker后出现一些莫名的问题。
docker安装完成后,我们就可以使用docker来安装我们需要使用到的各种工具了。
我们先来安装一下jenkins
这里选择的jenkins镜像为 jenkinsci/blueocean,是中文 jenkins 镜像,但是镜像的系统不是我们所熟悉的 centos、ubuntu、Debian 等,而是 Alpine。Alpine系统镜像存在一些小问题,后续会说到。
安装jenkins之前,我做的第一件事还是来到dockerhub官方镜像仓库,找到对应镜像的docker pull。
这里我们直接使用最新版本(真男人都用最新版本,要勇敢的做第一个吃螃蟹的人,遇到问题再去解决嘛)
拉去jenkins镜像后,我们需要使用docker run命令来运行镜像,同样,我们找到jenkins官网,点开jenkins安装教程。
我们可以看到jenkins官网对中国用户还是比较友好的,支持了中文文档。
这里的启动命令中 --rm 不建议使用哈,要不然每次想要重启镜像都得跑一遍docker run,有点太麻烦了,写道docker compose可能会好一点。
到这里我们服务器上安装jenkins的工作就完成了,是不是很简单呢。接下来我们到控制台操作一下jenkins上持续集成项目的相关配置。还是在可视化界面操作会更舒服一些。
第一次访问新的Jenkins实例时,系统会要求您使用自动生成的密码对其进行解锁。
- 浏览到 http://localhost:8080(或安装时为Jenkins配置的任何端口),并等待 解锁 Jenkins 页面出现。
密码存储目录:/jenkins/home/secrets/initialAdminPassword,其中/jenkins/home是我在docker run命令中自己定义的挂载目录,切忌直接cv,理解了再去操作才是最稳妥的。这里的挂载目录是用来在docker镜像外部操作docker镜像内部文件的方式。
因为正常情况下,我们需要修改镜像内的配置,是需要通过‘docker exec -it 容器id /bin/sh’命令进入到容器内部,才能进行修改,每次修改都进容器内部得多麻烦,所以我们一般会将docker中常用的一些数据卷挂载到宿主机的文件目录中,方便我们的操作。
完成首次登录的密码认证,接下来是自定义jenkins插件的安装,jenkins推荐了一些插件,这里我们直接点击安装,有些插件下载失败是正常情况,暂时不用管。稍后可以通过Jenkins中的Manage Jenkins > Manage Plugins 页面管理Jenkins插件。
安装完成插件后,创建一个管理员用户,创建完成后,我们就可以开始使用jenkins了。
点击新建任务,创建一条流水线
这里的jenkins配置仅配置流水线相关配置即可。
将我们的代码仓库地址配置到对应的url文本框,并新增Credentials认证方式。
这里是直接配置的Gitee账号密码。
指定分支和Jenkinsfile脚本路径后,jenkins的配置就完成了。
接下来是镜像相关的准备工作。
对于业务代码我们需要进行的操作是:
镜像构建服务器——代码拉取-> mvn编译构建代码,打成jar包->打包成微服务镜像、推送到私有仓库(阿里云个人镜像仓库)
业务运行服务器——私有仓库拉取镜像->运行镜像
以上工作都在jenkinsfile中配置完成
pipeline {
agent {
docker {
image 'registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:3-dfc'
args '-v /root/.ssh:/root/.ssh -v /dfc/maven/repository:/root/.m2/repository -v /dfc/maven/settings.xml:/usr/share/maven/ref/settings.xml'
}
}
environment {
IOMP_MICRO_APP = 'demo'
}
stages {
stage('Build') {
steps {
sh "mvn -B -DskipTests clean package jib:build"
}
}
stage('Deploy') {
steps {
sh "ssh root@121.196.151.186 'docker stop registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:0.0.1-SNAPSHOT || echo'"
sh "ssh root@121.196.151.186 'docker pull registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:0.0.1-SNAPSHOT'"
sh "ssh root@121.196.151.186 'docker rmi \$(docker images -f \"dangling=true\" -q) || echo'"
sh "ssh root@121.196.151.186 'docker run -d --network host -v $home/logs:/logs registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:0.0.1-SNAPSHOT'"
}
}
}
}
1、其中代码拉取工作由jenkins自带的git工具完成。
2、我们在maven:3-alpine镜像中进行mvn操作。因为maven:3-alpine镜像中缺少ssh相关命令,我们可以用dockerfile对maven:3-alpine镜像进行重新构建
Dockerfile文件内容:
FROM maven:3-alpine
RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \
&& apk update upgrade \
&& apk add --no-cache openssh
执行Dockerfile文件命令
docker build -f Dockerfile -t \
registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:3-dfc .
生成的registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:3-dfc镜像推送到阿里云私有仓库中。
在jenkinsfile中配置以registry.cn-hangzhou.aliyuncs.com/shen_depository/depository01:3-dfc为运行环境,对微服务代码进行编译构建。
这里有一个注意点,在agent中配置的是maven运行环境镜像,这里的images标签后配置的是maven运行环境镜像的名称,通过docker命令进行,所以我们在配置jenkins启动命令时需要需要对docker.sock文件进行挂载,否则在jenkins容器中是无法进行docker操作的。
args标签所配置的是一些数据卷的挂载,-v /root/.ssh:/root/.ssh,配置共享宿主机ssh功能,jenkinsfile文件的最后是需要ssh远程操作业务运行服务器执行镜像的拉去、运行操作的。
-v /dfc/maven/repository:/root/.m2/repository
-v /dfc/maven/settings.xml:/usr/share/maven/ref/settings.xml
挂载maven的仓库和settings文件,多个微服务项目共用一个仓库,避免jar包重复拉取。
3、打包微服务镜像的工作由jib插件完成。
Jib插件的使用关键在于from、to标签的配置,标签配置基础镜像,配置的是推送到私有仓库中的镜像名称,注意,这里如果不配置具体的镜像仓库地址,会默认去dockerhub仓库中寻找镜像。
如何触发jib插件呢?我们在jenkinsfile配置中有一行代码:
sh "mvn -B -DskipTests clean package jib:build"
-B :该参数表示让Maven使用批处理模式构建项目,能够避免一些需要人工参与交互而造成的挂起状态。
-DskipTests :跳过单元测试
jib:build,使用jib插件进行镜像构建、镜像推送。
在构建服务器上的工作到这里就完成了,接下来是业务运行服务器的工作内容。
4、ssh到远程服务器上执行docker命令
这里需要配置ssh免密登录:
一、生成密钥对:执行ssh-keygen -t rsa命令
二、把公钥分发给目标服务器
使用命令:ssh-copy-id -i /root/.ssh/id_rsa.pub root@121.196.151.186
注意:这里说明一点,如果目标服务器不存在authorized_keys的文件,那么分发服务器首次分发公钥时在目标服务器就会创建authorized_keys的文件,然后把公钥写入到authorized_keys文件,下次还有其他分发服务器做免密登录而且也是分发到相同路径下的authorized_keys文件的话,就会直接追加公钥到目标服务器上的authorized_keys文件。
三、修改 vim /etc/ssh/sshd_config文件,启用
PubkeyAuthentication yes
StrictModes yes
AuthorizedKeysFile .ssh/authorized_keys
注意:所操作的文件一定要做好赋权,如果权限不足会导致免密失败。
chattr -i authorized_keys令authorized_keys回到常态
ssh基于用户密码认证的原理
我们知道,当我们使用ssh root@192.168.1.100这样链接服务器时,如果是第一次链接服务器,会弹出一串英文询问你,并要求你输入密码,那么这个过程ssh链接的原理是什么呢?下面就来简单讲解一个ssh基于用户密码认证的原理。
1、ssh客户端第一次向ssh服务端发起一个ssh链接登录请求,如:A服务器请求ssh链接登录B服务器,ssh root@192.168.1.100,这时ssh客户端会提示一串英文,大概意思就是说无法确定你所链接的服务器的真实性,是否需要继续,输入: yes
2、ssh客户端输入yes之后,ssh服务端开始向ssh客户端发送公钥/etc/ssh/ssh_host_rsa_key.pub文件;
3、ssh客户端接受公钥,此时ssh客户端输入密码,并使用公钥对密码进行加密后发送给ssh服务端;
4、ssh服务端接受来之ssh客户端的加密后的密码,使用自己的/etc/ssh/ssh_host_rsa_key 私钥进行解密,解密认证通过后,登录链接建立完成;
5、ssh客户端自己留存一份ssh服务端主机的信息,位于~/.ssh/known_hosts文件中,下次再次链接ssh服务端主机不在弹出英文询问语句。
ssh免密登录的原理
1、A主机生成一对秘钥(私钥和公钥);
2、把A主机的公钥拷贝一份到B主机然后把其内容追加到B主机的/root/.ssh/authorized_keys文件上(B主机的sshd服务配置文件要事先启用秘钥验证登录功能);
3、A主机向B主机发起ssh 登录请求;
4、B主机收到请求后进行公钥对比,判断A主机的公钥是否已经存储在authorized_keys文件中,如果存在并正确,则随机生成一个字符串,然后使用A主机的公钥对字符串进行加密,得到加密后的字符串。
5、B主机把加密后的字符串发送给A主机,这加密后的字符串相当于口令;
6、A主机接受到加密的字符串后使用自己的私钥进行解密,解密后的字符串发送回给B主机;
7、B主机接收解密后的字符串,认证与自己最初生成的字符串一致,返回登录结果给A主机;
8、A主机接收登录结果,结果是成功则登录成功,结果是失败则登录失败。
配置完成后,在jenkins流水线上点击立即构建,完成构建。
至此jenkins持续集成配置完成。
菜鸡的学习笔记,如果有讲的不对的地方,还望各位大佬指正。