Jenkins持续集成

第一章 DevOps概念

一、什么是DevOps

DevOps是一种思想或方法论,它涵盖开发、测试、运维的整个过程(不仅限于Java)。DevOps强调软件开发人员与软件测试、软件运维、质量保障(QA)部门之间有效的沟通与协作。强调通过自动化的方法管理软件变更、软件集成。使软件从构建到测试、发布更加快捷、可靠,最终按时交付软件。

DevOps

二、为什么当今大公司一定要使用DevOps

2.1 传统瀑布模型
  • 完整、清晰、固定的需求
  • 完整、清晰、固定的产品定义
2.2 敏捷开发模型
  • 需求频繁变化
  • 需要快速开发
2.3 DevOps开发模型
  • 需求频繁变化
  • 开发需要敏捷
  • 操作需要敏捷

DevOps这种软件开发方法,涉及到软件整个开发生命周期,这些活动只能在DevOps中实现,而不是敏捷或瀑布。DevOps是在较短的开发周期内开发高质量软件的首选方法,同时可以提高客户满意度。这就是为什么顶级互联网公司选择DevOps作为其业务目标的前进方向。

三、如何落地实现DevOps这种理念

DevOps兴起于2009年,近年来由于云计算、互联网的发展,促进了DevOps的基础设施及工具的发展,涌现出了一大批优秀的工具,这些工具包括开发、测试、运维的各个领域,例如:GitHub、Git\SVN、Docker、Jenkins、Hudson、Ant\Maven\Gradle、Selenium、QUnit、JMeter等等。下图是DevOps相关的工具集

DevOps相关的工具集

四、Docker一把瑞士军刀,让DevOps真正落地于实践

Docker是一个开源的应用容器引擎,诞生于2013年初,基于Go语言开发,dotCloud公司出品(后改名为Docker Inc)。

Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上。容器是完全使用沙箱机制,相互隔离。容器性能开销极低。

Docker从17.03版本之后分为CE(Community Edition,社区版)和EE(Enterprise Edition,企业版)。

  • 镜像(Image): Docker镜像(Image),就相当于是一个root文件系统,比如官方镜像Ubuntu:16.04就包含了完整的一套Ubuntu16.04最小系统的root文件系统。

  • 容器(Container): 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和对象一样,镜像是静态的定义,容器是镜像运行时的实体,容器可以被创建、启动、停止、删除、暂停等。

  • 仓库(Repository): 仓库可以看成一个代码控制中心,用来保存镜像。

五、持续集成流程

持续集成流程

第二章 DevOps实践

一、DevOps基础环境安装

1.1 使用系统说明
  • 远程服务器:阿里云ECS,2核16G,Ubuntu 18.04.64位 (服务器配置最少2核8G起步),IP地址120.24.95.76

  • 阿里云ECS安全组开放端口:500060016002600380808001

  • 本地电脑:Mac OS

1.2 安装Git
1.2.1 ssh登录ECS
AC-2:~ AC$ ssh [email protected]
[email protected]'s password: 

# 按提示输入密码进行登录
1.2.2 安装Git

更新服务器上的包索引

sudo apt-get update

安装git

sudo apt-get install git
1.2.3 配置Git全局环境
git config --global user.name "alanchen"

git config --global user.email "[email protected]"
1.2.4 生成ssh密钥
ssh-keygen -t rsa -C "[email protected]"
1.2.5 查看拷贝公钥

如果后面需要在GitLab配置SSH Keys时,可以从这里拷贝公钥,当然也可以用账号密码进行操作

cd ~/.ssh
cat id_rsa.pub
1.3 安装Maven
1.3.1 安装步骤

1、首先检查是否有maven

mvn -v

2、search

apt-cache search maven

3、安装

sudo apt-get install maven

4、检查是否安装成功

mvn -v

安装成功会显示版本号

root@iZwz96ew7wfkgebgbq9crbZ:~# mvn -v
Apache Maven 3.6.0
Maven home: /usr/share/maven
Java version: 11.0.13, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-166-generic", arch: "amd64", family: "unix"
root@iZwz96ew7wfkgebgbq9crbZ:~#
1.3.2 配置maven国内镜像,提高下载速度

1、找到配置文件settings.xml位置
通过mvn -v可以显示maven的安装目录,在安装目录下就有settings.xml配置文件。

cd /usr/share/maven/conf

2、编辑settings.xml配置文件

vi settings.xml

3、修改settings.xml配置文件
找到标签,在这个标签中加入国内的镜像即可,这里我推荐maven阿里云中央仓库。



  
      alimaven
      aliyun maven
      http://maven.aliyun.com/nexus/content/groups/public/
      central        
    


加入国内镜像
1.4 安装Docker
1.4.1 安装

使用官方安装脚本自动安装,安装命令如下:

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

也可以使用国内 daocloud 一键安装命令:

curl -sSL https://get.daocloud.io/docker | sh
1.4.2 配置镜像加速器(非必要)
容器镜像服务

二、安装Docker私有仓库

2.1 安装步骤

1、搜索镜像

docker search registry

2、拉取镜像

docker pull registry

3、创建容器

#创建存放镜像的目录

mkdir -p /opt/data/docker/  
#创建容器 -p指定端口 -v数据卷挂载

docker run -it -d -p 5000:5000 -v /opt/data/docker:/tmp/registry registry

ECS安全组需要开放5000端口

2.2 配置私有仓库地址
vi /etc/docker/deamon.json

配置内容

{
  “insecure-registries”:[“120.24.95.76:5000”]
}
配置内容
2.3 重启

1、重启配置

sudo systemctl daemon-reload

2、重启Docker

sudo systemctl restart docker

3、查看仓库容器状态

docker ps -a

仓库容器当前为退出状态

root@iZwz96ew7wfkgebgbq9crbZ:/usr/share/maven/conf# docker ps -a
CONTAINER ID   IMAGE      COMMAND                  CREATED         STATUS         PORTS                                       NAMES
22db63715a88   registry   "/entrypoint.sh /etc…"   4 minutes ago   Up 4 minutes   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   thirsty_euclid
root@iZwz96ew7wfkgebgbq9crbZ:/usr/share/maven/conf# 

4、启动本地仓库容器

docker start 22db63715a88

启动

root@iZwz96ew7wfkgebgbq9crbZ:/usr/share/maven/conf# docker start 22db63715a88
22db63715a88
root@iZwz96ew7wfkgebgbq9crbZ:/usr/share/maven/conf#
2.4 访问Docker私有仓库

在浏览器中访问http://120.24.95.76:5000/v2/_catalog

访问结果

三、安装GitLab

下面将通过Docker安装GitLab,如果在ECS宿主机上直接安装GitLab,可参考我另外一篇文章 Ubuntu部署GitLab

3.1 Docker安装GitLab步骤

1、查找GitLab镜像

docker search gitlab

2、拉取GitLab镜像

docker pull gitlab/gitlab-ce

3、查看本地镜像

docker images
root@iZwz96ew7wfkgebgbq9crbZ:/usr/share/maven/conf# docker images
REPOSITORY         TAG       IMAGE ID       CREATED        SIZE
gitlab/gitlab-ce   latest    508bfaaaf273   4 days ago     2.36GB
registry           latest    b8604a3fe854   2 months ago   26.2MB
root@iZwz96ew7wfkgebgbq9crbZ:/usr/share/maven/conf# 

4、建立映射文件
在本机建立3个目录,分别为:配置文件、数据文件、日志文件。GitLab容器通过挂载本机目录启动后就可以映射到本机。主要出于以下两点原因:
1、后续可以直接在本机查看和编辑,不用再进入容器操作。
2、容器是一个虚拟化的技术,容器挂了之后,容器里的数据就没了,数据不安全

创建文件:

# 配置文件
mkdir -p /home/gitlab/etc

# 数据文件
mkdir -p /home/gitlab/data

# 日志文件
mkdir -p /home/gitlab/logs

5、启动容器

docker run --name='gitlab' -d \
--publish 6002:443  --publish 6001:80 --publish 6003:22 \
-v /home/gitlab/etc:/etc/gitlab \
-v /home/gitlab/data:/var/opt/gitlab \
-v /home/gitlab/logs:/var/log/gitlab \
gitlab/gitlab-ce:latest

https443端口用6002端口映射,web访问端口80用6001端口映射(GitLab默认用的是80端口),ssh端口22用6003端口映射。(备注ECS阿里云要开放6001、6002、6003端口)

root@iZ0jldusfvkkz0zfl9gsdaZ:/home/gitlab/etc# docker run --name='gitlab' -d \
> --publish 6002:443  --publish 6001:80 --publish 6003:22 \
> -v /home/gitlab/etc:/etc/gitlab \
> -v /home/gitlab/data:/var/opt/gitlab \
> -v /home/gitlab/logs:/var/log/gitlab \
> gitlab/gitlab-ce:latest
56a55cb01c9df7c9a5bee514b04adf131b158ae83c44fedf9570c469a6328f75

可以通过docker logs -f gitlab 命令查看启动日志,通过docker ps -a 查看容器启动状态。

root@iZwz96ew7wfkgebgbq9crbZ:~# docker ps -a
CONTAINER ID   IMAGE                     COMMAND                  CREATED         STATUS                            PORTS                                                                                                                   NAMES
02bde20ab6df   gitlab/gitlab-ce:latest   "/assets/wrapper"        2 minutes ago   Up 2 minutes (health: starting)   0.0.0.0:6003->22/tcp, :::6003->22/tcp, 0.0.0.0:6001->80/tcp, :::6001->80/tcp, 0.0.0.0:6002->443/tcp, :::6002->443/tcp   gitlab
22db63715a88   registry                  "/entrypoint.sh /etc…"   5 hours ago     Up 5 hours                        0.0.0.0:5000->5000/tcp, :::5000->5000/tcp                                                                               thirsty_euclid
root@iZwz96ew7wfkgebgbq9crbZ:~# 

状态为health: starting表示还在启动中。

6、访问GitLab
http://120.24.95.76:6001

成功访问GitLab
3.2 修改root默认密码
3.2.1 查看容器,GitLab是否正常运行
docker ps -a

Up为启动状态

root@iZwz96ew7wfkgebgbq9crbZ:~# docker ps -a
CONTAINER ID   IMAGE                     COMMAND                  CREATED         STATUS                   PORTS                                                                                                                   NAMES
02bde20ab6df   gitlab/gitlab-ce:latest   "/assets/wrapper"        6 minutes ago   Up 6 minutes (healthy)   0.0.0.0:6003->22/tcp, :::6003->22/tcp, 0.0.0.0:6001->80/tcp, :::6001->80/tcp, 0.0.0.0:6002->443/tcp, :::6002->443/tcp   gitlab
22db63715a88   registry                  "/entrypoint.sh /etc…"   5 hours ago     Up 5 hours               0.0.0.0:5000->5000/tcp, :::5000->5000/tcp                                                                               thirsty_euclid
root@iZwz96ew7wfkgebgbq9crbZ:~# 

3.2.2 进入GitLab的容器中
# docker exec -it(gitlab的容器名称或id) bash

docker exec -it 63cc520288bd bash

// 或者
docker exec -it gitlab bash
root@iZwz96ew7wfkgebgbq9crbZ:~# docker exec -it gitlab bash
root@02bde20ab6df:/# 

3.2.3 修改密码

1、使用以下命令启动Ruby on Rails控制台

gitlab-rails console

2、等待控制台加载完毕并找到root用户,稍微要多等待一会

user = User.where(id: 1).first

或者

user = User.find_by(email: '[email protected]')

3、更改密码

user.password='123456abc'

user.password_confirmation='123456abc'

4、保存更改

user.save

操作过程:

root@iZwz96ew7wfkgebgbq9crbZ:~# docker exec -it gitlab bash
root@02bde20ab6df:/# gitlab-rails console
--------------------------------------------------------------------------------
 Ruby:         ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-linux]
 GitLab:       14.6.2 (0a901d60f8a) FOSS
 GitLab Shell: 13.22.1
 PostgreSQL:   12.7
--------------------------------------------------------------------------------
Loading production environment (Rails 6.1.4.1)
irb(main):001:0> user = User.where(id: 1).first
=> #
irb(main):002:0> user = User.find_by(email: '[email protected]')
=> #
irb(main):003:0> user.password='123456abc'
=> "123456abc"
irb(main):004:0> user.password_confirmation='123456abc'
=> "123456abc"
irb(main):005:0> user.save
=> true
irb(main):006:0> 

5、用root账号以及刚设置的密码登录GitLab


登录GitLab

6、登录成功


登录成功
3.3 配置

按上面的方式,GitLab容器运行没问题,但在GitLab上创建项目的时候,生成项目的URL访问地址是按容器的hostname来生成的,也就是容器id(如:http://02bde20ab6df/root/test.git)。作为GitLab服务器,我们需要一个固定的URL访问地址,于是需要配置gitlab.rb(宿主机路径:/home/gitlab/comfig/gitlab.rb

访问地址为容器id
3.3.1 配置gitlab.rb
cd /home/gitlab/etc

vi gitlab.rb

可以使用/来查找关键字,找到指定的内容,然后通过n来下一个查找,编辑内容:

# 在GitLab创建项目时候http地址的host(如果不加端口,端口默认为80)
external_url 'http://120.24.95.76:6001'

# 在GitLab创建项目时候ssh地址的host(不用添加端口,不用加http)
gitlab_rails['gitlab_ssh_host'] = '120.24.95.76'

# Docker run 的时候我们把22端口映射为外部的6003了,这里修改下
gitlab_rails['gitlab_shell_ssh_port'] = 6003
改配置

跳坑重点强调:

  • 22端口映射问题:如果不映射22端口,ssh克隆时一直提示输入密码,且密码错误。ssh传输都是通过22端口传输的,一般被宿主的sshd服务占用。所以GitLab容器的22端口不能直接映射到宿主的22端口,要换个其他端口,比如6003。这样,通过端口映射,客户端的ssh传输请求就能达到容器中的GitLab服务。

  • external_url默认为80端口问题:请注意,我上面的配置external_url是有写端口号6001的,如果不写,则默认为80端口。此处有两个坑:

第一个坑:如果external_url不写端口6001,而用默认的80端口,那项目的Clone with HTTP地址也是不带端口的(默认为80端口),由于80端口的原因,我们在git clone http 地址时会clone失败。即使在下面要修改的gitlab.yml文件里,将port端口设置为6001,保存退出,当容器一启动再来看该文件内容,port又会变成默认的80端口。

第二个坑:如果external_url写了端口6001,重启配置,容器也能正常重启成功,但GitLab却访问不了了。问题的原因就出在external_url地址设置上。
GitLab默认的http访问端口号为80端口,如果想更改端口号,一般是通过docker run时设置端口映射,将80端口映射为其他端口。例如前面的操作:

docker run --name='gitlab' -d \
--publish 6002:443  --publish 6001:80 --publish 6003:22 \
-v /home/gitlab/etc:/etc/gitlab \
-v /home/gitlab/data:/var/opt/gitlab \
-v /home/gitlab/logs:/var/log/gitlab \
gitlab/gitlab-ce:latest

这里将GitLab的http端口改为6001,如果你这时修改external_url地址为http://ip:6001,那GitLab肯定访问不了,因为你已经将内部的端口号修改为6001端口了,而你通过docker run映射出来的端口号是80端口,所以不可能访问到。那该怎么办?既然你已经将内部的端口号由80端口改为6001端口,这时候你就将容器停止并删除,启动容器时,将端口由80改成6001

docker run --name='gitlab' -d \
--publish 6002:443  --publish 6001:6001 --publish 6003:22 \
-v /home/gitlab/etc:/etc/gitlab \
-v /home/gitlab/data:/var/opt/gitlab \
-v /home/gitlab/logs:/var/log/gitlab \
gitlab/gitlab-ce:latest
3.3.2 配置gitlab.yml
cd /home/gitlab/data/gitlab-rails/etc

vi gitlab.yml
  gitlab:
    ## Web server settings (note: host is the FQDN, do not include http://)
    host: 120.24.95.76
    port: 6001
    https: false
旧的内容
修改后的内容
3.3.3 停用GitLab容器
docker stop gitlab
3.3.4 删除GitLab容器
docker rm -f gitlab

# 或者通过id删除
docker rm -f 0535d33bf034
3.3.5 启动GitLab容器
docker run --name='gitlab' -d \
--publish 6002:443  --publish 6001:6001 --publish 6003:22 \
-v /home/gitlab/etc:/etc/gitlab \
-v /home/gitlab/data:/var/opt/gitlab \
-v /home/gitlab/logs:/var/log/gitlab \
gitlab/gitlab-ce:latest

注意:两个端口都是6001

3.4 登录GitLab创建devops项目

http://120.24.95.76:6001

创建项目
创建项目

我们可以看到项目的访问地址为IP,不是容器ID了,SSH地址后面是6003端口,HTTP地址后面是6001端口。

项目地址
3.5 GitLab创建用户
Admin管理
用户列表
创建账号
修改密码
3.6 项目授权

devops项目授权给chenyan用户

项目用户管理
邀请用户加入项目

chenyan账号登录GitLab,即可以看到devops项目

chenyan账号登录
devops项目
3.7 GitLab配置SSH Keys

chenyan用户配置SSH Keys

3.7.1 配置Git全局环境

在本地电脑操作

git config --global user.name "chenyan"

git config --global user.email "[email protected]"
3.7.2 生成ssh密钥
ssh-keygen -t rsa -C "[email protected]"
3.7.3 拷贝公钥
cd ~/.ssh
cat id_rsa.pub
AC-2:~ AC$ cd ~/.ssh
AC-2:.ssh AC$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2kYvXyZRehV65k96uuVlfCxbQrlCTTtdYdSOm8ZOeywo6+vqWpQjVyDobeQKANOswOr09YR8UwRd5VjssLI7dh4SHuvvZpgWaPGZf1HxT9N5ssIUNTKLe36O5QXeQQ41wTF6nNRoFkWbErzzw+DqUTBYvVJGVpfrJMO4V/SFZk4WceQT1zJ2E3lBI6hjbtuIgGSqYK6trutuCnEw+DW7zkrTxzKQqVzB1h1m0dTpqT+rwl3j16avmyiKFWfL1uMvGJfeTP7XNEsTaQXo0eseByVxI8NNPguPihGPp0Rt7Bx7SUFam+2zhg6LdMqXwPiXft8DPI8YiC0zHvKpYC5fB [email protected]
AC-2:.ssh AC$ 
3.7.4 配置SSH Keys

chenyan账号登录GitLab

设置
配置SSH Keys
3.7.5 拉取项目到本地

进入本地电脑code,用来存放devops项目

cd ~/code/

1、通过SSH方式clone代码

git clone ssh://[email protected]:6003/root/devops.git
AC-2:.ssh AC$ cd ~/code/
AC-2:code AC$ git clone ssh://[email protected]:6003/root/devops.git
Cloning into 'devops'...
The authenticity of host '[120.24.95.76]:6003 ([120.24.95.76]:6003)' can't be established.
ECDSA key fingerprint is SHA256:iwQBJ3+2tzc3oM1K4l8qaLg5Nl6UtM0EM8fXiNhpyyU.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[120.24.95.76]:6003' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
AC-2:code AC$ 

2、或者可以通过HTTP输入账号密码的方式clone代码
先将刚clone的代码删除

git clone http://120.24.95.76:6001/root/devops.git
AC-2:code AC$ git clone http://120.24.95.76:6001/root/devops.git
Cloning into 'devops'...
Username for 'http://120.24.95.76:6001': chenyan
Password for 'http://[email protected]:6001': 
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
AC-2:code AC$ 

四、编写devops项目代码并提交到远程仓库

4.1 创建SpringBoot项目devops
创建项目
创建项目

设置项目名称


项目名称

添加Spring Web依赖


加依赖

覆盖刚刚clone的项目目录


项目存放目录
4.2 编写restful接口

编写controller代码

@RestController
@RequestMapping("devops")
public class DevOpsController {

    @GetMapping("hello")
    public String hello(){
        return "AlanChen";
    }
}
项目截图

自动生成的pom.xml文件为



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.2
         
    
    com.alanchen
    devops
    0.0.1-SNAPSHOT
    devops
    Demo project for DevOps
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    



访问controller服务接口
http://127.0.0.1:8080/devops/hello

访问hello接口
4.3 将本地的devops项目代码提交到远程仓库
cd ~/code/devops

git add .

git commit -m "add hello"

git push
4.4 登录GitLab查看项目情况
刚提交的代码

五、Docker制作SpringBoot项目工程镜像容器

5.1 打包devops项目为jar
打包
jar文件
5.2 将jar包上传到阿里云ECS服务器

先在ECS服务器上,建立/data/docker-demo目录

mkdir -p /data/devops-demo

上传jar文件

scp /Users/AC/code/devops/target/devops-0.0.1-SNAPSHOT.jar [email protected]:/data/devops-demo/devops-0.0.1-SNAPSHOT.jar

5.3 编写Dockerfile文件

阿里云ECS,进入/data/devops-demo目录,编写Dockerfile文件

cd /data/devops-demo
vi Dockerfile

文件内容

# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER eangulee [email protected]
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp 
# 将jar包添加到容器中并更名为app.jar
ADD *.jar app.jar 
# 运行jar包
RUN bash -c 'touch /app.jar'
#指定容器启动时要执行的命令,但如果存在CMD指令,CMD中的参数会被附加到ENTRYPOINT指令的后面
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

VOLUME指定了临时文件目录为/tmp。其效果是在主机/var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp。该步骤是可选的,如果涉及到文件系统的应用就很有必要了。/tmp目录用来持久化到Docker数据文件夹,因为Spring Boot使用的内嵌 Tomcat 容器默认使用/tmp作为工作目录项目的 jar 文件作为 app.jar添加到容器的ENTRYPOINT执行项目app.jar。为了缩短Tomcat启动时间,添加一个系统属性指向/dev/./urandom作为Entropy Source。如果是第一次打包,它会自动下载Java 8的镜像作为基础镜像,以后再制作镜像的时候就不会再下载了。

/data/devops-demo目录文件如下

root@iZwz9doa4kcnsjcv8fgt8pZ:/data/devops-demo# ls
devops-0.0.1-SNAPSHOT.jar  Dockerfile
root@iZwz9doa4kcnsjcv8fgt8pZ:/data/devops-demo# 
5.4 制作镜像

/data/devops-demo目录下执行命令,-t 参数是指定此镜像的tag名

docker build -t devopsdemo .

注意:最后有一个点.

执行过程

root@iZwz9doa4kcnsjcv8fgt8pZ:/data/devops-demo# docker build -t devopsdemo .
Sending build context to Docker daemon  17.56MB
Step 1/6 : FROM java:8
8: Pulling from library/java
5040bd298390: Pull complete 
fce5728aad85: Pull complete 
76610ec20bf5: Pull complete 
60170fec2151: Pull complete 
e98f73de8f0d: Pull complete 
11f7af24ed9c: Pull complete 
49e2d6393f32: Pull complete 
bb9cdec9c7f3: Pull complete 
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:8
 ---> d23bdf5b1b1b
Step 2/6 : MAINTAINER eangulee [email protected]
 ---> Running in 614c9c58a554
Removing intermediate container 614c9c58a554
 ---> ec0fb00f60c5
Step 3/6 : VOLUME /tmp
 ---> Running in 6bc1644cad98
Removing intermediate container 6bc1644cad98
 ---> a808a7c8ff24
Step 4/6 : ADD *.jar app.jar
 ---> 92fa72757b8c
Step 5/6 : RUN bash -c 'touch /app.jar'
 ---> Running in 17dbf2e59690
Removing intermediate container 17dbf2e59690
 ---> 2929030bfdb3
Step 6/6 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
 ---> Running in 5cdb4c0029ec
Removing intermediate container 5cdb4c0029ec
 ---> f2149993ff24
Successfully built f2149993ff24
Successfully tagged devopsdemo:latest
root@iZwz9doa4kcnsjcv8fgt8pZ:/data/devops-demo# 

制作完成后通过docker images命令查看我们制作的镜像

root@iZwz9doa4kcnsjcv8fgt8pZ:/data/devops-demo# docker images
REPOSITORY         TAG       IMAGE ID       CREATED              SIZE
devopsdemo         latest    f2149993ff24   About a minute ago   678MB
gitlab/gitlab-ce   latest    508bfaaaf273   4 days ago           2.36GB
registry           latest    b8604a3fe854   2 months ago         26.2MB
java               8         d23bdf5b1b1b   4 years ago          643MB
root@iZwz9doa4kcnsjcv8fgt8pZ:/data/devops-demo# 
5.5 启动容器
docker run -d -p 8001:8080 devopsdemo

-d参数是让容器后台运行
-p 是做端口映射,此时将服务器中的8001端口映射到容器中的8080端口(项目中端口默认是8080)。

注意:阿里云ECS要开放8001端口

5.6 验证

在浏览器中访问http://120.24.95.76:8001/devops/hello,如果能访问到hello接口,表示Dcoker部署SpringBoot项目成功。

六、使用maven构建镜像

上边构建的过程是通过手工一步一步完成,maven提供docker-maven-plugin插件可以完成从打包到构建镜像、构建容器等过程。

更多信息,请参考:docker-maven-plugin官方地址

6.1 编写pom_docker.xml

1、创建pom_docker.xml文件
2、将项目中pom.xml文件的内容全部复制到pom_docker.xml文件中
3、在pom_docker.xml文件中加入docker-maven-plugin插件内容

        
                com.spotify
                docker-maven-plugin
                1.2.2

                
                
                    
                    ${project.artifactId}
                    

                    
                    ${project.basedir}/src/main/resources
                    

                    
                    
                        ${project.version}
                    

                    
                    
                        
                            /
                            ${project.build.directory}
                            ${project.artifactId}-${project.version}.jar
                        
                    
                
            

pom_docker.xml文件全部内容如下



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.2
         
    
    com.alanchen
    devops
    0.0.1-SNAPSHOT
    devops
    Demo project for DevOps
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

            
                com.spotify
                docker-maven-plugin
                1.2.2

                
                
                    
                    ${project.artifactId}
                    

                    
                    ${project.basedir}/src/main/resources
                    

                    
                    
                        ${project.version}
                    

                    
                    
                        
                            /
                            ${project.build.directory}
                            ${project.artifactId}-${project.version}.jar
                        
                    
                
            

        
    




6.2 编写Dockerfile文件

在工程的resources目录下新建Dockerfile文件,文件内容和上面的Dockerfile文件内容一样。

# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER eangulee [email protected]
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp 
# 将jar包添加到容器中并更名为app.jar
ADD *.jar app.jar 
# 运行jar包
RUN bash -c 'touch /app.jar'
#指定容器启动时要执行的命令,但如果存在CMD指令,CMD中的参数会被附加到ENTRYPOINT指令的后面
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

项目目录如下

项目目录
6.3 提交代码

将本地项目devops编辑的代码全部都提交到远程GitLab仓库。

6.4连接登录阿里云ECS宿主机
AC-2:devops AC$ ssh [email protected]

# 按提示输入密码登录
6.5 拉取devops项目代码

1、进入目录

cd /data/devops-demo

2、clone代码

git clone http://120.24.95.76:6001/root/devops.git
root@iZwz96ew7wfkgebgbq9crbZ:/data/devops-demo# ls
devops
root@iZwz96ew7wfkgebgbq9crbZ:/data/devops-demo#

3、进入工程目录

cd devops

4、打包构建镜像

mvn -f pom_docker.xml clean package -DskipTests docker:build

打包过程会去下载依赖包,如果下载速度慢,可以将下载镜像地址改成国内地址。

成功构建结果如下:

 ---> Running in 0e76046ca6e7
Removing intermediate container 0e76046ca6e7
 ---> 6b505550ff52
Step 6/6 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

 ---> Running in 1bd9886f3c3a
Removing intermediate container 1bd9886f3c3a
 ---> ce9d7605919b
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built ce9d7605919b
Successfully tagged devops:latest
[INFO] Built devops
[INFO] Tagging devops with 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  04:38 min
[INFO] Finished at: 2022-01-16T16:37:09+08:00
[INFO] ------------------------------------------------------------------------
root@iZwz96ew7wfkgebgbq9crbZ:/data/devops-demo/devops#

5、制作完成后通过docker images命令查看我们制作的镜像

docker images 
root@iZwz96ew7wfkgebgbq9crbZ:/data/devops-demo/devops# docker images 
REPOSITORY         TAG              IMAGE ID       CREATED          SIZE
devops             0.0.1-SNAPSHOT   ce9d7605919b   38 seconds ago   678MB
devops             latest           ce9d7605919b   38 seconds ago   678MB
gitlab/gitlab-ce   latest           508bfaaaf273   4 days ago       2.36GB
registry           latest           b8604a3fe854   2 months ago     26.2MB
java               8                d23bdf5b1b1b   5 years ago      643MB
root@iZwz96ew7wfkgebgbq9crbZ:/data/devops-demo/devops# 

5、创建启动容器

docker run -d -p 8002:8080 devops:0.0.1-SNAPSHOT

备注:阿里云ECS安全组要开放8002端口。

6、验证
在浏览器中访问http://120.24.95.76:8002/devops/hello,如果能访问到hello接口,表示maven构建镜像启动容器成功。

成功

七、ECS宿主机安装Jenkins

安装步骤可参考我另外一篇文章Ubuntu安装Jenkins

八、Jenkins持续集成

目标:通过Jenkins持续集成,git提交代码后,自动编译打包发布程序。

8.1 使用dockerfile-maven-plugin插件

在上面介绍了使用Spotify公司开发的docker-maven-plugin插件来构建Docker镜像。然而在如下所示官方申明中,Spotify官方已经不再推荐使用该插件:

docker-maven-plugin

上面说明了不再推荐使用该插件的原因,转而推荐了另外一款由该公司开发的Maven插件dockerfile-maven-plugin。下面我们使用dockerfile-maven-plugin插件来构建Docke镜像

8.1.1 编写pom_docker_registry.xml文件

在devops工程目录下编写pom_docker_registry.xml文件。

1、创建pom_docker_registry文件

2、将项目中pom_docker.xml文件的内容全部复制到
pom_docker_registry.xml文件中

3、在pom_docker_registry.xml文件中更改plugins标签内的内容

          
            
                org.springframework.boot
                spring-boot-maven-plugin
            

            
                com.spotify
                dockerfile-maven-plugin
                1.4.13

                
                    
                        default
                        
                            build
                            push
                        
                    
                

                
                
                    120.24.95.76:5000/${project.artifactId}
                    ${project.version}
                    
                        ${project.build.finalName}.jar
                    
                
            
        

pom_docker_registry.xml文件全部内容如下



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.2
         
    
    com.alanchen
    devops
    0.0.1-SNAPSHOT
    devops
    Demo project for DevOps
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

            
                com.spotify
                dockerfile-maven-plugin
                1.4.13

                
                    
                        default
                        
                            build
                            push
                        
                    
                

                
                
                    120.24.95.76:5000/${project.artifactId}
                    ${project.version}
                    
                        ${project.build.finalName}.jar
                    
                
            
        
    



可以看到,该插件的配置比docker-maven-plugin更简单了。repository指定docker镜像的repo名字。tag指定docker镜像的tag。buildArgs可以指定一个或多个变量,传递给Dockerfile,在Dockerfile中通过ARG指令进行引用。

另外,可以在execution中同时指定build和push目标。当运行mvn package时,会自动执行build目标,构建Docker镜像。当运行mvn deploy命令时,会自动执行push目标,将Docker镜像push到Docker仓库。

4、增加Dockerfile文件
在项目根目录(和pom文件在同一级)新建一个Dokerfile文件,文件内容如下:

# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER eangulee [email protected]
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为app.jar
ARG JAR_FILE
ADD target/${JAR_FILE} /app.jar
# 运行jar包
RUN bash -c 'touch /app.jar'
#指定容器启动时要执行的命令,但如果存在CMD指令,CMD中的参数会被附加到ENTRYPOINT指令的后面
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

5、项目目录如下


项目目录

6、提交代码
将本地项目devops编辑的代码全部都提交到远程GitLab仓库。

8.1.2 修改maven setting.xml配置

先找到配置文件settings.xml位置,通过mvn -v可以显示maven的安装目录,在安装目录下就有settings.xml配置文件。在pluginGroups中增加一个com.spotify

vi /usr/share/maven/conf/settings.xml
setting.xml配置
8.2 Jenkins集成
8.2.1 Jenkins创建持续集成任务
新建Item
创建任务
描述
配置git地址,添加凭证
配置凭证账号密码
选择凭证、修改分支
shell构建步骤

填入shell脚本内容

#!/bin/bash
result=$(docker ps | grep "120.24.95.76:5000/devops")
# -n 表示:result字符串长度大于0,注意[[ ]]内部两边有空格
if [[ -n "$result" ]]
then
echo "stop devops"
docker stop devops
fi
result1=$(docker ps -a | grep "120.24.95.76:5000/devops")
if [[ -n "$result1" ]]
then
echo "rm devops"
docker rm devops
fi
result2=$(docker images | grep "1120.24.95.76:5000/devops")
if [[ -n "$result2" ]]
then
echo "120.24.95.76:5000/devops:0.0.1-SNAPSHOT"
docker rmi 120.24.95.76:5000/devops:0.0.1-SNAPSHOT
fi
shell脚本内容
maven构建

执行maven构建

clean package -f pom_docker_registry.xml -DskipTests dockerfile:build
maven脚本命令

拉取镜像,创建容器,启动容器


shell

shell命令

docker run --name devops -p 8002:8080 -idt 120.24.95.76:5000/devops:0.0.1-SNAPSHOT
shell命令

配置完了,点击保存


保存配置

点击保存按钮后的界面


点击保存按钮后的界面
8.2.2 手动构建
手动构建
8.2.3 构建成功

1、显示构建成功


构建成功

2、访问docker私有仓库http://120.24.95.76:5000/v2/_catalog,显示了devops

image.png
8.2.4 构建失败情况
8.2.4.1 构建失败情况一

问题描述:在shell脚本运行docker报权限问题,错误信息如下

Got permission denied while trying to connect to the Docker daemon socket at unix

解决方法:将Jenkins用户加入docker组,重启Jenkins服务

sudo gpasswd -a jenkins docker
sudo service jenkins restart
8.2.4.2 构建失败情况二

问题描述:镜像推送时出现 server gave HTTP response to HTTPS client 问题

[�[1;31mERROR�[m] Failed to execute goal �[32mcom.spotify:docker-maven-plugin:1.2.2:build�[m �[1m(default-cli)�[m on project

[36mdevops�[m: �[1;31mException caught�[m: Get "https://120.24.95.76:5000/v2/": http: server gave HTTP response to HTTPS client

原因分析:因为 Docker引擎默认通过 https 协议与 Docker Registry 通信,所以如果搭建的Docker 私有镜像库是 http 协议的话,就会输出上述日志。

解决方法:
情况1.这种写法是没有配置Docker加速器的情况下,在 /etc/docker/daemon.json中设置以下

// 没有配置加速器的

// 单个私服的写法
{
    "insecure-registries": ["registry的IP地址:端口号"]
}
// 多个私服的写法
{
    "insecure-registries": ["registry1的IP地址:端口号","registry2的IP地址:端口号"]
}

情况2.这种写法是配置过Docker加速器的情况下,在 /etc/docker/daemon.json 中设置以下:

// 没有配置加速器的

// 单个私服的写法
{
    "registry-mirrors": ["http://f1361db2.m.daocloud.io"],
    "insecure-registries": ["registry的IP地址:端口号"]
}
// 多个私服的写法
{
    "registry-mirrors": ["http://f1361db2.m.daocloud.io"],
    "insecure-registries": ["registry1的IP地址:端口号","registry2的IP地址:端口号"]
}

我的配置为:

{"insecure-registries":["120.24.95.76:5000"]}

以上配置完成以后使用命令

systemctl daemon-reload
systemctl restart docker.service
systemctl enable docker.service

注意:执行完上面命令后,需要去重新启动gitlab、docker私有仓库服务。

8.2.4.3 构建失败情况三

构建失败错误信息

docker: Error response from daemon: Conflict. The container name "/devops" is already in use by container "30ae08c83d81b79d8688cf67affb1edd1b742e2ad1eff513d5be2a81c90a6532". You have to remove (or rename) that container to be able to reuse that name.

查看镜像和容器情况,可以看出在重新构建后,之前的那个容器没有被停掉,导致再启动容器时,启动失败


查看镜像、容器

问题原因:
在Jenkins里的shell脚本有问题,导致脚本执行失败,重新构建时没有删除旧的容器和镜像。比如,在[[ ]]]内两边没有留空格,导致shell脚本错误。

错误的写法:

if [[-n "$result"]]

正确的写法

# -n 表示:result字符串长度大于0,注意[[ ]]内部两边有空格
if [[ -n "$result" ]]

为了避免shell脚本错误导致执行失败,我们可以在服务器目录下,新建一个shell脚本文件,然后执行测试,看是否能正常执行,比如

vi test.sh

内容为将要在Jenkins要执行的shell脚本

#!/bin/bash
result=$(docker ps | grep "120.24.95.76:5000/devops")
# -n 表示:result字符串长度大于0,注意[[ ]]内部两边有空格
if [[ -n "$result" ]]
then
echo "stop devops"
docker stop devops
fi
result1=$(docker ps -a | grep "120.24.95.76:5000/devops")
if [[ -n "$result1" ]]
then
echo "rm devops"
docker rm devops
fi
result2=$(docker images | grep "1120.24.95.76:5000/devops")
if [[ -n "$result2" ]]
then
echo "120.24.95.76:5000/devops:0.0.1-SNAPSHOT"
docker rmi 120.24.95.76:5000/devops:0.0.1-SNAPSHOT
fi

执行test.sh脚本

sudo bash ./test.sh

执行过程

root@iZwz9f4eh9lmah6qiq41zvZ:~# sudo bash ./test.sh
120.24.95.76:5000/devops:0.0.1-SNAPSHOT
Untagged: 120.24.95.76:5000/devops:0.0.1-SNAPSHOT
Deleted: sha256:48288cce36ea8c2eead8e3a58dc0890b7a3c2edf3ab95a77fd75cc140a7d73f8
Deleted: sha256:3a9b395bca1c89fb12aedfb0dab365b212dffdc775ef1a646acc7d80fd072d86
Deleted: sha256:b3e98485e2b5e7b8c7a89c64cdf44039de5ff796152ce800e906f20d2756ca33
Deleted: sha256:48b6b69723281b1c4bc221bcda5ff0b4db1175a3db2a97a47c6ef4a4624c27d9
Deleted: sha256:19b3570f0e1341cb71f3b35b307a5aa088fac708663965ca213cecde0c89164b
root@iZwz9f4eh9lmah6qiq41zvZ:~# 
8.2.4.4 构建失败情况四

错误信息

Must specify baseImage if dockerDirectory is null

问题原因:
JenkinsInvoke top-level Maven targets错误地设置成docker:builddockerDirectory是插件docker-maven-plugin的配置,所以报错。

解决方案:
检查Jenkins Invoke top-level Maven targets设置,因为我们使用的是dockerfile-maven-plugin,因此命令是dockerfile:build而不是docker:build

clean package -f pom_docker_registry.xml -DskipTests dockerfile:build
8.3 Jenkins自动构建
8.3.1 Jenkins中拿到钩子地址

1、Jenkins安装Gitlab插件前Build Triggers的选项


Jenkins安装Gitlab插件前Build Triggers的选项

2、安装Gitlab插件


安装Gitlab插件

安装完插件后要重启Jenkins插件才会生效

Gitlab插件

勾选GitLab webhook选项,点击保存,并复制URL地址http://120.79.114.234:8080/project/devops,该地址需要配置到GitLab设置里

勾选

3、GitLab authentication设置
由于我们Jenkins访问GitLab用的是账号名密码,不是用的ssh keys,因此我们要取消authentication的勾选选项,否则使用钩子时会报403错误,如下

提示403错误

取消authentication的勾选选项操作如下:


设置
取消authentication勾选项
8.3.2 GitLab配置webhook(钩子)

1、登录GitLab,在Network里找到这两个选项并进行勾选,点击保存。

Network勾选选项

2、进入devops项目,点击Settings-Webhooks,粘贴Jenkins那边得到的URL地址,点击【Add webhook】按钮进行保存。

Settings-Webhooks
URL地址
Add webhook

3、在Test里选择Push events进行Push测试。


Push测试
测试成功
自动构建
8.3.3 修改代码push后自动构建

1、将hello方法里的代码改成Kyra

@RestController
@RequestMapping("devops")
public class DevOpsController {

    @GetMapping("hello")
    public String hello(){
        return "Kyra";
    }
}

2、git提交代码

AC-2:devops AC$ git add .
AC-2:devops AC$ git commit -m "Kyra"
[main 094c6d7] Kyra
 1 file changed, 1 insertion(+), 1 deletion(-)
AC-2:devops AC$ git push
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (10/10), 719 bytes | 719.00 KiB/s, done.
Total 10 (delta 2), reused 0 (delta 0)
To http://120.79.114.234:6001/root/devops.git
   3eec4b3..094c6d7  main -> main
AC-2:devops AC$ 

3、git push后Jenkins会自动构建


git push后Jenkins会自动构建

4、刷新接口,接口返回修改后的Kyra

http://120.24.95.76:8002/devops/hello

你可能感兴趣的:(Jenkins持续集成)