尚硅谷云原生学习笔记(1-75集)

笔记列表:

目录

1、什么是云计算

1.1、互联网时代的历程

在这里插入图片描述

1.2、云计算到底是什么

在这里插入图片描述

2、云计算平台的分类理解

2.1、云计算历程

在这里插入图片描述

2.2、云计算服务名称

在这里插入图片描述

  • IaaS:比如华为服务器等
  • PaaS:比如阿里云等
  • SaaS:比如微盟、金蝶等
  • CaaS:比如QQ安装包

3、云平台的优缺点

在这里插入图片描述

4、服务的架构变革

4.1、体系变革

在这里插入图片描述

4.2、架构变革

4.2.1、单体架构

在这里插入图片描述

4.2.2、集群架构

在这里插入图片描述

4.2.3、分布式架构

在这里插入图片描述

4.2.4、微服务架构

在这里插入图片描述

4.2.5、网格化架构

在这里插入图片描述

5、技术的变革

5.1、云上挑战

在这里插入图片描述

5.2、技术变革

在这里插入图片描述

在这里插入图片描述

6、提问解答

7、完整云原生平台的基础技术量

7.1、云原生的生态系统

在这里插入图片描述

7.2、完整云原生平台基础研究量

在这里插入图片描述

8、应用的12要素

9、云原生的其他概念

9.1、常用术语

文档链接: https://kdocs.cn/l/cshYnro61lmQ

官方链接: http://www.cloudfoundry.cn/cloud-native-glossary/

文档截图:

在这里插入图片描述

9.2、云原生官方定义

链接: https://github.com/cncf/toc/blob/main/DEFINITION.md

中文版本截图:

在这里插入图片描述

10、云原生的官方指导学习路线

官方链接(貌似不能访问):
https://raw.githubusercontent.com/cncf/trailmap/master/CNCF_TrailMap_latest.png

在这里插入图片描述

11、云原生课程的疑问

12、Docker的底层容器隔离机制

12.1、Docker架构

12.1.1、整体框架

在这里插入图片描述

  • Client:客户端;操作docker服务器的客户端(命令行或者界面)
  • Docker_Host:Docker主机;安装Docker服务的主机
  • Docker daemon:后台进程;运行在Docker服务器的后台进程
  • Images:镜像;Image是只读模板,其中包含创建Docker容器的说明,其中容器是由Image运行而来,Image固定不变。
  • Containers:容器;在Docker服务器中的容器(一个容器一般是一个应用实例,容器间互相隔离),一个镜像可以生成多个容器
  • Registries:镜像仓库,也就是存储Docker Image的地方,官方远程仓库地址:https://download.docker.com/linux/centos/docker-ce.repo,当然也可以使用阿里云镜像仓库:https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

12.1.2、虚拟机、Docker、容器的关系

在这里插入图片描述

  • Infrastructure:基础设施;比如华为服务器
  • Host Operating System:操作系统;比如基于Linux操作系统的CentOS
  • Docker:docker环境
  • App X:容器

12.2、Docker隔离原理

12.2.1、资源隔离(namespace 6项隔离)

在这里插入图片描述

12.2.2、资源限制(cgroups资源限制)

在这里插入图片描述

cgroup资源控制系统,每种子系统独立地控制一种资源。功能如下:

在这里插入图片描述

13、Docker安装完成

14、Docker镜像加速配置

14.1、在线安装

14.1.1、docker官网

https://www.docker.com

注意: 安装过程中需要在linux上登录root用户,否则部分命令将执行受阻

14.1.2、找到在CentOS中安装docker的文档

点击Developers》Docs,如下:

在这里插入图片描述
点击Download And Install,如下:

在这里插入图片描述
点击Docker fro Linux,如下:

在这里插入图片描述
点击CentOS,如下:

在这里插入图片描述

14.1.3、判断安装docker的CentOS环境是否符合要求

判断来源依然是官网,截图如下,如果你不知道你的CentOS版本,你可以在终端中使用cat /etc/redhat-release命令查看当前CentOS版本

在这里插入图片描述

14.1.4、卸载旧版本

如果你之前已经安装过docker,然后本次安装的是新的docker版本,那需要先卸载旧版本,然后在安装新版本,卸载命令如下。如果你根本没有安装过docker,请忽略这一步。

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

上述命令来源于官网,截图如下:
在这里插入图片描述

14.1.5、安装gcc相关工具

14.1.5.1、判断CentOS是否能上外网

使用下列命令即可判断,如下:

ping www.baidu.com

如果无法连接外网,那就需要配置一下,博客如下:CentOS配置静态IP

14.1.5.2、安装gcc编译器

执行以下命令安装gcc编译器:

yum -y install gcc

注意:如果你不确定是否已经安装了,你也可以执行这条命令,多次执行该命令不会多次下载

14.1.5.3、安装gcc-c++编译器

执行以下命令安装gcc-c++编译器:

yum -y install gcc-c++

注意:如果你不确定是否已经安装了,你也可以执行这条命令,多次执行该命令不会多次下载

14.1.6、选择合适的安装方式

选择大多数人使用的安装方式就可以了,点击下图中的蓝色链接即可:
在这里插入图片描述

14.1.7、安装yum-utils安装包

安装yum-utils安装包,命令如下:

yum install -y yum-utils

14.1.8、安装阿里云镜像仓库

不能使用官方推荐的 https://download.docker.com/linux/centos/docker-ce.repo,因为这是国外的镜像仓库,在国内使用容易产生TCP连接问题和超时问题

建议使用阿里云或者网易云的docker镜像仓库,我们下面以阿里云docker镜像仓库为例来进行安装配置,以下配置脚本来源于阿里云官网的文章Docker CE 镜像中,如下:

sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

14.1.9、安装docker引擎

(1)安装最新版本docker,需要执行以下命令:

sudo yum -y install docker-ce docker-ce-cli containerd.io

(2)如果想安装其他版本docker,可以先使用以下命令查询所有docker版本列表

yum list docker-ce --showduplicates | sort -r

上述命令查询结果如下,其中红框中就是dockerVersion:

在这里插入图片描述

如果选好了docker版本,可以将下面命令中的dockerVersion替换掉,之后执行命令安装docker即可:

sudo yum install -y docker-ce-dockerVersion.x86_64 docker-ce-cli-
dockerVersion.x86_64 containerd.io

例如我选择的dockerVersion是3:19.03.9-3.el7,那么命令就是:

sudo yum install -y docker-ce-3:19.03.9-3.el7.x86_64  docker-ce-cli-3:19.03.9-3.el7.x86_64 containerd.io

14.1.10、配置镜像加速器

14.1.10.1、配置阿里云镜像加速器(不太推荐,原因是部分镜像无法下载)

首先进入阿里云官网,并登录账号,搜索容器镜像服务,选择立即开通,如下:
在这里插入图片描述
找到需要执行的脚本命令,如下:
在这里插入图片描述

一定要在linux中执行上述截图中框起来的脚本命令才能完成加速功能

14.1.10.2、配置网易镜像加速器(推荐)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["http://hub-mirror.c.163.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

14.1.11、启动docker

执行以下命令启动docker,如下:

systemctl start docker

注意: 启动完成不会有任何消息提示,但是可以通过ps -ef | grep docker来验证是否docker是否启动成功

14.1.12、设置docker开机自启

执行以下命令:

systemctl enable docker

14.2、离线安装(说明:没有实现,先记录一下,后续可能会实现)

14.2.1、docker官网

https://www.docker.com

注意: 安装过程中需要在linux上登录root用户,否则部分命令将执行受阻

14.2.2、下载docker离线安装包

点击Developers》Docs,如下:

在这里插入图片描述
点击Download And Install,如下:

在这里插入图片描述
点击Docker fro Linux,如下:

在这里插入图片描述
点击Binaries下面的Install daemon and client binaries on Linux,如下:

在这里插入图片描述
tgz压缩包下载路径在以下位置:

在这里插入图片描述

之后点击x86_64/,如下:

在这里插入图片描述

之后就可以选择适合自己的docker版本下载,下载速度很快,所以就不给安装包了,如下:

在这里插入图片描述

TODO 安装方法后续验证通过在补充

15、Docker镜像的一些概念

在这里插入图片描述

  • 查看所有镜像:docker images或者docker image ls
  • 拉取最新镜像:docker pull 镜像名称,相当于docker pull 镜像名称:latest
  • 拉取特定版本镜像:docker pull 镜像名称:镜像版本
  • 镜像选择:尽量选择带alplineslim的镜像。原因是:镜像是linux操作系统+软件自身构成的,其中带alplineslim的镜像使用的linux操作系统很小,所以最终镜像本身也不大,另外常规版Linux+软件自身构成的镜像还是很大的

所有Docker命令手册:
https://docs.docker.com/engine/reference/commandline/docker

16、Docker镜像的一些其他操作

  • 删除单个镜像:docker rmi -f 镜像名称:标签;添加-f的作用是删除已经运行过的容器所属镜像,或者正在运行的容器所属镜像
  • 删除所有镜像:docker rmi -f $(docker images -aq),其中-a是列出所有镜像,而-q是只列出镜像id
  • 删除游离镜像:docker image prune,然后在控制台输入y就可以了
  • 镜像改名:docker tag 原镜像名称:原标签 新镜像名称:新标签,改名之后通过docker images可以看到原来镜像和新镜像,并且镜像id相同

17、Docker其他的一些命令

  • 查看运行中Up状态的容器:docker ps,当容器状态是Up(运行中)才能被看到:Up(运行中);如果启动命令太长会被省略,想看查看完整启动命令需要添加--no-trunc指令,例如:docker ps --no-trunc
  • 查看所有状态的容器:docker ps -a,当容器状态是以下几种中任意一种都能被看到:Created(新建)、Up(运行中)、Pause(暂停)、Exited(退出)
  • 删除所有容器:docker rm -f $(docker ps -aq),其中-a是展示所有状态的容器
  • 容器的几种状态:Created(新建)、Up(运行中)、Pause(暂停)、Exited(退出)
  • 新建容器:docker create --name=myredis -p 6379:6379 redis:latest,可以通过docker ps -a看到该容器,并且容器状态是Created
  • 启动容器:docker start 容器id/容器名称,可以把Created(新建)、Exited(退出)状态的容器启动起来,执行完成后可以通过docker ps或者docker ps -a看到该容器,并且容器状态是Up
  • 暂停容器:docker pause 容器id/容器名称,执行完成后可以通过docker ps -a看到该容器,并且容器状态是Pause
  • 暂停恢复容器:docker unpause 容器id/容器名称,执行完成后可以通过docker ps或者docker ps -a看到该容器,并且容器状态是Up
  • 优雅停止容器:docker stop 容器id/容器名称,执行完成后可以通过docker ps -a看到该容器,并且容器状态是Exited,该操作运行正在运行中的程序处理完所有事情在停止
  • 强制停止容器:docker kill 容器id/容器名称,执行完成后可以通过docker ps -a看到该容器,并且容器状态是Exited,该操作将会使程序马上停止
  • 直接以后台方式启动容器:docker run -d --name=myredis -p 6379:6379 redis:latest,可以通过docker ps看到该容器,并且容器状态是Up,-d代表后台启动,这行语句相当于docker create --name=myredis -p 6379:6379 redis:latest + docker start myredis
  • 以交互模式启动容器:docker run -it --name=myredis -p 6379:6379 redis:latest,容器启动之后我们会直接进入容器内部
  • 查看容器日志:docker logs -f 容器id/容器名称,添加-f用于动态跟踪查看容器日志

18、Docker的进入容器细节

  • 进入容器:docker exec -it -u 0:0 --privileged 容器id/容器名称 /bin/bash-i是以交互模式进入容器,-t是新打开一个终端,-u 0:0是以root用户身份进入容器,--privileged是以特权方式进入容器,这样用户进入容器之后就能拥有极大的执行权力,最后的/bin/bash代表进入容器bash控制台,部分容器进入控制台使用sh命令或者/bin/sh命令
  • 查看容器详情:docker inspect 容器id/容器名称,对应复杂写法:docker container inspect 容器id/容器名称
  • 查看镜像详情:docker inspect 镜像名称:镜像标签,对应复杂写法:docker image inspect 容器id/容器名称

19、Docker cp命令

简单使用:

# 从容器中复制内容到外部
docker cp 容器:容器内部内容 外部存储位置
例如:docker cp 4e7c32cf23cd:/etc/nginx/nginx.conf nginx.conf,用于将nginx.conf

# 将外部内容复制到容器中
docker cp 外部内容 容器:容器内部存储位置
例如:docker cp index.html 4e7c32cf23cd:/usr/share/nginx/html,用于将index.html复制到容器的/usr/share/nginx/html中,并且会替换html下面的index.html

详细用法:

# 从容器中复制内容到外部
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

# 将外部内容复制到容器中
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH

SRC_PATHDEST_PATH身份不同时,最终效果也不同,具体使用注意点如下:

在这里插入图片描述

20、Docker镜像的推送等操作

  • 检查容器中文件系统结构的改变:docker diff 容器id/容器名称,结果中以不同字母开头就代表不同含义,其中:【A:添加文件或目录;C:文件或者目录更改;D:文件或者目录删除】
  • 把容器提交成新镜像:docker commit -a 明快de玄米61 -m "first commmit" 容器id/容器名称 myredis:v1,其中-a后面写的是作者,-m后面写的是提交说明,由于中间有空格,所以用双引号包裹起来,myredis是新镜像名称,而v1是新镜像版本号
  • 游离镜像产生途径:两次docker commit相同镜像名称和版本,将会使前一次的镜像成为游离镜像
  • docker仓库中镜像命名规则:一般是仓库地址/命名空间/镜像仓库名称:镜像标签,比如docker hub中的nginx官方镜像就是docker.io/library/nginx:latest,官方镜像在拉取的时候默认可以省略docker.io/library/,所以拉取的时候直接使用docker pull nginx:latest。而docker hub中的非官方镜像在拉取的时候只能省略仓库地址,而不能省略命名空间;如果是阿里云镜像仓库,那仓库地址也不能省略,比如:docker pull registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/quay.io_prometheus_prometheus:[镜像版本号]
  • 登录docker仓库:docker login -u 用户名 docker仓库地址(如果推送docker hub就不用写docker仓库地址),-u就是–username,也就是用户名。比如登录dockerhub的命令是:docker login -u mingkuaidexuanmi61,而登录阿里云的命令是:docker login --username=明快de玄米61 registry.cn-hangzhou.aliyuncs.com,登录成功会提示:Login Succeeded
  • 退出docker仓库:docker logout
  • 镜像推送到镜像仓库步骤
    • 登录镜像仓库:docker login -u 用户名 docker仓库地址(如果推送docker hub就不用写docker仓库地址),比如:1、docker login -u mingkuaidexuanmi61(登录docker hub);2、docker login --username=明快de玄米61 registry.cn-hangzhou.aliyuncs.com(登录阿里云镜像仓库)
    • 镜像改名:docker tag 镜像id 仓库地址/命名空间/镜像仓库名称:镜像标签(如果推送到docker hub 就不用写“仓库地址/”),比如:1、docker tag 69a160e0a651 mingkuaidexuanmi61/myredis:v1(未来推送到docker hub);2、docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/quay.io_prometheus_prometheus:[镜像版本号](未来推送到阿里云镜像仓库)
    • 推送到镜像仓库:docker push 仓库地址/命名空间/镜像仓库名称:镜像标签(如果推送到docker hub 就不用写“仓库地址/”),比如:1、docker push mingkuaidexuanmi61/myredis:v1(推送到docker hub);2、docker push registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/quay.io_prometheus_prometheus:[镜像版本号](推送到阿里云镜像仓库)
      对于上述三个步骤,我们把推送镜像到阿里镜像仓库的步骤截取一下吧,如下:
      在这里插入图片描述

21、Docker镜像的转移操作(导入、导出)

  • 单个容器导出、导入(注意:不要使用):不要使用的原因是导出的镜像在导入之后必须使用之前容器的启动命令启动,非常麻烦,这里把命令也说明一下,如下:docker export -o tar包名称 容器iddocker import tar包名称 镜像名称:镜像标签;如果必须要将现有容器变成镜像导出,大家可以使用docker commit先制作镜像,然后使用docker save -o tar包名称 镜像名称:镜像标签导出镜像
  • 多个镜像导出成tar包(注意:可以使用):docker save -o tar包名称 单个或者多个镜像信息(多个镜像中间用空格分隔),例如:docker save -o myredis.tar myredis:v1
  • 导出包含多个镜像的tar包(注意:可以使用):docker load -i tar包名称,例如:docker load -i myredis.tar

22、Docker容器长久运行之道

容器启动之后肯定有需要一直做的事情,否则不可能长久运行,比如busybox镜像就没有这种事情,那就不能长久运行。如果我们想让busybox容器长久运行,那就需要指明一个命令让它能长久运行,比如:docker run -d busybox ping www.baidu.com

23、Docker如何构建镜像

创建一个ping百度的镜像,其中Dockerfile如下:

FROM alpine
CMD ping www.baidu.com

构建镜像命令如下:

# -t后面指定镜像名称:标签,-f后面指定Dockerfile文件的全路径,.代表工作目录
docker build -t attackbaidu:v1 -f Dockerfile .

24、如何下载做实验

docker实验室

说明: 每次登陆docker实验室,都会获得4小时的使用时长,最主要的功能是可以下载国外的镜像,有些时候下载国外镜像非常慢,可以先使用该网站下载下来,然后上传到阿里云镜像仓库中,之后我们下载下来,然后通过docker tag改名之后就可以正常使用了

在这里插入图片描述

25、镜像如何在底层存储

26、容器与镜像的写时复制技术

通过docker image inspect 镜像id可以查看容器细节,比如nginx镜像底层存储信息如下:

在这里插入图片描述

  • LowerDir:底层目录
  • MergedDir:合并目录
  • UpperDir:上层目录
  • WorkDir:工作目录

LowerDir:

/var/lib/docker/overlay2/03ed09a2686181fef7a4418b94eafb135695a4053a4ecf910556f54fcbe931b5/diff
目录文件列表:docker-entrypoint.d

/var/lib/docker/overlay2/aad5146a099afeed2f1facca6e0673f0535eb58aaf609fbd187961aaf1d29967/diff
目录文件列表:docker-entrypoint.d

/var/lib/docker/overlay2/36b7df9b17ff9dc6197461d5da662e1fe546554fbd4adcba91f5dae6eaedf564/diff
目录文件列表:docker-entrypoint.sh

/var/lib/docker/overlay2/6ea0055863bb9a7870cc5677087fb8b57a669989ae506e5bfc07af6b833bf214/diff
目录文件列表:docker-entrypoint.d  etc  lib  tmp  usr  var

/var/lib/docker/overlay2/81a82a1e3f38865dec609b878d7f1d9c8a667144d95407fab90173563a70ff1b/diff
目录文件列表:bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

这相当于是一种叠罗汉的过程,最底层就是linux系统,然后往上一层层记录不相同的内容就构成了底层目录

上面简单介绍了一下镜像的结构,其实我们对容器执行docker inspect 容器id也可以看到容器也是这些层,如果我们不修改容器内容,那么容器的层就会指向镜像的层,如果我们对容器内容进行修改,根据写时复制思想,就会把原始的文件复制到容器对应层,然后进行修改,但是无论怎么修改,都不会影响到镜像

在这里插入图片描述

27、Docker的overlayFS存储驱动原理

在这里插入图片描述
简单来说镜像层的lowerdir底层目录来存储基础内容,如果我们需要修改文件,那就在把文件复制到容器层的upperdir上层目录中进行修改,原始层和修改层组合到一起就是合并层,而容器层真正使用的是merged合并层目录

详细了解请看:https://docs.docker.com/storage/storagedriver/overlayfs-driver/

28、Docker数据卷挂载的三种方式

29、Docker的-v挂载测试

30、Docker的卷管理

说明:

讲解VolumesBind mounts之前,我们先来说明一下两者的区别,如果-v后面,并且:之前的目录以/开头,那就是Bind mounts(比如:-v /data/nginx_html:/usr/share/nginx/html),否则就是Volumes(比如:-v /usr/share/nginx/html或者-v nginx_html:/usr/share/nginx/html

使用Bind mounts需要提前把目录内容准备好,因为容器中的对应内容将被替换成挂载指定的目录里面的,如果挂载指定的目录里面是空的,那容器中的对应内容就会被删除,所以谨慎使用这种方式;
但是这种方式也不是一无是处,比如我们想让容器中的编码方式以及时间和本地虚拟机中的一致,那就可以使用这种挂载方式,让容器共享本地虚拟机中的文件

使用Volumes不需要提前准备内容,因为卷对应目录中的内容和容器中对应目录的内容完全一样

30.1、Volumes(解释:开发者自己创建文件夹,手动挂载)

匿名卷:

# 挂载目录为空,甚至连:都不用写,虽然没有指定卷名称,但是docker会为它自动生成一个随机卷名称
docker run -d -P -v /usr/share/nginx/html --name=mynginx nginx

具名卷(不需要提前创建卷名,创建容器的时候会自动创建):

# 名字是卷的名称,都是自己取的
docker run -d -P -v nginx_html:/usr/share/nginx/html --name=mynginx nginx

查看卷:

卷的几种操作:

# 创建卷
docker volume create 卷名称

# 查看卷详情,尤其是卷对应的真实物理地址
docker volume inspect 一个或者多个卷名称

# 查看所有卷
docker volume ls

# 清除没有被使用的卷
docker volume prune

# 删除卷
docker volume rm 一个或者多个卷名称

查看容器所用的卷一般使用两种方法

方法1:通过查看容器详情查找

具体命令是docker inspect 容器id,例如查看nginx容器的信息如下:

匿名卷物理位置截图:

在这里插入图片描述
具名卷物理位置截图:

在这里插入图片描述
方法2:通过卷详情查找

如果你知道卷名称,可以通过卷详情查找,当然如果不知道卷名称,也可以通过docker volume ls先查找对应卷名称,然后继续说通过卷详情查找物理存储路径,比如我设置的卷名称是nginx_html,那么命令就是:docker volume inspect nginx_html

在这里插入图片描述

30.2、Bind mounts(解释:docker自己创建文件夹,自动挂载)

# 不需要提前创建/data/nginx_html,创建容器的时候会自动创建多级目录
# 但是存在的一个问题是:如果nginx_html是空的/没创建,那么将导致/usr/share/nginx/html也是空的,这是空挂载,多多注意
docker run -d -P -v /data/nginx_html:/usr/share/nginx/html --name=mynginx1 nginx

30.3、tmpfs mounts(解释:可以把数据挂载到内存中,不用这个)

31、Docker的可视化界面

31.1、容器开机自启动

我们使用--restart=always参数可以完成功能,这其实是设置容器存在时的重启策略,我们设置的是任何情况都重启,那开机的时候容器存在但是没有启动,自然就会触发重启策略;

  • 如果容器还没有创建,那就可以通过docker run --restart=always方式设置启动策略
  • 如果容器已经创建,那就可以通过docker update --restart=always来设置重启策略

31.2、安装docker可视化界面—portainer

docker主节点可以安装可视化界面,单个节点那自身就是主节点了,安装指令如下:

docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v \
/var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data \
portainer/portainer-ce

安装完成后直接访问http://主机:9000端口就可以了,访问成功之后需要先设置密码,然后就能看到对应界面了

在这里插入图片描述

对于集群情况,还有其他节点,那它们需要安装agent端,之后我们就可以在主节点的页面看到集群中所有节点信息了,具体指令如下:

docker run -d -p 9001:9001 --name portainer_agent --restart=always -v \
/var/run/docker.sock:/var/run/docker.sock -v \
/var/lib/docker/volumes:/var/lib/docker/volumes portainer/agent

32、最基本Dockerfile构建镜像

Dockerfile:

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo 111

# 容器运行期间执行的命令,可以使用sh文件,或者直接在CMD后面写也行
CMD sleep 10;echo success

构建镜像:

# -t:后面写的是新镜像名称和标签,-f后面指定Dockfile文件位置,.代表Dockfile中命令执行的工作空间
docker build -t myalpine:v1 -f Dockerfile .

打印的构建过程:

在这里插入图片描述

查看构建完成的镜像:

在这里插入图片描述
采用交互模式运行构建完成的镜像:

docker run -it 0ca5b66e5a2e

然后10s之后控制台输出success退出

33、Dockerfile怎么写—1

33.1、FROM

挑选说明:

FROM 指定基础镜像,最好挑一些apline,slim之类的基础小镜像

如何确定我需要什么要的基础镜像?

  • Java应用是jdk/jre基础镜像(例如:SpringBoot应用,打jar包),或者是Tomcat基础镜像(例如:SpringWeb应用,打war包)
  • JS模块化应用一般用nodejs基础镜像
  • 其他各种语言用自己的服务器或者基础环境镜像,例如python、golang、java、php等

33.2、LABEL

作用:

用来标明镜像的说明信息,比如镜像的制作人、制作时间等

写法举例:

# 写法1(一行写完):
LABEL multi.label1="value1" multi.label2="value2" other="value3"

# 写法2(多行写,用\换行):
LABEL multi.label1="value1" \
	  multi.label2="value2" \
	  other="value3"

33.3、ARG的生命周期

总结:镜像构建时期存活,但是容器运行时期失效

解释:构建镜像的时候有效,可以用在RUN指令(镜像构建期间执行)中,但是不能用在CMDENTRYPOINT (容器运行期间执行)中

33.4、ENV的生命周期

总结:镜像构建和容器运行时期都存活

解释:可以用在Dockerfile的任何指令中,都是生效的

33.5、RUN的执行时期

总结:镜像构建时期执行

解释:构建镜像的时候执行,也就是根据Dockerfile创建镜像的整个过程中会执行

33.6、CMD的执行时期

总结:容器运行时期执行

解释:容器启动完成的运行期间执行,也就是在容器启动完成之后运行的时候执行

33.7、RUN的两种书写形式

33.7.1、shell形式(可以取出变量的值)

写法: RUN 命令

举例: RUN echo $name;echo $name2

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

ARG name="hello world"
ARG name2="明快de玄米61"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $name;echo $name2

解释: 这种写法等于:/bin/sh -c "echo $name;echo $name2",由于我本次测试使用的是alpine镜像,所以是/bin/sh -c,如果使用其他镜像,相当于是/bin/bash -c,视具体镜像而定

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

ARG name="hello world"
ARG name2="明快de玄米61"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN /bin/sh -c "echo $name;echo $name2"

说明: 这种写法可以取出ARGENV定义的变量值

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

ARG name="hello world"
ENV address="中国"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $name;echo $address

33.7.2、exec形式(可以执行shell命令,但是无法取出变量的值)

写法: RUN ["命令"……]

举例: RUN ["echo", "$name"]

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

ARG name="hello world"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN ["echo", "$name"]

执行结果:无法取出变量name的值,构建过程中只能打印出$name,可以使用docker build -t myalpine:v1 --no-cache -f Dockerfile .去尝试

在这里插入图片描述

33.7.3、exec形式转变成shell形式(可以取出变量的值)

写法: RUN ["/bin/sh", "-c", "具体指令"]

举例: RUN ["/bin/sh", "-c", "echo $name"]

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

ARG name="hello world"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN ["/bin/sh", "-c", "echo $name"]

执行结果:可以取出name变量的值

在这里插入图片描述

解释: 这种写法等于:/bin/sh -c "echo $name",由于我本次测试使用的是alpine镜像,所以是/bin/sh -c,如果使用其他镜像,相当于是/bin/bash -c,视具体镜像而定

Dockerfile全部指令说明:https://docs.docker.com/engine/reference/builder/

34、ARG—指令

34.1、生效时间

镜像构建时期存活,但是容器运行时期失效;所以可以在RUN指令中可以使用,但是在CMDENTRYPOINT指令中不能使用

在这里插入图片描述

34.2、是否可以在定义之前使用

不能

在这里插入图片描述

34.3、能否并排定义

不能

在这里插入图片描述

34.4、如何在镜像构建命令中修改参数值

可以通过–build-arg参数修改ARG定义的参数值,例如我通过ARG定义了两个参数的值,分别是name="明快de玄米61"address="中国",如果我想把它们修改成其他值,执行的构建指令是:

docker build --build-arg name=mingming --build-arg address="my china" -t myalpine:v1 --no-cache -f D1 .

Dockerfile如下:

# 基础镜像
FROM alpine

# 打标签,也就是描述信息
LABEL maintainer="明快de玄米61" date="2022/12/17" \
weather=sunny

ARG name="明快de玄米61"
ARG address="中国"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $name;echo $address

构建结果如下:

在这里插入图片描述

34.5、可以在FROM之前使用ARG定义参数吗

可以

Dockerfile:

# 可以在任意位置定义,并且在镜像构建期间生效的命令中使用
ARG version=3.17.0

# 基础镜像
FROM alpine:$version

构建结果如下:

在这里插入图片描述

35、ENV指令

35.1、生效时间

构建期和运行期间都是生效的

Dockerfile:

# 基础镜像
FROM alpine

ENV desc="知识分享者"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $desc

# 容器运行期间执行的命令,可以使用sh文件,或者直接在CMD后面写也行
CMD echo $desc

构建期间执行结果:

在这里插入图片描述
运行期间执行结果:

运行命令:docker run -it myalpine:v1

在这里插入图片描述

35.2、能否在镜像构建命令中修改参数值

不能

35.3、能否在容器运行命令中修改参数值

可以

Dockerfile:

# 基础镜像
FROM alpine

ENV desc="知识分享者"
ENV age=100

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $desc;echo $age

# 容器运行期间执行的命令,可以使用sh文件,或者直接在CMD后面写也行
CMD echo $desc;echo $age

容器运行期间执行结果:

命令:docker run -it -e desc=博主 -e age=120 myalpine:v1

在这里插入图片描述

35.4、ENV能否引用ARG

Dockerfile:

# 基础镜像
FROM alpine

ARG desc1="知识分享者1"
ENV desc2=$desc1

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $desc1;echo $desc2

构建过程如下:

在这里插入图片描述

35.5、能否并排定义

Dockerfile:

# 基础镜像
FROM alpine

ENV desc1="知识分享者1" desc2="知识分享者2"

# 容器构建过程中运行的指令,默认使用镜像的root用户执行命令
RUN echo $desc1;echo $desc2

构建期间执行结果:

在这里插入图片描述

36、ENV的持久化问题

36.1、ENV的值到底存在哪里了

就那上述1中的镜像为例,通过docker inspect 镜像id命令查看镜像信息,可以看到desc2的信息如下,说明只要镜像一旦形成,ENV定义的环境变量的值就已经固化了,不过后期可以在docker run的时候通过-e参数修改

在这里插入图片描述

37、ADD与COPY指令

说明: ADD与COPY指令复制的内容都来自于Linux虚拟机中,而不是镜像中,不过最终是要复制到镜像中的

37.1、ADD能复制普通内容、解压压缩包、下载url链接中的文件

  • 链接:下载链接中的文件,然后复制到目录中,不会解压
  • 压缩包:解压压缩包到目录中,会解压(说明:jar包不属于压缩包)
  • 普通目录/文件:直接复制到目录中即可,不会解压

Dockerfile:

# 基础镜像
FROM alpine

# 自动下载
ADD https://download.docker.com/mac/static/stable/x86_64/docker-20.10.14.tgz /dest/

RUN cd /dest && ls -l

# 自动解压压缩包
ADD docker-20.10.14.tgz /app/

RUN cd /app && ls -l

# 复制普通内容到镜像中
ADD *.txt /redis/

RUN cd /redis && ls -l

结果:

在这里插入图片描述
在这里插入图片描述
拓展:

如果想复制某目录下面的全部内容,就可以通过/来表示,如下:

Dockerfile:

# 基础镜像
FROM alpine

# 赋值当前路径下的所有内容到redis下面
ADD ./ /redis/

# 复制duty目录下的内容到/webapp下,假设duty目录下是index.html、WEB-INF等,最终效果是/webapp下面是index.html、WEB-INF等,这种写法不会将duty整体复制到/webapp下
ADD duty /webapp/

# 复制duty目录到/webapp下,最终效果是/webapp下面是duty目录,这种写法可以将duty整体复制到/webapp下
ADD duty /webapp/duty

RUN cd /redis && ls -l

37.2、COPY是直接复制

  • 直接复制没什么好说的,不会下载链接中的目录,也不会解压压缩包

Dockerfile:

# 基础镜像
FROM alpine

COPY ./ /redis/

RUN cd /redis && ls -l

复制目录:

# 复制duty目录下的内容到/webapp下,假设duty目录下是index.html、WEB-INF等,最终效果是/webapp下面是index.html、WEB-INF等,这种写法不会将duty整体复制到/webapp下
COPY duty /webapp/

# 复制duty目录到/webapp下,最终效果是/webapp下面是duty目录,这种写法可以将duty整体复制到/webapp下
COPY duty /webapp/duty

构建过程截图:

在这里插入图片描述

37.3、多次RUN的指令的上下文关系

每一次RUN指令的执行都是以WORKDIR为上下文,如果想让执行能以我们cd进入的目录为上下文,那就需要把它写在一行中,并且用&&分隔,比如:RUN cd /redis && ls -l

38、COPY的文件可以改变目录

无,老师没说清,感觉作用也不是很大

39、WORKDIR的应用

  • 指定Dockerfile中语句的工作空间
  • 当我们首次进入容器时,会直接进入workdir指定的目录下

指定工作空间:

Dockerfile:

# 基础镜像
FROM alpine

# alpine镜像的默认workdir是/,此时workdir是/
RUN pwd

# 设置workdir是/app,此时workdir是/app
WORKDIR /app
RUN pwd

# 在/app的基础上再次设置workdir为webabb/WEB-INF,此时workdir是/app/webabb/WEB-INF
WORKDIR webapp/WEB-INF
RUN pwd

构建过程截图:

在这里插入图片描述

进入容器的目录是workdir指定的目录:

我们进入nginx容器中最常改的东西是html文件,所以我们把workdir设置成/usr/share/nginx/html,Dockerfile如下:

# 基础镜像
FROM nginx

# 设置workdir
WORKDIR /usr/share/nginx/html

构建命令是:

docker build -t mynginx:v1 --no-cache -f D2 .

运行命令是:

docker run -dP mynginx:v1

进入容器内部,命令是:

docker exec -it f37721b0288 /bin/bash

可以看到默认空间正是我们设置的workdir,如下:

在这里插入图片描述

40、USER配合COPY进行权限的控制

38、COPY的文件可以改变目录的补充,但是作用不大,就不总结了

41、VOLUME的坑

  • 相当于docker run-v指令中匿名卷Volumes的作用
  • 尽量写在最后,因为VOLUME之后对挂载目录中内容的修改操作都会被丢弃
  • 只要被挂载出去的目录,后续docker commit提交镜像的时候这些挂载出去的目录都会被丢弃,包括VOLUMNdocker run -v
  • VOLUMN指令会延续下去,即使docker commit提交镜像的时候VOLUMN指令也会起作用

41.1、相当于docker run-v指令中匿名卷Volumes的作用

我们来制作一个nginx镜像,并且把/usr/share/nginx/html/etc/nginx目录挂载出去

Dockerfile:

# 基础镜像
FROM nginx

# 将html目录和配置文件挂载出来
VOLUME [ "/usr/share/nginx/html", "/etc/nginx" ]

构建命令:

docker build -t mynginx:v1 --no-cache -f D1 .

运行命令:

docker run -dP --name=mynginx1 mynginx:v1

查看挂载情况:

# 这一串字符串是容器id
docker inspect b3780984ae99

如下图:

在这里插入图片描述

进入htm挂载目录:

cd /var/lib/docker/volumes/3b79fbfb8e1cf3fd5d0da72f956b51f3db3189b73ffebbbc550bdbea34d6a476/_data

如下图:

在这里插入图片描述

41.2、尽量写在最后,因为VOLUME之后对挂载目录中内容的修改操作都会被丢弃

Dockerfile:

# 基础镜像
FROM alpine

VOLUME [ "/data" ]

RUN echo "111" > /data/a.txt

RUN cd /data && ls -l

构建过程截图:

在这里插入图片描述

41.3、只要被挂载出去的目录,后续docker commit提交镜像的时候这些挂载出去的目录都会被丢弃,包括VOLUMNdocker run -v

我们以1中制作的nginx镜像为例,我们把index.html中的内容修改成111,然后通过docker diff 容器id却看不到index.html的改变,其实从这个情况我们已经看出来了,即使通过docker commit 提交镜像也不会把index.html中是111的情况记录进去

我们把修改之后的nginx容器制作成镜像,命令是:

# b3780984ae99是nginx容器id
docker commit b3780984ae99 mynginx:v2

然后把容器运行起来,命令是:

docker run -dP mynginx:v2

之后通过docker inspect命令查看index.html所在位置,命令是:

docker insepct f08516

结果是:

在这里插入图片描述
进入该位置之后,查看index.html,结果如下:

在这里插入图片描述

41.4、VOLUMN指令会延续下去,即使docker commit提交镜像的时候VOLUMN指令也会起作用

上述操作3中已经运行了提交的镜像,我们通过docker inspect指令看到了挂载出来的/usr/share/nginx/html/etc/nginx,说明延续成功了

在这里插入图片描述

42、EXPOSE暴露端口

  • EXPOSE的主要是给程序员看的
  • 在运行docker run指令,然后设置-P参数的时候,docker会为容器自动暴露EXPOSE指定的端口
  • EXPOSE指令可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP。
    在这里插入图片描述
    下面举个例子,以busybox镜像为基础镜像,然后把80和90端口暴露出来,虽然这两个端口没啥用处,但是依然可以暴露出来看下嘛

Dockerfile:

# 基础镜像
FROM alpine

EXPOSE 80

EXPOSE 90

CMD ping www.baidu.com

构建语句:

docker build -t myalpine:v1 --no-cache -f D1 .

运行语句:

docker run -dP myalpine:v1

查看容器语句:

docker ps

查看结果如下

在这里插入图片描述

43、CMD、ENTRYPOINT容器启动指令

  • CMD和ENTRYPOINT角色划分:ENTRYPOINT是真正的大门,而CMD是为ENTRYPOINT提供参数的

  • 指令重复哪个会生效:多个CMD指令只有最后一个会生效、多个ENTRYPOINT指令只有最后一个会生效,所以只写一个就行了

  • CMD和ENTRYPOINT也有两种写法,分别是shell形式和exec形式,这两种的区别和写法与RUN中说明的一致,依然是exec形式无法取出变量值,但是可以通过/bin/sh -c的形式让exec形式变成shell形式

  • 如何覆盖CMD的参数:docker run指令中最后一个位置是写命令的,这个位置写的东西会覆盖CMD中的全部内容,比如下面的例子中默认是ping 5次百度的,但是我们在docker run指令的最后写了6 atugigu.com,所以最后的效果变成了ping 6次尚硅谷,这也说明了docker run指令的最后一个位置可以覆盖CMD中的全部指令
    在这里插入图片描述

  • CMD和ENTRYPOINT同时写,具体执行标准如下:在这里插入图片描述

举个CMD和ENTRYPOINT同时写的例子吧,该例子的作用是ping baidu.com

Dockerfile:

# 基础镜像
FROM alpine

CMD ["www.baidu.com"]

ENTRYPOINT ["ping"]

构建指令:

docker build -t myalpine:v1 --no-cache -f D1 .

运行指令:

docker run -P -it myalpine:v

在这里插入图片描述

44、多阶段构建

多阶段构建的目的是使用前一阶段的成果,我们举个例子吧,我们写一个普通的springboot项目,然后第一阶段使用maven进行构建,第二阶段生成可以运行的镜像,具体Dockerfile如下:

# 第一阶段:生成jar包,给第一阶段通过AS取名buildapp,方便第二阶段复制app.jar
FROM maven:3.5.0-jdk-8-alpine AS buildapp

WORKDIR /app

COPY pom.xml .
COPY src .

RUN mvn clean package -Dmaven.test.skip=true

RUN cp target/*.jar app.jar

# 第二阶段:生成可以运行的镜像
FROM  openjdk:8-jre-alpine
# 修改时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 从第一阶段复制app.jar
COPY --from=buildapp /app/app.jar app.jar

# 定义参数
ENV JAVA_OPTS=""
ENV PARAMS=""

# 启动命令
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS" ]

45、开通云服务器

我使用本地虚拟机,所以就不总结这一集了

46、Dockerfile的springboot应用写法

46.1、自己制作的镜像如何瘦身

  • 选择最小可用的基础镜像,比如带有alpine、slim这种的
  • 合并RUN环节的所有指令,少生成一些层,毕竟每一个指令就是一层,多个RUN指令合并的时候用&&连接,比如RUN echo 111 && echo 222
  • 使用.dockerignore文件,排除上下文中不需要参与构建的资源,类似于.gitignore
  • 使用多阶段构建
  • 合理使用构建缓存加速构建,比如构建的时候不加–no-cache

47、Docker运行期间的一些问题延伸

不同的容器运行使用不同的虚拟机

48、桥接网络的原理

48.1、docker系统净化

命令:

docker system prune

作用:

  • 移除所有停止的容器
  • 所有没有被使用的网络
  • 所有游离的镜像
  • 所有的游离构建缓存

48.2、docker容器、宿主机网络关系

如果我们不开启任何容器,我们在虚拟机上通过ip addr命令可以看到至少3中网络,分别是loens33docker0,其中lo是本地网络,ens33是和外界通信的网络,而docker0是我们docker网关,如下图:

在这里插入图片描述
我们通过docker run -d -p 30000:9090 --name=myalpine alpine ping www.baidu.com开启一个alpine容器,添加ping百度命令的原因是避免alpine容器停止,总要找个事情给它做嘛,然后在虚拟机上继续执行ip addr,我们会看到会多出一个网络信息,比如我的是31: veth38dede4@if30,如下:

在这里插入图片描述

我们使用命令docker exec -it 083654229bcc /bin/sh进入启动的alpine容器内部,输入ip addr命令,我们也会看到一个独特的网络信息,比如我的是30: eth0@if31,如下:

在这里插入图片描述

是不是已经感受到了一一对应的关系,没错它们就是一一对应完成容器和虚拟机的通信

我启动alpine容器的命令是:docker run -d -p 30000:9090 --name=myalpine alpine ping www.baidu.com,那我们访问外界的30000端口其实就是在访问alpine容器的9090端口,其实这种端口映射关系虚拟机都帮我们记着呢,另外大家先看下上面在alpine容器内部的ip addr命令截图,里面记载了ip信息是172.17.0.2/16,现在我们通过exit命令退出容器,并且回到虚拟机中,执行一下iptables -nL命令,执行结果如下:

在这里插入图片描述

你看看ipport都和我们容器的信息对应起来的,所以当我们访问30000端口的时候,虚拟机就知道我们找的是alpine容器的9000端口

我们在开一个alpine容器,命令是:docker run -d -p 31000:9090 --name=myalpine1 alpine ping www.baidu.com,使用ip addr可以看到多处的网络信息是33: vethfd0079b@if32,然后进入容器内部通过ip addr看到的网络信息是32: eth0@if33,对应的ip信息是172.17.0.3/16,然后在虚拟机中通过iptables -nL可以看到多了一行记录,它是172.17.0.3 tcp dpt:9090

如果我们在第二个alpine(ip:172.17.0.3)容器中ping第一个alpine(ip:172.17.0.2)容器的ip,发现是可以ping通的,反之亦然,所以说明两个容器的网络是连通的,其实两个容器中间的传输介质就是docker0网关,另外我们在alpine容器中ping www.baidu.com,发现也是通的,其实我们也是通过docker0网关,然后到ens33,最终猜到公网的,所以我们以两个alpine容器、docker0网关、ens33为例来说明一下网络交互情况,如下图:

在这里插入图片描述

49、–link来连接容器

49.1、容器网络互通在解释

上一个总结中基本说清了容器之间、容器和公网之间网络互通的原因,但是docker0网关那块没说太明白,我们再来聊一下,其实我们默认启动的容器都是在一个网络下面,默认网络叫做网桥bridge,查看网络的命令是:docker network ls,结果如下:

在这里插入图片描述
我们通过docker network inspect f9a627c0fa09查看网桥bridge的详细信息,里面可以看到网关和子网信息、网桥中的容器信息,如下:

在这里插入图片描述
因此我们那些默认容器都在同一个子网下面,当然可以通过一个网关进行网络互通了

49.2、–link的弊端

如果通过IP连接,其实是不稳定的,因为docker容器可能会出现问题挂掉,当再起一个同样名称容器的时候,容器原有ip可能已经变化了,如果频繁的去更改其他容器连接该容器的ip,说实话是一个很烦人的事情,所以最好用域名来代替ip,这时候–link属性就出现了,我们先把–link的使用方法说一下吧

我们先启动一个redis容器,命令是docker run -dP --name=redisserver redis,可以看出来redis容器的名称是redisserver,再来启动一个tomcat容器,并且让tomcat容器和redis容器联系在一起,命令是docker run -dP --name=tomcat --link=redisserver tomcat:jre8-alpine,其中--link后面写的是redis容器的名称,所以我们进入tomcat容器内部,应该是可以通过ping redisserver来连接redis容器的,我们来尝试一下

首先通过命令docker exec -it bf6f17bf556d /bin/bash进入tomcat容器,然后执行ping redisserver,发现是可以ping通的,其实原因是我们已经把redisserver对应的redis容器ip信息已经记录到了hosts文件中,我们可以执行cat /etc/hosts命令查看hosts文件内容,如下:

在这里插入图片描述
这种做法存在两个弊端,如下:

  • redis容器重新创建之后,ip可能改变,那么ping redisserver就无法连通了
  • 这种做法是单向的,也就是只有tomcat容器能pingredis,但是redis无法pingtomcat

50、docker自定义网络原理

50.1、常用网络模式

我们想完成的效果其实就是在一个容器里面可以通过类似域名的形式ping通另外一个容器,其中一方容器删除在重启都不应该影响到另外一个容器的连接,上次提到了--link,发现这种把域名和ip记录在hosts文件中的方式是不符合要求的,而自定义网络方式可以满足这一需求

我们先来说一下几种常见的网络模式:

项目ValueValue
bridge模式–net=bridge默认值,在Docker网桥docker0上为容器创建新的网络栈
none模式–net=none不配置网络,用户可以稍后进入容器,自行配置
container模式–network=container:容器id,当前容器和另外一个容器共享网络。kubernetes中的pod就是多个容器共享一个Network namespace。
host模式–net=host容器和宿主机共享Network namespace
用户自定义模式–net=自定义网络名称在创建容器的时候还可以将网络指定成用户自己定义的网络

默认情况下,我们使用的就是bridge桥接网络模式,然后简单介绍一下其他几个网络的缺点

  • none模式:一般不使用
  • container模式:和其他容器共享网络,也就是当前容器的ip和其他容器ip都是一致的,其他网络信息也都是共享的,比如我们可以让alipine在启动的时候共享redis容器的网络;操作是先启动一个redis容器,命令是:docker run -dP --name=redisserver redis,然后容器一个alpine容器来共享redis容器的网络,命令是:docker run -it --name=myalpine --network=container:a06b4114eef6 alpine,我们在alipine容器中输入ip addr,然后在redis容器中输入ip addr,发现两者都是一样的,这种很少使用
  • host模式:和虚拟机用同一个网络,那我们容器每开一个端口,那么虚拟机也需要开启对应端口,这种一般也不用
  • 用户自定义模式:用户自定义的网络,其中子网范围、网关都是我们自定义的,最大的好处是同处一个自定义网络的容器可以使用ping 容器名ping通,即使某容器删除之后又创建,只要容器名不变,那么其他容器依然可以连接上它,这个使用频率较高

50.2、自定义网络

  • 自定义网络:命令是docker network create --driver 网络驱动(默认是:bridge) --subnet 子网范围 --gateway 网关 网络名称,例如:docker network create --driver bridge --subnet 172.18.0.0/16 --gateway 172.18.0.1 mynet
  • 查看所有网络:docker network ls,其他自定义网络命令可以使用docker network --help查看
  • 启动容器指定自定义网络:命令例如docker run -d --network=mynet --name=myalpine alpine ping www.baidu.com,使用--network属性来指定自定义网络名称,其中mynet就是我的自定义网络名称
  • 查看自定义网络详情:命令是docker inspect 网络id,也可以写成docker network inspect 网络id,比如:docker inspect 91733d1c9e17,效果如下
    在这里插入图片描述
  • 将其他容器加入自定义网络:docker network connect 自定义网络名称 容器名称,比如我们将redis容器加入mynet网络,命令是docker network connect mynet redisserver
  • 测试处于同一自定义网络的容器之间互通:启动alpine容器命令docker run -d --network=mynet --name=myalpine alpine ping www.baidu.com,启动redis容器命令docker run -dP --network=mynet --name=redisserver redis,由于redis容器没法ping,所以我们只测试alpine容器ping通redis容器,我们通过命令docker exec -it 5be99b974da0 /bin/sh进入alpine容器,然后输入ping redisserver 回车,发现能ping通

51、docker-compose简单安装

52、compose以及集群模式

TODO docker官网无法访问,明天在总结这两节内容

53、青云需要创建vpc

我不用青云,我用自己本地虚拟机,不总结这块

54、子网掩码

XXX.XXX.XXX.XXX/数字,比如172.16.0.0/16,其中每一个XXX的范围都是0~255,其中一个XXX代表8为二进制数,然后斜杠后面的16代表前16位不能变,也就是172.16不能变,而后面的16位可以改变,所以斜杠后面的数字越大,那么子网范围就越小

55、青云开通服务器集群

我不用青云,我用自己本地虚拟机,不总结这块

56、CICD

56.1、DevOps概念

DevOps是Development和Operations的组合词,DevOps重视开发人员和运维人员的交互,然后通过自动化流程让软件构建、测试、发布更加便捷、频繁、可靠。
在这里插入图片描述

56.2、CICD概念

CICD简单来说就是持续集成、持续部署

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

57、CICD的指导实现

57.1、内循环与外循环

在这里插入图片描述
在这里插入图片描述

57.2、实践流程

在这里插入图片描述
在这里插入图片描述

57.3、CICD蓝图

在这里插入图片描述

58、jenkins简介与安装

59、jenkins安装完成

59.1、官方网址

59.2、安装jenkins

安装docker环境:

如果你的虚拟机没有安装docker环境,可以参考上面的13、Docker安装完成 来安装docker环境

下载jenkins镜像:

https://blog.csdn.net/qq_42449963/article/details/127470086

docker命令:

docker run \
-u root \
-d \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins-data:/var/jenkins_home \
-v /etc/localtime:/etc/localtime:ro \
-v /var/run/docker.sock:/var/run/docker.sock \
--restart=always \
jenkinsci/blueocean

命令解释:

  • -u root:以root用户身份运行镜像
  • -v:以具名卷方式挂载,详细了解请看上文29、Docker的-v挂载测试
  • -v jenkins-data:/var/jenkins_home:/var/jenkins_home目录中包含了jenkins的所有配置信息,所以需要挂载出来
  • -v /etc/localtime:/etc/localtime:ro:外国用的都是UTC时间,所以需要用我们的本地时间代替容器中的UTC时间,最后的ro代表read only,这样可以保证jenkins容器内时间运行正常;如果我们写Dockerfile制作镜像,那就需要使用把这些情况写在Dockerfile中
  • -v /var/run/docker.sock:/var/run/docker.sock:/var/run/docker.sock 表示Docker守护程序,用于监听基于Unix的套接字。 该映射允许 jenkinsci/blueocean 容器与Docker守护进程通信, 如果 jenkinsci/blueocean 容器需要实例化其他Docker容器,则该守护进程是必需的
  • –restart=always:不论发生什么原因,始终尝试重启,其实一般情况下作用就是虚拟机启动的时候就需要自动启动该容器
  • jenkinsci/blueocean:相比于传统的jenkins,多了一个blueocean,这种展示效更加好看

59.3、首次登录、插件安装

访问地址:

http://ip:port/8080/

在这里插入图片描述

获取管理员密码:

先通过docker ps找到启动好的jenkins容器,然后通过docker logs -f 容器id查看容器启动日志,操作如下:

在这里插入图片描述

回车之后结果如下:

在这里插入图片描述

插件安装:

将该字符串复制之后输入登录页面中点击继续按钮即可,然后就会让我们安装插件,我们选择安装推荐的插件即可,如下:

在这里插入图片描述

如果有安装失败的,尽量重试几次,如果还是无法下载,那就点击继续按钮吧,如果有些插件你是真的需要,可以在jenkins的插件管理里面在下载

创建第一个管理员用户:

我喜欢的用户名和密码一般都是root/123456,设置完成之后点击保存并完成即可,如下:

在这里插入图片描述

实例化配置:

一般使用默认值的就可以,其实就是访问地址,然后点击保存并完成即可

在这里插入图片描述
点击按钮重启jenkins:

在这里插入图片描述

即使重启完成,但是页面依然是加载中的状态,我们可以刷新浏览器页面,然后就可以看到登录页面了

59.4、正常登陆

输入用户名和密码之后点击登录按钮就可以登录了,比如我的用户名和密码就是root/123456

60、再绑一个公网IP

这节不总结

61、创建git项目和gitee建立连接

61.1、创建springboot项目

首先创建project:

在这里插入图片描述

然后创建springboot项目,如下:

在这里插入图片描述

创建过程中一般选择添加spring web、lombok等依赖,并且spring父工程版本尽量选2版本的,不要选3的,免得出错,然后随意写一个Controller,比如:

@RestController
public class TestController {
    @GetMapping("/devops")
    public String devops() {
        return "devops";
    }
}

另外可以根据自己的需求在application.properties/yml中设置一下server.port,也就是项目访问端口号,如下:

server.port=30001

61.2、推送项目到gitee

创建本地仓库:

在本地项目中创建git仓库,可以通过IDEAVCS下面的Create Git Repository……来创建,但是我这版的IDEA中没有该选项,所以只能通过下面的Terminal终端来使用git init来创建本地仓库了

在这里插入图片描述

在gitee中创建空仓库:

在这里插入图片描述

仓库创建完成是这个样子的,如下:

在这里插入图片描述

上图中就是git远程仓库地址,我们下面会用到的

将项目推送到gitee仓库:

对IDEA中的项目执行git addgit commit操作,如下:

在这里插入图片描述

设置远程仓库地址,这就是我们上面复制的git远程仓库地址,如下:

在这里插入图片描述

点击Push按钮推送本地仓库数据到远程仓库即可,如下:

在这里插入图片描述

62、jenkins文件的结构

62.1、新建流水线任务

新建任务:

在这里插入图片描述

给流水线起一个名字:

在这里插入图片描述

将gitee仓库设置成公开的,然后复制仓库地址:

在这里插入图片描述

填写初始化信息:

在这里插入图片描述

看下分支名称,以及gitee项目中的jenkinsfile文件名称和下图中的是否一致,都没问题的话点击保存按钮即可,如下:

在这里插入图片描述

62.2、编写Jenkinsfile文件

在项目根路径下创建Jenkinsfile文件(对应新建流水线任务时的Jenkinsfile文件名称)

在这里插入图片描述

Jenkinsfile文件内容如下:

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、编译
        // 注意:单引号:一般包括常量字符串,无法识别变量;双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来
        stage('编译') {
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
            }
        }

        // 2、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 3、打包
        stage('打包') {
            steps {
                echo '打包……'
            }
        }

        // 4、部署
        stage('部署') {
            steps {
                echo '部署……'
            }
        }
    }
}

我们把Jenkinsfile推送到gitee仓库中

在这里插入图片描述

在jenkins中找到上一步初始化的流水线任务,可以立即构建,可以通过Blue Ocean去运行,结果如下:

在这里插入图片描述

63、jenkins步骤生成器与环境变量

63.1、流水线语法

进入你的流水线任务,然后点击流水线语法,如下:

在这里插入图片描述

里面有片段生成器和过程声明器:

在这里插入图片描述

63.2、测试过程声明器的使用

使用过程声明器生成脚本,如下:

在这里插入图片描述
然后把脚本复制到上述java-devops-demo项目的Jenkinsfile文件中,如下:

在这里插入图片描述

变量写法需要注意:

  • 单引号:一般包括常量字符串,无法包裹变量
  • 双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,那么就可以被识别

然后我们将项目改变提交到Gitee中,然后在Jenkins中重新构建任务,输出结果如下:

在这里插入图片描述

64、jenkins其他简单的设置

64.1、在Jenkinsfile中写linux命令

点击流水线任务里面的流水线语法,如下:

在这里插入图片描述

在页面左侧选中片段生成器,然后选中sh生成方式,如下:

在这里插入图片描述

然后在文本框中输入shell脚本,之后点击生成流水线语法按钮,如下:

在这里插入图片描述

然后把shell脚本放在Jenkinsfile中,如下:

在这里插入图片描述

把Jenkinsfile传到Gitee中,然后在Jenkins中进行构建即可,效果如下图:

在这里插入图片描述

根据上步运行结果,我们还可以把printenv中的属性值打印出来,Jenkinsfile中需要添加如下内容:

在这里插入图片描述

最终在Jenkins中运行效果如下:

在这里插入图片描述

64.2、Jenkins中printenv命令打印的环境变量

常用环境变量:

  • WORKSPACE:工作空间,比如:/var/jenkins_home/workspace/java-devops-demo,其中每一个流水线任务都有一个工作空间
  • WORKSPACE_TMP:临时目录,比如:/var/jenkins_home/workspace/java-devops-demo@tmp,其中每一个流水线任务都有一个临时目录,存储流水线构建过程中的一些临时文件
  • JOB_URL:任务构建访问地址,比如:http://192.168.139.131:8080/job/java-devops-demo/,前面的ip和port可以通过Jenkins中系统管理》系统配置》Jenkins Location》Jenkins URL去设置
  • BUILD_NUMBER:已经构建的次数,即当前构建编号,比如:15

全部环境变量举例:

JENKINS_HOME=/var/jenkins_home

GIT_PREVIOUS_SUCCESSFUL_COMMIT=ac6eb8d76c8ae1b50cb5225c62470311338e5be6

JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental

CI=true

RUN_CHANGES_DISPLAY_URL=http://192.168.139.131:8080/job/java-devops-demo/15/display/redirect?page=changes

HOSTNAME=82a6b03774d6

LD_LIBRARY_PATH=/opt/java/openjdk/lib/server:/opt/java/openjdk/lib:/opt/java/openjdk/../lib

NODE_LABELS=built-in

HUDSON_URL=http://192.168.139.131:8080/

GIT_COMMIT=7b1264e417081269ea49ebd96d89513d891f247e

SHLVL=2

HOME=/root

BUILD_URL=http://192.168.139.131:8080/job/java-devops-demo/15/

HUDSON_COOKIE=06f60d19-0622-4c0d-b584-cb0dd06d35e0

JENKINS_SERVER_COOKIE=durable-08b2d13e1a43b2acce2dbe978130dabdc466cce60036ff8972bdd7a1aa0f16b0

JENKINS_UC=https://updates.jenkins.io

WORKSPACE=/var/jenkins_home/workspace/java-devops-demo

REF=/usr/share/jenkins/ref

NODE_NAME=built-in

RUN_ARTIFACTS_DISPLAY_URL=http://192.168.139.131:8080/job/java-devops-demo/15/display/redirect?page=artifacts

STAGE_NAME=编译

EXECUTOR_NUMBER=1

GIT_BRANCH=origin/master

JENKINS_VERSION=2.346.3

RUN_TESTS_DISPLAY_URL=http://192.168.139.131:8080/job/java-devops-demo/15/display/redirect?page=tests

JENKINS_INCREMENTALS_REPO_MIRROR=https://repo.jenkins-ci.org/incrementals

BUILD_DISPLAY_NAME=#15

HUDSON_HOME=/var/jenkins_home

JOB_BASE_NAME=java-devops-demo

PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

BUILD_ID=15

BUILD_TAG=jenkins-java-devops-demo-15

LANG=C.UTF-8

JENKINS_URL=http://192.168.139.131:8080/

JOB_URL=http://192.168.139.131:8080/job/java-devops-demo/

GIT_URL=https://toscode.gitee.com/mkdxm61/java-devops-demo.git

BUILD_NUMBER=15

JENKINS_NODE_COOKIE=4e20f893-eac7-443c-b282-b45b55a36952

RUN_DISPLAY_URL=http://192.168.139.131:8080/job/java-devops-demo/15/display/redirect

JENKINS_SLAVE_AGENT_PORT=50000

HUDSON_SERVER_COOKIE=df1a2dec263d5c01

JOB_DISPLAY_URL=http://192.168.139.131:8080/job/java-devops-demo/display/redirect

JOB_NAME=java-devops-demo

COPY_REFERENCE_FILE_LOG=/var/jenkins_home/copy_reference_file.log

JAVA_HOME=/opt/java/openjdk

PWD=/var/jenkins_home/workspace/java-devops-demo

GIT_PREVIOUS_COMMIT=ac6eb8d76c8ae1b50cb5225c62470311338e5be6

WORKSPACE_TMP=/var/jenkins_home/workspace/java-devops-demo@tmp

65、jenkins环境检查

我们目前从gitee中拿到了代码,但是我们把代码从gitee中拉取下来(需要git环境),然后把代码打成jar包(需要maven环境),并且未来要根据Dockerfile文件生成镜像(需要docker环境),所以需要检查一下相关环境,比如我们就检查一下java、git、docker、maven环境吧,在Jenkinsfile文件中添加脚本如下:

在这里插入图片描述

最终结果如下:

在这里插入图片描述
所以可以看出maven环境是缺乏的

66、gitee远程触发jenkins自动构建

66.1、生成用户token

选择系统管理:

在这里插入图片描述

点击安全》管理用户:

在这里插入图片描述

然后点击设置》添加新Token》生成按钮,如下:

在这里插入图片描述
复制token之后,点击应用和保存按钮,如下:

在这里插入图片描述

66.2、获取远程构建链接

进入项目之中,点击配置按钮,如下:
在这里插入图片描述
设置一个合适的令牌名称,如下:

在这里插入图片描述
回到刚才项目中的配置页面的身份验证令牌下面,复制远程触发链接,如下:

在这里插入图片描述
其中JENKINS_URL对应Jenkins中系统管理》系统配置》 Jenkins Location》Jenkins URL的值,一般都是Jenkins的ip和端口,如下:

在这里插入图片描述

然后webhook回调地址拼接方式是:

http://用户名:用户token@JENKINS_URLIP:JENKINS_URLPort/job/java-devops-demo/build?token=身份验证令牌

结合上一步生成的token(即:11631e11e42b9cbf6859819c41c057270c)、token对应用户名称(即:root)、本次身份验证令牌(即:mingkuaidexuanmi61)、本次远程回调链接(即:JENKINS_URL/job/java-devops-demo/build?token=TOKEN_NAME),可知本次webhook回调地址是:

http://root:11631e11e42b9cbf6859819c41c057270c@192.168.139.131:8080/job/java-devops-demo/build?token=mingkuaidexuanmi61

66.3、设置gitee中的webhook

添加webhook,如下:

在这里插入图片描述

将上面的webhook回调地址填入gitee中,如下:

在这里插入图片描述

后续我们就可以实现推送代码到gitee,然后gitee直接回调jenkins了,这样就不用我们去jenkins上手动构建了

67、Jenkins插件安装

67.1、每个阶段使用一个代理

对应链接:https://www.jenkins.io/zh/doc/book/pipeline/docker/

在这里插入图片描述

67.2、总流程中写agent none和agent any的区别

  • agent none:每一个stage都需要写agent才行
  • agent any:不需要每一个stage都需要写agent

67.3、更改jenkins插件镜像源

虽然不更改也行,但是更改成国内jenkins插件镜像源之后下载插件速度更快一点

点击系统管理按钮,如下:

在这里插入图片描述

点击插件管理按钮,如下:

在这里插入图片描述

点击高级按钮,如下:

在这里插入图片描述

然后把页面滑到最下方,使用https://jenkins-zh.gitee.io/update-center-mirror/tsinghua/update-center.json 或者 http://mirror.xmission.com/jenkins/updates/current/update-center.json替换掉升级站点URL下文本框中的内容,点击保存按钮,如下:

在这里插入图片描述

68、使用基础网络

青云配置,我不需要配置

69、jenkins插件安装

推荐安装插件列表:

在这里插入图片描述

70、自定义maven代理,使用自定义配置文件

我们需要使用maven来为项目打包,那就需要一个maven依赖,我们可以使用不同阶段使用不同容器的方式来完成效果,在项目Jenkinsfile文件中添加内容如下:

在这里插入图片描述
我们在运行jenkins容器的时候,使用Docker镜像代理的方式来为Jenkins容器在Linux虚拟机上启动了一个maven容器,不过maven容器依然可以使用jenkins容器的目录,所以我们把settings.xml放在jenkins的/var/jenkins_home/目录中,这样可以在移动jenkins的时候,直接将maven配置文件也移动了,并且我们已经把该目录挂载出来了,所以我们可以直接将整理好的settings.xml文件放在上述目录中,另外在settings.xml中需要指定仓库地址,我们也把仓库建立在jenkins的/var/jenkins_home/目录中,这样就可以循环利用仓库内容,其中settings.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  
    <localRepository>/var/jenkins_home/data/maven_repository</localRepository>

  <pluginGroups>
  </pluginGroups>

  <proxies>
  </proxies>

  <servers>
  </servers>
  <mirrors>
	
    <mirror>
	  <id>central</id>    
	  <name>central</name>      
	  <url>http://maven.aliyun.com/nexus/content/groups/public</url>   
	  <mirrorOf>central</mirrorOf>    
    </mirror>
	
  </mirrors>
  <profiles>
	<!-- 自己配置,目的是避免使用错误的jre版本 -->
	<profile>
	  <id>jdk-1.8</id>
	  
	  <activation>
		<activeByDefault>true</activeByDefault>
		<jdk>1.8</jdk>
	  </activation>

	  <properties>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
	  </properties>
	</profile>
  </profiles>
</settings>

画图分析上述内容如下所示:

在这里插入图片描述

我们来看一下执行效果吧,如下:

在这里插入图片描述
上述说明了我们使用放在jenkins/var/jenkins_home/目录中的settings.xmlmaven_repository。对于settings.xml来说,便于迁移jenkins的时候同步迁移maven配置文件。对于maven仓库来说,已经下载过的jar包就不需要在下载了,可以减少项目构建所花的时间。

以上是一种做法,另外一种做法是执行linux中的挂载位置,这种做法在迁移jenkins的时候容易忽略settings.xml,不建议使用,有兴趣的朋友可以去看容器的缓存数据

在这里插入图片描述

71、docker maven完全加速起来

改变maven本地仓库位置的目的:

在上一集视频中我们提到可以把maven容器的settings.xml和maven本地仓库都放在jenkins/var/jenkins_home/目录中,这样可以在移植jenkins的时候不用在单独操心maven的settings.xml配置文件,另外还可以让每次mvn clean package命令执行的时候可以利用上一次命令执行下载的jar包

对于maven容器的settings.xml,我这边没有什么异议,不过maven本地仓库我这边还是有异议的,上次我们把maven本地仓库也放在了jenkins/var/jenkins_home/目录中,这样造成一个问题是我们在迁移jenkins目录时还需要将maven本地仓库先删除,这样不太好

我们本次的做法是将maven本地仓库从jenkins/var/jenkins_home/目录中抽取出来,但是依然起到maven命令执行加速的作用(本次mvn clean package的命令执行可以利用到上次命令执行产生的maven本地仓库jar包)

改变maven本地仓库位置的方案:

改变settings.xml中的仓库位置,如下:

在这里插入图片描述

在IDEA的项目中Jenkinsfile文件中添加maven的挂载信息,如下:

在这里插入图片描述

Jenkinsfile提交到Gitee中,然后在Jenkins中构建即可,发现mvn clean package的执行时间也不长

72、简单Jenkins流水线完成

创建Dockerfile:

# 基础镜像
FROM  openjdk:8-jre-alpine
# 修改时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 复制打成的jar包
COPY /target/*.jar app.jar

# 定义参数
ENV JAVA_OPTS=""
ENV PARAMS=""

# 暴露端口,和springboot程序中的端口对应
EXPOSE 30001

# 启动命令
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS" ]

修改Jenkinsfile文件:

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息
    environment {
        WS = "${WORKSPACE}"
    }

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、环境检查
        // 注意:单引号:一般包括常量字符串,无法识别变量;
        //      双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,就可以被识别
        stage('环境检查') {
            steps {
                echo '环境检查……'
                sh 'java -version'
                sh 'git --version'
                sh 'docker version'
            }
        }

        // 2、编译
        stage('编译') {
            agent {
                docker {
                    image 'maven:3-alpine'
                    args '-v /data/maven/repository:/root/maven/repository'
                }
            }
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
                sh 'pwd & ls -alh'
                sh 'mvn --version'
                echo "当前工作目录:${WORKSPACE}"
                echo "常态工作目录:${WS}"
                /**
                 * 需要做:
                 *      每一个stage阶段都是从“常态工作目录”开始,但是部分阶段会进入临时目录,比如本次就是这种情况
                 * 我们需要在打包阶段也需要获取到target中的jar包,但是目前mvn clean package命令在
                 * 临时目录中执行,当我们进入“打包”阶段的时候不会发现打成的jar包,所以我们需要让mvn clean package
                 * 命令在“常态工作目录”中执行,然后进入“打包”阶段也能看到生成的jar包
                 *
                 * 怎么做:
                 *      我们先进入“常态工作目录”,然后执行“mvn clean package”命令,我们不能在该阶段中通过
                 *  ${WORKSPACE}获取工作目录,毕竟当前工作目录是临时目录,所以我们在上面“定义环境信息”处已经
                 *  记录了“常态工作目录”的路径,所以我们在这里使用就ok了
                 *      由于每一行指令都是基于“当前工作目录”,所以必须将“cd ${WS}”和后面的指令写在一行,否则
                 *  执行位置就不正确了
                 */
                sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/config/maven/settings.xml" -Dmaven.test.skip=true && pwd && ls -alh'
            }
        }

        // 3、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 4、打包
        stage('打包') {
            steps {
                echo '打包……'
                sh 'pwd & ls -alh'
                sh 'docker rmi -f java-devops-demo'
                sh 'docker build -t java-devops-demo -f Dockerfile .'
            }
        }

        // 5、部署
        stage('部署') {
            steps {
                echo '部署……'
                sh 'docker rm -f java-devops-demo-item'
                sh 'docker run -d -P --name=java-devops-demo-item java-devops-demo'
                sh 'docker ps | grep java-devops-demo-item'
            }
        }
    }
}
  • 修改环境信息:添加WS = "${WORKSPACE}",用以存储常态工作空间,让mvn clean package可以在常态工作空间执行
  • 修改编译阶段:主要做的是切换mvn clean package的执行位置为常态工作空间
  • 添加打包阶段:其中执行docker rmi -f java-devops-demo的作用是删除以往的镜像,避免出现虚悬镜像
  • 添加部署阶段:其中执行docker rm -f java-devops-demo-item的作用是删除正在运行的容器,然后docker run命令的作用是按照后台方式运行容器,并且以随机端口形式暴露Dockerfile中的端口

73、发送邮件通知

73.1、后置阶段的使用

查找位置:

在这里插入图片描述

用在stage中:

说明:如果本阶段成功,那就打印成功,否则就打印失败,当然也可以在成功或者失败里面做其他事情

stage('打包') {
    steps {
        echo '打包……'
        sh 'pwd & ls -alh'
        sh 'docker rmi -f java-devops-demo'
        sh 'docker build -t java-devops-demo -f Dockerfile .'
    }

    // 后置执行
    post {
        // 成功
        success {
            echo '成功'
        }
        // 失败
        failure {
            echo '失败'

        }
    }
}

效果截图:

在这里插入图片描述
用在pipeline中:

说明:如果所有阶段都成功,那就在最后一个阶段的最后打印成功,有任何一个阶段失败,那就会打印失败,当然也可以在成功或者失败里面做其他事情

pipeline {
    ……………………

    // 后置执行
    post {
        // 成功
        success {
            echo '成功'
        }
        // 失败
        failure {
            echo '失败'

        }
    }
}

73.2、完成邮件发送功能

73.2.1、获取邮箱授权码

我的邮箱是QQ邮箱,所以肯定去QQ邮箱官网查找授权码了,具体方式是登录QQ邮箱,然后按照如下方式获取授权码,比如我的就是:bxyxzwlsizpaecah

在这里插入图片描述

73.2.1、配置系统管理员邮件地址

进入Jenkins,然后点击系统管理》系统配置,然后找到系统管理员邮件地址,配置一个邮件地址,如下:

在这里插入图片描述

73.2.3、配置 Extended E-mail Notification

进入Jenkins,然后点击系统管理》系统配置,然后找到 Extended E-mail Notification,配置如下内容

Credentials信息的填写需要点击高级按钮才会出现奥

在这里插入图片描述

我们先说一下上面SMTP serverSMTP Port的内容是从哪里来的,它们来自于QQ邮箱官网,具体位置如下:

在这里插入图片描述

然后找到如下位置:

在这里插入图片描述

我们说一下上面的添加按钮吧,它可以用来添加邮箱用户和授权码信息,点击添加按钮之后填写如下内容:

在这里插入图片描述
添加完成后就可以在Credentials下面去选中刚才添加的邮箱连接信息了,现在我们继续往下说

配置发送内容为html格式,如下:

在这里插入图片描述

73.2.4、配置邮件通知

进入Jenkins,然后点击系统管理》系统配置,然后找到邮件通知,配置如下内容

在这里插入图片描述

配置完成之后可以测试一下连通情况,如下:

在这里插入图片描述

没有问题记得应用和保存

73.2.5、获取邮件Html模板

我是直接使用https://blog.csdn.net/shenshenruoxi/article/details/106222851里面的模板,具体内容是:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${PROJECT_NAME}-第${BUILD_NUMBER}次构建日志</title>
</head>
 
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
    offset="0">
    <table width="95%" cellpadding="0" cellspacing="0"
        style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
        <tr>
            <td>(本邮件是程序自动下发的,请勿回复!)<br/></td>
        </tr>
        <tr>
            <td><h2>
                    <font color="#0000FF">构建结果 - ${BUILD_STATUS}</font>
                </h2></td>
        </tr>
        <tr>
            <td><br />
            <b><font color="#0B610B">构建信息</font></b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>
                <ul>
                    <li>项目名称 : ${PROJECT_NAME}</li>
                    <li>构建编号 : 第${BUILD_NUMBER}次构建</li>
                    <li>触发原因: ${CAUSE}</li>
                    <li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                    <li>构建  Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
                    <li>工作目录 : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>                   
                </ul>
            </td>
        </tr>        
        <tr>
            <td></td>
        </tr>
        <tr>
            <td><b><font color="#0B610B">构建情况总览:</font></b>${TEST_COUNTS,var="fail"}<br/>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td><pre cols="160" rows="80" 
                    style="font-family: Courier New">${BUILD_LOG,maxLines=250}</pre>
            </td>
        </tr>
    </table>
</body>
</html>

73.2.6、获取Jenkinsfile中需要填写的内容

在Jenkins中进入对应的流水线任务,点击流水线语法按钮,执行如下操作:

在这里插入图片描述
然后将内容复制到IDEA中Jenkinsfile中,大家只用看邮件通知即可,如下:

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息
    environment {
        WS = "${WORKSPACE}"
    }

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、环境检查
        // 注意:单引号:一般包括常量字符串,无法识别变量;
        //      双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,就可以被识别
        stage('环境检查') {
            steps {
                echo '环境检查……'
                sh 'java -version'
                sh 'git --version'
                sh 'docker version'
            }
        }

        // 2、编译
        stage('编译') {
            agent {
                docker {
                    image 'maven:3-alpine'
                    args '-v /data/maven/repository:/root/maven/repository'
                }
            }
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
                sh 'pwd & ls -alh'
                sh 'mvn --version'
                echo "当前工作目录:${WORKSPACE}"
                echo "常态工作目录:${WS}"
                /**
                 * 需要做:
                 *      每一个stage阶段都是从“常态工作目录”开始,但是部分阶段会进入临时目录,比如本次就是这种情况
                 * 我们需要在打包阶段也需要获取到target中的jar包,但是目前mvn clean package命令在
                 * 临时目录中执行,当我们进入“打包”阶段的时候不会发现打成的jar包,所以我们需要让mvn clean package
                 * 命令在“常态工作目录”中执行,然后进入“打包”阶段也能看到生成的jar包
                 *
                 * 怎么做:
                 *      我们先进入“常态工作目录”,然后执行“mvn clean package”命令,我们不能在该阶段中通过
                 *  ${WORKSPACE}获取工作目录,毕竟当前工作目录是临时目录,所以我们在上面“定义环境信息”处已经
                 *  记录了“常态工作目录”的路径,所以我们在这里使用就ok了
                 *      由于每一行指令都是基于“当前工作目录”,所以必须将“cd ${WS}”和后面的指令写在一行,否则
                 *  执行位置就不正确了
                 */
                sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/config/maven/settings.xml" -Dmaven.test.skip=true && pwd && ls -alh'
            }
        }

        // 3、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 4、打包
        stage('打包') {
            steps {
                echo '打包……'
                sh 'pwd & ls -alh'
                sh 'docker rmi -f java-devops-demo'
                sh 'docker build -t java-devops-demo -f Dockerfile .'
            }

            // 后置执行
            post {
                // 成功
                success {
                    // One or more steps need to be included within each condition's block.
                    echo '成功'
                }
                // 失败
                failure {
                    // One or more steps need to be included within each condition's block.
                    echo '失败'

                }
            }
        }

        // 5、部署
        stage('部署') {
            steps {
                echo '部署……'
                sh 'docker rm -f java-devops-demo-item'
                sh 'docker run -d -P --name=java-devops-demo-item java-devops-demo'
                sh 'docker ps | grep java-devops-demo-item'
            }
        }

        // 6、邮件通知
        stage('邮件通知') {
            steps {
                echo '邮件通知……'
                emailext body: '''<!DOCTYPE html>
                <html>
                <head>
                <meta charset="UTF-8">
                <title>${PROJECT_NAME}-第${BUILD_NUMBER}次构建日志</title>
                </head>
                 
                <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
                    offset="0">
                    <table width="95%" cellpadding="0" cellspacing="0"
                        style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
                        <tr>
                            <td>(本邮件是程序自动下发的,请勿回复!)<br/></td>
                        </tr>
                        <tr>
                            <td><h2>
                                    <font color="#0000FF">构建结果 - ${BUILD_STATUS}</font>
                                </h2></td>
                        </tr>
                        <tr>
                            <td><br />
                            <b><font color="#0B610B">构建信息</font></b>
                            <hr size="2" width="100%" align="center" /></td>
                        </tr>
                        <tr>
                            <td>
                                <ul>
                                    <li>项目名称 : ${PROJECT_NAME}</li>
                                    <li>构建编号 : 第${BUILD_NUMBER}次构建</li>
                                    <li>触发原因: ${CAUSE}</li>
                                    <li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                                    <li>构建  Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
                                    <li>工作目录 : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>                   
                                </ul>
                            </td>
                        </tr>        
                        <tr>
                            <td></td>
                        </tr>
                        <tr>
                            <td><b><font color="#0B610B">构建情况总览:</font></b>${TEST_COUNTS,var="fail"}<br/>
                            <hr size="2" width="100%" align="center" /></td>
                        </tr>
                        <tr>
                            <td><pre cols="160" rows="80" 
                                    style="font-family: Courier New">${BUILD_LOG,maxLines=250}</pre>
                            </td>
                        </tr>
                    </table>
                </body>
                </html>
                ''', subject: '${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志', to: '2746711685@qq.com'
            }
        }
    }
}

最终执行结果是正确的,这是Jenkins的执行结果

在这里插入图片描述
这是接收到的邮件内容

在这里插入图片描述

73.3、如何在Jenkinsfile中把消息通过短信形式发送到手机,或者发送到微信、钉钉、飞书等

各大平台都支持curl方式的内容发送,所以我们可以通过以下方式把信息发给其他用户

sh "curl XXX"

74、CICD还能做什么?

74.1、推送镜像到阿里云镜像仓库

74.1.1、推送目的

如果是单个虚拟机上装docker、k8s、jenkins还好,如果是多个机器呢,那我们未来使用k8s的yaml文件进行构建的时候可能本地没有最新镜像,那我们就需要从镜像仓库中下载,并且我们构建的镜像总要有一个位置去存储它,不可能让他一直在jenkins所在虚拟机中,这也不利于版本维护,目前我们测试推送镜像到阿里云镜像仓库,后续在k8s中我们将通过Jenkinsfile文件把生成的镜像推送到harbor仓库中,然后在k8s通过yaml部署项目的时候就可以从harbor中拉取最新镜像

74.1.2、新建阿里云账号信息

首先需要登录阿里云,然后点击控制台,如下:

在这里插入图片描述

然后找到容器镜像服务,如下:

在这里插入图片描述

然后点击实例列表中的个人版,没开通的记得开通下,如下:

在这里插入图片描述

依次点击仓库管理》镜像仓库》创建镜像仓库,如下:

在这里插入图片描述

在弹窗中填写如下信息:

在这里插入图片描述

然后创建本地仓库即可,如下:

在这里插入图片描述

创建完成后就可以进入镜像仓库的基本信息页面,如下:

在这里插入图片描述

上图中那几个将镜像推送到仓库的步骤等会我们往阿里云镜像仓库推送镜像的时候会用到

74.1.3、设置阿里云账号信息

在阿里云的容器镜像服务中,点击实例列表中的个人版,之后设置一个阿里云镜像仓库连接密码

在这里插入图片描述

74.1.4、在jenkins中配置阿里云镜像仓库的用户名和密码连接信息

首先进入jenkins中,然后先进入用户名和密码添加页面,如下:

在这里插入图片描述
按照以下步骤进入用户名和密码设置页面,如下:

在这里插入图片描述
在这里插入图片描述

然后填写阿里云镜像仓库的连接信息,如下:

在这里插入图片描述
在这里插入图片描述

74.1.5、更改Jenkinsfile

74.1.5.1、使用阿里云镜像仓库的第1种连接方式
  • environment中可以看到ALIYUN_DOCKER_REPO = credentials('aliyun-docker-repo')
    首先aliyun-docker-repo就是我们上面设置的阿里云镜像仓库连接信息的ID,就在上面那张图片里面,我就不粘贴图片了
    ALIYUN_DOCKER_REPO = credentials('aliyun-docker-repo')这种写法来自于https://www.jenkins.io/zh/doc/book/pipeline/syntax/#environment,另外这种写法将会产生两个额外变量,也就是ALIYUN_DOCKER_REPO_USR(用户名)ALIYUN_DOCKER_REPO_PSW(密码),其实也就是在变量的基础上添加了_USR_PSW,这是Jenkins规定的方式,截图如下:
    在这里插入图片描述

  • stage('推送镜像')中用到的命令来自于阿里云,除了登录命令需要设置用户名和密码,这和阿里云的设置不一样,其他都是一样的

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息
    environment {
        WS = "${WORKSPACE}"
        // 阿里云连接信息
        ALIYUN_DOCKER_REPO = credentials('aliyun-docker-repo')
    }

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、环境检查
        // 注意:单引号:一般包括常量字符串,无法识别变量;
        //      双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,就可以被识别
        stage('环境检查') {
            steps {
                echo '环境检查……'
                sh 'java -version'
                sh 'git --version'
                sh 'docker version'
            }
        }

        // 2、编译
        stage('编译') {
            agent {
                docker {
                    image 'maven:3-alpine'
                    args '-v /data/maven/repository:/root/maven/repository'
                }
            }
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
                sh 'pwd & ls -alh'
                sh 'mvn --version'
                echo "当前工作目录:${WORKSPACE}"
                echo "常态工作目录:${WS}"
                /**
                 * 需要做:
                 *      每一个stage阶段都是从“常态工作目录”开始,但是部分阶段会进入临时目录,比如本次就是这种情况
                 * 我们需要在打包阶段也需要获取到target中的jar包,但是目前mvn clean package命令在
                 * 临时目录中执行,当我们进入“打包”阶段的时候不会发现打成的jar包,所以我们需要让mvn clean package
                 * 命令在“常态工作目录”中执行,然后进入“打包”阶段也能看到生成的jar包
                 *
                 * 怎么做:
                 *      我们先进入“常态工作目录”,然后执行“mvn clean package”命令,我们不能在该阶段中通过
                 *  ${WORKSPACE}获取工作目录,毕竟当前工作目录是临时目录,所以我们在上面“定义环境信息”处已经
                 *  记录了“常态工作目录”的路径,所以我们在这里使用就ok了
                 *      由于每一行指令都是基于“当前工作目录”,所以必须将“cd ${WS}”和后面的指令写在一行,否则
                 *  执行位置就不正确了
                 */
                sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/config/maven/settings.xml" -Dmaven.test.skip=true && pwd && ls -alh'
            }
        }

        // 3、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 4、打包
        stage('打包') {
            steps {
                echo '打包……'
                sh 'pwd & ls -alh'
                // 删除最新镜像
                sh 'docker rmi -f java-devops-demo'
                // 删除该版本镜像,避免产生虚悬镜像
                sh 'docker rmi -f java-devops-demo:v1.0'
                // 删除改名的镜像,避免产生虚悬镜像
                sh 'docker rmi -f registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0'
                // 构建镜像
                sh 'docker build -t java-devops-demo -f Dockerfile .'
            }
        }

        // 5、推送镜像
        stage('推送镜像') {
            steps {
                echo '推送镜像……'
                sh "docker login -u ${ALIYUN_DOCKER_REPO_USR} -p ${ALIYUN_DOCKER_REPO_PSW} registry.cn-hangzhou.aliyuncs.com"
                sh "docker tag java-devops-demo registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0"
                sh "docker push registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0"
            }
        }
    }
}
74.1.5.2、使用阿里云镜像仓库的第2种连接方式

推送镜像中,大家可以看到如下结构:

withCredentials([usernamePassword(credentialsId: 'aliyun-docker-repo', passwordVariable: 'aliyun_docker_pwd', usernameVariable: 'aliyun_docker_usr')]) {
    XXX
}

这种结构来自于Jenkins流水线语法,我们可以进入单个项目,然后点击左侧的流水线语法,之后选择如下选项:

在这里插入图片描述

之后我们在绑定下面点击新增按钮,选择最后一个选项,用来分别生成用户名称和用户密码,然后我们给用户名和用户密码取个名字,分别是aliyun_docker_usraliyun_docker_pwd

可以看上面的代码,其中aliyun-docker-repo是阿里云镜像仓库连接信息的ID,这个上面是说过的,然后aliyun_docker_usraliyun_docker_pwd就是我们为阿里云镜像仓库连接信息取的名字

只要把代码写在withCredentials方法里面,就可以把aliyun_docker_usraliyun_docker_pwd当做变量来使用

在这里插入图片描述

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息
    environment {
        WS = "${WORKSPACE}"
    }

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、环境检查
        // 注意:单引号:一般包括常量字符串,无法识别变量;
        //      双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,就可以被识别
        stage('环境检查') {
            steps {
                echo '环境检查……'
                sh 'java -version'
                sh 'git --version'
                sh 'docker version'
            }
        }

        // 2、编译
        stage('编译') {
            agent {
                docker {
                    image 'maven:3-alpine'
                    args '-v /data/maven/repository:/root/maven/repository'
                }
            }
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
                sh 'pwd & ls -alh'
                sh 'mvn --version'
                echo "当前工作目录:${WORKSPACE}"
                echo "常态工作目录:${WS}"
                /**
                 * 需要做:
                 *      每一个stage阶段都是从“常态工作目录”开始,但是部分阶段会进入临时目录,比如本次就是这种情况
                 * 我们需要在打包阶段也需要获取到target中的jar包,但是目前mvn clean package命令在
                 * 临时目录中执行,当我们进入“打包”阶段的时候不会发现打成的jar包,所以我们需要让mvn clean package
                 * 命令在“常态工作目录”中执行,然后进入“打包”阶段也能看到生成的jar包
                 *
                 * 怎么做:
                 *      我们先进入“常态工作目录”,然后执行“mvn clean package”命令,我们不能在该阶段中通过
                 *  ${WORKSPACE}获取工作目录,毕竟当前工作目录是临时目录,所以我们在上面“定义环境信息”处已经
                 *  记录了“常态工作目录”的路径,所以我们在这里使用就ok了
                 *      由于每一行指令都是基于“当前工作目录”,所以必须将“cd ${WS}”和后面的指令写在一行,否则
                 *  执行位置就不正确了
                 */
                sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/config/maven/settings.xml" -Dmaven.test.skip=true && pwd && ls -alh'
            }
        }

        // 3、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 4、打包
        stage('打包') {
            steps {
                echo '打包……'
                sh 'pwd & ls -alh'
                // 删除最新镜像
                sh 'docker rmi -f java-devops-demo'
                // 删除该版本镜像,避免产生虚悬镜像
                sh 'docker rmi -f java-devops-demo:v1.0'
                // 删除改名的镜像,避免产生虚悬镜像
                sh 'docker rmi -f registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0'
                // 构建镜像
                sh 'docker build -t java-devops-demo -f Dockerfile .'
            }
        }

        // 5、推送镜像
        stage('推送镜像') {
            steps {
                echo '推送镜像……'
                withCredentials([usernamePassword(credentialsId: 'aliyun-docker-repo', passwordVariable: 'aliyun_docker_pwd', usernameVariable: 'aliyun_docker_usr')]) {
                    sh "docker login -u ${aliyun_docker_usr} -p ${aliyun_docker_pwd} registry.cn-hangzhou.aliyuncs.com"
                    sh "docker tag java-devops-demo registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0"
                    sh "docker push registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0"
                }
            }
        }
    }
}

74.2、input语法—手动确认

74.2.1、input语法说明

首先我们先说一下input手动确认的意义,比如现在有一些参数无法确定,需要在运行的时候执行,那就需要用到input手动确定了

然后我们来看一下官方的input语法地址https://www.jenkins.io/zh/doc/book/pipeline/syntax/#input,相关的解释也是有说明的

接下来我们来说明一下input语法的生成情况,首先我们在jenkins中找到对应项目,然后进入项目,之后打开项目左侧的流水线语法,如下:

在这里插入图片描述

然后点击左侧的Declarative Directive Generator,之后在右侧点击input:input,如下:

在这里插入图片描述

我们在消息中输入交互式输入的标题,输入完成后点击下面的高级…按钮,如下:

在这里插入图片描述

然后起一个确认按钮标题的名称,如下:

在这里插入图片描述

点击新增按钮,我们先来说一个文本参数的写法,如下:

在这里插入图片描述

下面的镜像版本IMAGE_VERSION是给我们脚本中用的,默认版本是不填的时候用的,提示信息是给用户看的,如下:

在这里插入图片描述

然后我们再来说一个可以选择框的情况,点击新增按钮,点击选项参数,如下:

在这里插入图片描述

然后填写相关内容,如下:

在这里插入图片描述

74.2.2、Jenkinsfile脚本

大家直接去看里面的input语法就好

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息
    environment {
        WS = "${WORKSPACE}"
    }

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、环境检查
        // 注意:单引号:一般包括常量字符串,无法识别变量;
        //      双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,就可以被识别
        stage('环境检查') {
            steps {
                echo '环境检查……'
                sh 'java -version'
                sh 'git --version'
                sh 'docker version'
            }
        }

        // 2、编译
        stage('编译') {
            agent {
                docker {
                    image 'maven:3-alpine'
                    args '-v /data/maven/repository:/root/maven/repository'
                }
            }
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
                sh 'pwd & ls -alh'
                sh 'mvn --version'
                echo "当前工作目录:${WORKSPACE}"
                echo "常态工作目录:${WS}"
                /**
                 * 需要做:
                 *      每一个stage阶段都是从“常态工作目录”开始,但是部分阶段会进入临时目录,比如本次就是这种情况
                 * 我们需要在打包阶段也需要获取到target中的jar包,但是目前mvn clean package命令在
                 * 临时目录中执行,当我们进入“打包”阶段的时候不会发现打成的jar包,所以我们需要让mvn clean package
                 * 命令在“常态工作目录”中执行,然后进入“打包”阶段也能看到生成的jar包
                 *
                 * 怎么做:
                 *      我们先进入“常态工作目录”,然后执行“mvn clean package”命令,我们不能在该阶段中通过
                 *  ${WORKSPACE}获取工作目录,毕竟当前工作目录是临时目录,所以我们在上面“定义环境信息”处已经
                 *  记录了“常态工作目录”的路径,所以我们在这里使用就ok了
                 *      由于每一行指令都是基于“当前工作目录”,所以必须将“cd ${WS}”和后面的指令写在一行,否则
                 *  执行位置就不正确了
                 */
                sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/config/maven/settings.xml" -Dmaven.test.skip=true && pwd && ls -alh'
            }
        }

        // 3、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 4、打包
        stage('打包') {
            steps {
                echo '打包……'
                sh 'pwd & ls -alh'
                // 删除最新镜像
                sh 'docker rmi -f java-devops-demo'
                // 删除该版本镜像,避免产生虚悬镜像
                sh 'docker rmi -f java-devops-demo:v1.0'
                // 删除改名的镜像,避免产生虚悬镜像
                sh 'docker rmi -f registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0'
                // 构建镜像
                sh 'docker build -t java-devops-demo -f Dockerfile .'
            }
        }

        // 5、推送镜像
        stage('推送镜像') {
            input {
                message '需要推送镜像到阿里云仓库吗?'
                ok '需要'
                parameters {
                    text defaultValue: 'v1.0', description: '生产环境需要部署的版本', name: 'IMAGE_VERSION'
                    choice choices: ['华东区', '华南区', '华中区', '华北区'], description: '部署大区', name: 'DEPLOY_WHERE'
                }
            }
            steps {
                echo '推送镜像……'
                echo "注意:服务将被部署到“${DEPLOY_WHERE}”"
                withCredentials([usernamePassword(credentialsId: 'aliyun-docker-repo', passwordVariable: 'aliyun_docker_pwd', usernameVariable: 'aliyun_docker_usr')]) {
                    sh "docker login -u ${aliyun_docker_usr} -p ${aliyun_docker_pwd} registry.cn-hangzhou.aliyuncs.com"
                    sh "docker tag java-devops-demo registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:${IMAGE_VERSION}"
                    sh "docker push registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:${IMAGE_VERSION}"
                }
            }
        }
    }
}

然后我们来看下jenkins流水线的运行截图,如下:

在这里插入图片描述

74.3、script语法

下面的Jenkinsfile中只是简单说了script语法,里面介绍了if else if else的用法,其实script语法可以帮助我们做的事情非常多,比如多分支流水线构建等,如下:

// 写流水线的脚本(常用:声明式、脚本式)
pipeline {
    // 全部CICD流程都需要在这里定义

    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any

    // 定义环境信息
    environment {
        WS = "${WORKSPACE}"
    }

    // 定义流水线加工流程,定义流水线所有阶段
    stages {
        // 定义阶段
        // 1、环境检查
        // 注意:单引号:一般包括常量字符串,无法识别变量;
        //      双引号:可以用来包括常量字符串和变量,其中变量以$开头,或者用${}包裹起来,就可以被识别
        stage('环境检查') {
            steps {
                echo '环境检查……'
                sh 'java -version'
                sh 'git --version'
                sh 'docker version'
            }
        }

        // 2、编译
        stage('编译') {
            agent {
                docker {
                    image 'maven:3-alpine'
                    args '-v /data/maven/repository:/root/maven/repository'
                }
            }
            // 定义步骤
            steps {
                // 要做的所有事情
                echo '编译……'
                sh 'pwd & ls -alh'
                sh 'mvn --version'
                echo "当前工作目录:${WORKSPACE}"
                echo "常态工作目录:${WS}"
                /**
                 * 需要做:
                 *      每一个stage阶段都是从“常态工作目录”开始,但是部分阶段会进入临时目录,比如本次就是这种情况
                 * 我们需要在打包阶段也需要获取到target中的jar包,但是目前mvn clean package命令在
                 * 临时目录中执行,当我们进入“打包”阶段的时候不会发现打成的jar包,所以我们需要让mvn clean package
                 * 命令在“常态工作目录”中执行,然后进入“打包”阶段也能看到生成的jar包
                 *
                 * 怎么做:
                 *      我们先进入“常态工作目录”,然后执行“mvn clean package”命令,我们不能在该阶段中通过
                 *  ${WORKSPACE}获取工作目录,毕竟当前工作目录是临时目录,所以我们在上面“定义环境信息”处已经
                 *  记录了“常态工作目录”的路径,所以我们在这里使用就ok了
                 *      由于每一行指令都是基于“当前工作目录”,所以必须将“cd ${WS}”和后面的指令写在一行,否则
                 *  执行位置就不正确了
                 */
                sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/config/maven/settings.xml" -Dmaven.test.skip=true && pwd && ls -alh'
            }
        }

        // 3、测试
        stage('测试') {
            steps {
                echo '测试……'
            }
        }

        // 4、打包
        stage('打包') {
            steps {
                echo '打包……'
                sh 'pwd & ls -alh'
                // 删除最新镜像
                sh 'docker rmi -f java-devops-demo'
                // 删除该版本镜像,避免产生虚悬镜像
                sh 'docker rmi -f java-devops-demo:v1.0'
                // 删除改名的镜像,避免产生虚悬镜像
                sh 'docker rmi -f registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:v1.0'
                // 构建镜像
                sh 'docker build -t java-devops-demo -f Dockerfile .'
            }
        }

        // 5、推送镜像
        stage('推送镜像') {
            input {
                message '需要推送镜像到阿里云仓库吗?'
                ok '需要'
                parameters {
                    text defaultValue: 'v1.0', description: '生产环境需要部署的版本', name: 'IMAGE_VERSION'
                    choice choices: ['华东区', '华南区', '华中区', '华北区'], description: '部署大区', name: 'DEPLOY_WHERE'
                }
            }
            steps {
                echo '推送镜像……'
                script {
                    // groovy语法
                    def where = "${DEPLOY_WHERE}"
                    if (where == "华东区") {
                        echo "注意:服务将被部署到“${DEPLOY_WHERE}”"
                    } else if(where == "华南区") {
                        echo "注意:服务将被部署到“${DEPLOY_WHERE}”"
                    } else if(where == "华中区") {
                        echo "注意:服务将被部署到“${DEPLOY_WHERE}”"
                    } else if(where == "华北区") {
                        echo "注意:服务将被部署到“${DEPLOY_WHERE}”"
                        withCredentials([usernamePassword(credentialsId: 'aliyun-docker-repo', passwordVariable: 'aliyun_docker_pwd', usernameVariable: 'aliyun_docker_usr')]) {
                            sh "docker login -u ${aliyun_docker_usr} -p ${aliyun_docker_pwd} registry.cn-hangzhou.aliyuncs.com"
                            sh "docker tag java-devops-demo registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:${IMAGE_VERSION}"
                            sh "docker push registry.cn-hangzhou.aliyuncs.com/mingkuaidexuanmi61/java-devops-demo:${IMAGE_VERSION}"
                        }
                    } else {
                        sh "注意:没有合适的部署地点"
                    }
                }
            }
        }
    }
}

具体效果如下:

在这里插入图片描述

75、其他问题

没啥需要总结的

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值