docker安装+配置镜像+命令操作+数据卷+网络管理+DockerFile+镜像服务+项目部署+[高级使用]

文章目录

Docker基础

一、Docker介绍

1. 什么是虚拟化

在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。这些资源的新虚拟部份是不受现有资源的架设方式,地域或物理组态所限制。一般所指的虚拟化资源包括计算能力和资料存储。

在实际的生产环境中,虚拟化技术主要用来解决高性能的物理硬件产能过剩和老的旧的硬件产能过低的重组重用,透明化底层物理硬件,从而最大化的利用物理硬件 对资源充分利用

虚拟化技术种类很多,例如:软件虚拟化、硬件虚拟化、内存虚拟化、网络虚拟化(vip)、桌面虚拟化、服务虚拟化、虚拟机等等。

2. 什么是Docker

Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。Docker项目后来加入了 Linux 基金会,并成立推动 开放容器联(OCI)。

其基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker技术比虚拟机技术更为轻便、快捷。

3. 容器与虚拟机比较

容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。

虚拟机: 虚拟机是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;

image-20210613174154630

**Docker:Docker没有虚拟的硬件,也没有模拟操作系统,而是直接运行在宿主机上。**Docker会为每个应用进程形成隔离环境,让的应用进程以为自己是独立机器。因此Docker要比传统虚拟机更为轻便。

image-20210613174212415

4. Docker优势

与传统的虚拟机相比,Docker优势体现为启动速度快、占用体积小。

特性Docker容器虚拟机
启动秒级分钟级
硬盘使用一般为 MB一般为 GB
性能接近原生弱于
系统支持量单机支持上千个容器一般几十个

5. Docker架构

Docker是一个客户端-服务器(C/S)架构程序。Docker客户端(client)只需要向Docker服务器或者后台进程发出请求,服务器或者后台进程将完成所有工作并返回结果。

Docker中有三个很重要的概念:

  • 镜像(Image
  • 容器(Container
  • 仓库(Repository

理解了这三个概念,就理解了 Docker 的整个生命周期。

image-20200701203056621
【1】镜像服务(Image

Linux的操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。

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

**Docker 镜像是一个特殊的文件系统,**除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变,是一个只读的模板

简单来说:镜像就像你下载并安装好的一个游戏,比如《我的世界》,其中包含了运行所需要的jre库。因此这个游戏可以放到任何机器上运行。

镜像服务: 
		管理存放镜像的位置,用于共享镜像文件
    官方: https://hub.docker.com/
		阿里: https://www.aliyun.com/
仓库:
		每一种软件对应一个仓库,在仓库中存放有当前软件不同版本的各个镜像
    不同版本使用tag区分
    eg: 
				mysql:5.6  mysql:5.7.25   
【2】容器(Container

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

容器的实质是进程,但与直接在宿主执行的进程不同,Docker会保证隔离每一个容器进程

容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。**这种特性使得容器封装的应用比直接在宿主运行更加安全。**也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。

【3】镜像仓库(Docker Registry

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个 仓库Repository);每个仓库可以包含多个 标签Tag);每个标签对应一个版本的镜像。

通常,一个仓库(Repository)会包含同一个软件不同版本的镜像(image),而标签(Tag)就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

以Nginx镜像为例。我们可以通过 nginx:1.7.9,或者 nginx:1.8.0 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 nginx,那将视为 nginx:latest最新版本的。

仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。

最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像,供用户下载。国内也有一些云服务商提供类似于 Docker Hub 的公开服务。

比如 网易云镜像服务DaoCloud 镜像市场阿里云镜像库 等。

除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。

当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。

6. 直击Docker的作用

技术存在的必然性,一个技术的存在都是为了解决指定的问题.
    
#什么是镜像?
	将Linux程序基于运行环境打包,就是镜像,特征:
			只读
			分层,每一层都基于前一层,层称为Layer
#什么是容器?
	容器是镜像运行的一个实例。
	是将镜像做只读拷贝后创建一层可写的Layer层,然后创建独立内存、网络等空间并运行。
	特征:
			容器是宿主机的一个独立进程。
			多个容器间相互独立
			容器操作不影响镜像
#Docker作用?
	软件或程序环境迁移

image-20210610090947848

image-20210610101647993

二、Docker安装与配置

Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。

Docker CE 分为 stable test nightly 三个更新频道。

官方网站上有各种环境下的 安装指南,这里主要介绍 Docker CE 在 LinuxmacOS 上的安装。

Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10, CentOS 7 满足最低内核的要求。

1. 卸载旧版docker

这里的 \ 是换行的作用

yum remove docker \
   docker-client \
   docker-client-latest \
   docker-common \
   docker-latest \
   docker-latest-logrotate \
   docker-logrotate \
   docker-selinux \
   docker-engine-selinux \
   docker-engine \
   docker-ce

2. 安装docker依赖

# 安装基本依赖库
yum install -y yum-utils  device-mapper-persistent-data  lvm2 --skip-broken
# 更新XFS文件系统管理工具
yum update xfsprogs -y

3. 安装docker

# 更新本地镜像源
yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
# 更新镜像源缓存
sed -i 's/download.docker.com/mirrors.ustc.edu.cn\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
# 更新镜像源缓存
yum makecache fast
# 安装Docker
yum install -y docker-ce

4. 启动docker服务

启动服务前先关闭防火墙

# 查看防火墙状态
systemctl status firewalld
# 关闭本地防火墙
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld

# 启动docker服务
systemctl start docker
# 设置开机自启动
systemctl enable docker

5. 配置镜像加速

Docker官方镜像仓库网速较差,我们需要设置国内镜像:

​ 参考阿里云的镜像加速文档:阿里云镜像管理地址(https://www.aliyun.com/)

# 创建配置文件
mkdir -p /etc/docker
# 配置镜像加速地址 (填写自己阿里云下的镜像加速地址)
tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://7n40e80k.mirror.aliyuncs.com"]
}
EOF
# 重新加载配置并重启Docker
systemctl daemon-reload
systemctl restart docker

注:
有的可能出现配置镜像错误的原因:etc目录下没有docker目录,
此时需要先在etc目录下创建docker文件夹,然后再对daemon。json进行修改。

# 观察镜像是否生效
docker info
image-20210613223758795

三、Docker相关命令

系统服务管理docker

# 启动docker
systemctl start docker
# 停止docker
systemctl stop docker
# 重启docker
systemctl restart docker
# 查看docker状态
systemctl status docker
# 开机启动
systemctl enable docker

1. 镜像操作

操作Docker镜像的常用命令有:
	docker --help # 查询帮助
	docker xxx --help # 查询xxx命令的作用和使用方式★★★★★
    docker search  # 在镜像仓库搜索镜像
    docker pull # 从镜像仓库拉取镜像
    docker pull 镜像名称:tag 
    docker push # 将本地镜像推送到远程镜像库
    docker images # 查看本地镜像列表
    docker rmi 镜像名称:tag # 删除本地镜像
    docker save # 保存镜像为一个tar文件
    docker load # 加载本地tar文件中包含的镜像
    docker build # 构建一个镜像
    docker tag # 给镜像打新标签
  
# 删除所有镜像, 谨慎使用
docker rmi `docker images -q`  

例如:

需求1:从镜像仓库中拉取一个nginx镜像
# 1.首先去镜像仓库搜索nginx镜像
# 2.根据镜像名称搜索,相关镜像对应的拉取命令
docker pull nginx
# 3.查看拉取到的镜像
docker images

需求2:去DockerHub搜索并拉取一个Redis镜像
docker pull redis // 不写tag,默认最新
# 1.查询docker tag命令的作用和语法
docker tag --help
# 2.使用docker tag打包镜像
docker tag redis:latest myredis:1.0
# 3.使用docker save将镜像打入到tar包中,便于传播
docker save -o myredis.tar myredis:1.0
# 加载本地tar文件中包含的镜像
docker load -i 文件名.tar

2. 容器操作

操作Docker容器的常用命令有:
  docker run --name mn -p 80:80 -d 镜像名称 # 创建并运行容器
  	--name 容器名称
  	-p 端口映射
  	-d 后台运行
  docker stop 容器名称   # 停止容器
  docker start 容器名称  # 启动容器
  docker restart 容器名称(或者容器ID)  # 重启容器
  docker pause 			# 暂停容器
  docker unpause        # 恢复容器
  docker ps             # 查看运行中的容器
  docker ps -a 			# 查看所有容器
  docker ps –l			  # 查看最后一次运行的容器
  docker ps -f status=exited # 查看停止的容器
  docker rm 容器名称	 # 删除容器
  docker rm -f 容器名称  # 强制删除容器(无论运行与否) 
  docker exec 		    # 执行容器内的指定指令
  docker commit         # 提交一个容器为镜像
  docker logs -f 容器名称(或容器ID)   # 查看容器运行日志

说明:
 -i:表示运行容器
 -t:表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端。
 --name :为创建的容器命名, **必须是唯一的**。
 -v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),
 可以使用多个-v做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,
 然后共享到容器上。
 -d:在run后面加上-d参数,则会创建一个**守护式容器**在后台运行(这样创建容器后不会自动登录容器,
 如果只加-i -t两个参数,创建后就会自动进去容器)。
 -p:表示**端口映射**,前者是宿主机端口,后者是容器内的映射端口。
 可以使用多个-p做多个端口映射

例如:

需求1:创建并运行一个Nginx容器
# 1.创建并运行一个Nginx容器的命令为:
		docker run --name myn -p 80:80 -d nginx
    # 命令解读:
    # docker run :创建并运行一个容器
    # --name : 给容器起一个名字,比如叫做myn
    # -p :端口映射,例如:-p 80:80,把容器的80端口映射到宿主机的80端口
    # -d:后台运行容器
    # nginx:镜像名称
# 2.访问虚拟机页面 http://[你的虚拟机IP]
		192.168.182.140:80
		
需求2:进入Nginx容器,修改HTML文件内容,添加“Hello Nginx”
# 创建并运行nginx容器
docker run \
--name myn \
-p 80:80 \
-d \
nginx
# 1.进入nginx容器的命令为
	docker exec -it mn bash
#命令解读:
  #  docker exec :进入容器内部执行
  #  -it : 给当前进入的容器创建一个Linux命令行终端,允许我们通过命令行与容器交互
  #  myn :要进入的容器的名称
  #  bash:进入容器后执行的命令,bash是一个linux终端交互语言格式
# 2.进入nginx的HTML所在目录 /usr/share/nginx/html (此目录去官网查找)
	cd /usr/share/nginx/html
# 3.修改index.html的内容为 Hello Nginx:
	sed -i 's#Welcome to nginx#Hello Nginx#g' index.html
	sed -i 's#<head>#<head><meta charset="utf-8">#g' index.html
# 4.退出容器的客户端
	exit
	
需求3:运行一个redis容器,并且支持数据持久化
#1.到DockerHub搜索Redis镜像
#2.查看Redis镜像文档中的帮助信息
#3.利用docker run 命令运行一个Redis容器
docker run --name 容器名称 -p 6379:6379 -d redis redis-server --appendonly yes

# redis持久化机制:
	RDB: 默认开启的(快照机制)
    AOF: 手动配置
    
需求4:进入redis容器,并执行redis-cli客户端命令,存入num=996
#1.进入redis容器
	docker exec -it 容器名称 bash
#2.执行redis-cli客户端命令
	redis-cli
#3.设置数据num=666
	set num 666

3. 其他操作

创建容器三种方式【了解】
#(1)交互式方式创建容器
docker run -it --name 容器名称 镜像名称:标签 /bin/bash
docker run -it --name=mycentos1 centos:7 /bin/bash
这时我们通过ps命令查看,发现可以看到启动的容器,状态为启动状态  
#(2)守护式方式创建容器
docker run -di --name 容器名称 镜像名称:标签
docker run -di --name=mycentos2 centos:7  
#(3)登录守护式容器方式
docker exec -it 容器名称 (或者容器ID)  /bin/bash
文件拷贝与挂载
# 拷贝到容器
docker cp 需要拷贝的文件或目录 容器名称:容器目录
# 从容器中拷贝出
docker cp 容器名称:容器目录 需要拷贝的文件或目录

# 目录挂载
# --privileged=true 代表的是多级文件夹下的权限访问问题
docker run -di -v /usr/local/myhtml:/usr/local/myhtml --privileged=true --name=mycentos3 centos:7
说明:
如果共享的是多级的目录,可能会出现权限不足的提示,
因为CentOS7中的安全模块selinux把权限禁掉了,
我们需要添加参数  --privileged=true来解决挂载的目录没有权限的问题
查看容器IP地址
# 查看容器IP地址
# 查看容器运行的各种数据
docker inspect 容器名称(容器ID) 
# 直接查看IP地址
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称(容器ID)
打包加载与备份
# 容器保存为镜像
# my-nginx 容器名称, mynginx_i 自定义镜像名称
docker commit my-nginx mynginx_i   

# 镜像备份(镜像保存为tar 文件)
docker save -o [文件名] IMAGE [IMAGE...]
docker  save -o mynginx.tar mynginx_i

# 镜像恢复与迁移 执行后再次查看镜像,可以看到镜像已经恢复
docker load -i mynginx.tar

四、数据卷

1. 数据卷的概念

【1】为什么引入数据卷
image-20210613232029552
【2】数据卷的特征
image-20210613232014555
【3】数据卷的原理
image-20210613232252833

数据卷 是一个可供一个或多个容器使用的特殊目录,一般是在宿主机的某个特定的目录下。

把变化的数据记录在容器之外的宿主机上,实现容器与数据的分离

可以提供很多有用的特性:

  • 数据卷 可以在容器之间共享和重用
  • 数据卷 的修改会立马在挂载数据卷的容器中可见
  • 数据卷 的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除

通过docker volume命令可以管理数据卷。

2. 数据卷操作命令

数据卷是一个虚拟的概念,一个数据卷指向宿主机上的一个文件夹
#创建数据卷
	docker volume create 数据卷名称 
#查询数据卷信息
	docker volume inspect 数据卷名称
#查询所有数据卷基本信息
	docker volume ls
#删除未使用的数据卷
	docker volume prune
#删除数据卷
	docker volume rm 数据卷名称
#挂载数据卷 (建立数据卷与容器目录的对应关系)
举例1:
	docker run \ 
  	--name mn \
  	-v html:/root/html \
  	-p 8080:80
 	nginx
    # 说明:
    # 		docker run :就是创建并运行容器
    #   	--name myn :给容器起个名字叫myn
    #   	-v html:/root/htm :挂载html数据卷 到容器内的/root/html目录
    #  	 	-p 8080:80 :把宿主机的8080端口映射到容器内的80端口
    #   	nginx :镜像名称
    
    访问:http://虚拟机ip:8080
 
举例2: 
    docker run --name my-nginx -p 8888:80
    -v html:/usr/share/nginx/html 
    -v $PWD/nginx.conf:/etc/nginx/nginx.conf 
    --privileged=true 
    -d nginx
    # 命令数名:
    `--name my-nginx`:容器名称为my-nginx
    `-p 80:80`:将容器的80端口映射到宿主机的80端口
    `-v html:/usr/share/nginx/html`:挂载html数据卷 到容器的`/usr/share/nginx/html`目录
    `-v $PWD/nginx.conf:/etc/nginx/nginx.conf``$PWD/nginx.conf`:当前目录下的nginx.conf文件
    把宿主机当前目录下的`nginx.conf`文件挂载到容器内的`/etc/nginx/nginx.conf`文件
    `--privileged`:授予本地目录的访问权限
    `-d`:后台运行
    `nginx`:镜像名称

	访问:http://虚拟机ip:8888

例如:

需求1:创建 html数据卷,并查看数据卷在宿主机的目录位置
#1.创建数据卷
	docker volume create html
#2.查看所有数据卷
	docker volume ls
#3.查看数据卷详细信息
	docker volume inspect html

需求2:创建一个nginx容器,挂载数据卷html上到容器内的html目录,并修改html数据卷中的index.html内容
#1.首先到DockerHub的Nginx页面查看HTML目录在容器内的位置
#2.创建容器并挂载数据卷到容器内的HTML目录
	docker run \
	--name mn \
	-v html:/usr/share/nginx/html \
	-p 80:80 \
	-d \
	nginx
#3.进入HTML数据卷所在位置,并修改HTML内容
  # 查看html数据卷的位置
  docker volume inspect html
  # 进入该目录
  cd /var/lib/docker/volumes/html/_data
  # 修改文件
  vi index.html
  
需求3:挂载到宿主机文件覆盖nginx容器内配置文件,并修改内容。实现一个方向代理效果:http://localhost:80/bd 请求代理到 http://www.baidu.com
#1.去DockerHub的Nginx页面查看配置文件在容器内的位置
	容器中配置文件位置: /etc/nginx/nginx.conf
#2.在宿主机的/tmp目录新建一个nginx.conf文件,编写反向代理逻辑
	cd /tmp
	touch nginx.conf
	参考下面配置
#3.创建nginx容器,挂载/tmp/nginx.conf到容器内的nginx配置文件
	# 删除旧容器
		docker rm -f mn
	# 创建新容器,挂载nginx.conf文件
    docker run \
    --name mn \
    -v html:/usr/share/nginx/html \
    -v /tmp/nginx/nginx.conf:/etc/nginx/nginx.conf \
    -p 80:80 \
    -d \
    nginx
#4.在浏览器查看访问
http://虚拟机ip/bd

/tmp/nginx.conf 下编辑:

下面配置错误 缺少一些参数

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location /bd {
            proxy_pass https://www.baidu.com;
        }
		location / {
            root  /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
}

五、网络管理操作

当我们要部署基于docker的微服务群时,往往会需要容器之间互相连接。这时就需要用到Docker中的网络配置了。通过docker network命令可以管理docker网络。

集群: 多台服务器做相同的事情
分布式: 多台服务器做不同的事情,在共同协作下完成一个具体的业务

#创建一个名为my-net的网络(名称可以自定义)
docker network create my-net
#将指定容器加入到my-net网络
docker network connet my-net 容器名称
#将一个容器退出(断开)指定的网络
docker network disconnect 网络名称 容器名称
#查看网络的详细信息,如IP网段等
docker network inspect 网络名称
#列出所有的网络
docker network ls
#删除所有未使用的网络
docker network prune
#删除所有指定的网络
docker network rm	网络名

例如:

需求1:创建一个网络my-net,并且将之前的nginx容器加入网络中
#1.创建一个名为my-net的网络
	docker network create my-net
#2.查看创建的网络
	docker network ls
#3.查看网络加入语法
	docker network connect --help
#4.将nginx容器加入网络
	docker network connect my-net myn
	
需求2:基于busyBox镜像创建并运行一个容器,加入my-net网络,测试与nginx容器的网络是否畅通
1.基于BusyBox镜像创建容器,并使用--network参数加入my-net网络
	docker run -it --rm --name busybox1 --network my-net busybox sh
  # 命令说明:
  #   -it	运行容器并保持一个可交互的shell终端
  #   --rm	容器退出时,自动删除容器
  #   --network my-net		连接到my-net网络
  #   busybox	是一个测试用的简单容器
  #   sh	终端交互方式采用sh方式
#2.通过ping命令测试网络连接,同一个网络中的容器可以用容器名互联
	ping ip地址

注:

  1. 创建容器时的 --network 参数允许我们直接加入一个网络中
  2. 互联的容器可以利用容器名互相访问

六、DockerFile自定义镜像

在前面镜像原理的中,我们可以了解到,镜像的本质是一层层的Layer。

基于一个rootfs这个基础的Layer定制每一层所添加的配置、文件,要执行的操作等。
如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,

那么这个脚本就是 Dockerfile。
因此,Dockerfile就是一个描述镜像构建的文件。其中一定会有一个基础镜像(BaseImage),

然后在基础镜像上每完成一次修改或安装命令,就形成一层新的Layer,直到镜像构建完成。

作用:

  1. 对于开发人员:可以为开发团队提供一个完全一致的开发环境;

  2. 对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件构建一个新的镜像开始工作了;

  3. 对于运维人员:在部署时,可以实现应用的无缝移植。

DockerFile参考指令:https://docs.docker.com/engine/reference/builder

命令作用
FROM image_name:tag定义了使用哪个基础镜像启动构建流程
MAINTAINER user_name声明镜像的创建者
ENV key value设置环境变量 (可以写多条)
RUN command是Dockerfile的核心部分(可以写多条)
ADD source_dir/file dest_dir/file将宿主机的文件复制到容器内,如果是一个压缩文件,将会在复制后自动解压
COPY source_dir/file dest_dir/file和ADD相似,但是如果有压缩文件并不能解压
WORKDIR path_dir设置工作目录
image-20210614001506342

例如:

需求1:基于Nginx镜像构建一个新镜像,修改其中的index.html文件
#1.在一个空文件夹新建一个文件,命名为Dockerfile,内容如下
	# 创建空文件夹
    mkdir /tmp/nginxfile
    # 进入空文件夹
    cd /tmp/nginxfile
    # 创建Dockerfile文件【文件名不能是其他】
    vi Dockerfile
    -----------------
    FROM nginx:1.20.1 
    RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html 
    -----------------
#2.在当前目录下执行命令,构建镜像【.  表示当前目录】
	docker build -t mynginx:1.20.1  .
#3.创建并运行容器
	docker run --name mn1.2.0.1 -p 80:80 -d mynginx:1.0 
# 说明
Dockerfile内容非常简单,就两个命令:FROM和RUN
FROM:就是基础镜像,是Dockerfile中必备的,我们构建镜像没必要从rootfs开始,
可以基于已有镜像基础上去构建自己的镜像,节省很多时间
RUN:像 Shell 脚本一样可以执行命令,这里是直线echo 命令将'<h1>Hello, Docker!</h1>'写入容器的index.html文件中,那么nginx的欢迎页面内容就被修改了。

那么这里Dockerfile描述的镜像就比nginx官方镜像多了一层Layer,定制了nginx欢迎页面。
需求2:基于CentOS7定制nginx镜像
# 基于centos7安装
FROM centos:7
#拷贝nginx的安装包
COPY nginx-1.10.3.tar.gz /usr/local/src
# 环境变量
ENV NGX_DIR=/opt/nginx
#安装依赖、解压、编译、安装
RUN yum -y install pcre pcre-devel zlib zlib-devel openssl openssl-devel gcc tar \
  && cd /usr/local/src \
	&& tar -xvf nginx-1.10.3.tar.gz \ 
	&& rm -rf nginx-1.10.3.tar.gz \
	&& cd nginx-1.10.3 \
	&& ./configure --prefix=$NGX_DIR --sbin-path=/usr/bin/nginx \
	&& make \
	&& make install 

#设置数据挂载目录以及工作目录 匿名卷:当前卷默认不存在,当容器创建时,再生成当前卷
VOLUME $NGX_DIR
#容器启动后执行该命令
ENTRYPOINT ["nginx", "-g", "daemon off;"]
需求3:基于java:8-alpine镜像,将一个Java项目构建为镜像
# 1.新建一个空的目录,然后在目录中新建一个文件,命名为Dockerfile
# 2.拷贝app.jar到这个目录中(自己可以随意打一个jar包测试)
# 3.编写Dockerfile文件:
		touch Dockerfile
		--------------------
		# 基于java:8-alpine作为基础镜像
		FROM java:8-alpine
		# 将app.jar拷贝当前Dockerfile文件目录下 作为镜像中新Layer层  
		COPY app.jar /tmp/app.jar
		# 编写入口ENTRYPOINT
		ENTRYPOINT ["java", "-jar", "/tmp/app.jar"]
		----------------------
# 4.使用docker build命令构建镜像
		docker build -t web:1.0 .
# 5.使用docker run创建容器并允许  端口可自己指定
		docker run --name web -p 9090:9090 -d web:1.0 

# 测试访问 
虚拟机ip:9090 

自定义创建jdk8镜像

步骤:

(1)创建目录

mkdir –p /usr/local/dockerjdk8

(2)下载jdk-8u171-linux-x64.tar.gz并上传到服务器(虚拟机)中的/usr/local/dockerjdk8目录

(3)创建文件Dockerfile vi Dockerfile

#依赖镜像名称和ID
FROM centos:7
#指定镜像创建者信息
MAINTAINER AHCFL
#切换工作目录
WORKDIR  /usr/local/mysoft/jdk8_docker
RUN mkdir -p /usr/local/mysoft/jdk8_docker
#ADD 是相对路径jar,把java添加到容器中
ADD jdk-8u181-linux-x64.tar.gz /usr/local/mysoft/jdk8_docker

#配置java环境变量
ENV JAVA_HOME /usr/local/mysoft/jdk8_docker/jdk_8u181
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

(4)执行命令构建镜像

docker build -t='jdk8' .  # 默认是 latest  # -t 指定tag版本

注意后边的空格和点,不要省略

(5)查看镜像是否建立完成

docker images

七、Docker镜像服务

image-20210614230624084

1. 阿里云容器镜像服务

https://cr.console.aliyun.com/cn-hangzhou/instance

image-20210614193124095

相关命令

将镜像推送到Registry步骤
# 请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。
docker login --username=ahcfl_**** registry.cn-hangzhou.aliyuncs.com
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/ahcfl/nginx:[镜像版本号]
docker push registry.cn-hangzhou.aliyuncs.com/ahcfl/nginx:[镜像版本号]
# 用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。 您可以在访问凭证页面修改凭证密码。
docker login --username=ahcfl_**** registry.cn-hangzhou.aliyuncs.com
# 登出
docker logout

# 打包一个本地的镜像,通过`docker tag`命令
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/it-heima/nginx:[镜像版本号]
eg: docker tag 37bb9c63c8b2 registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

# 接下来,通过`docker push`命令来推送一个镜像
docker push NAME:[TAG]
eg: docker push registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816
 
# 从Registry中拉取镜像
docker rmi registry.cn-hangzhou.aliyuncs.com/ahcfl/nginx:[镜像版本号]
docker pull registry.cn-hangzhou.aliyuncs.com/ahcfl/nginx:[镜像版本号]

选择合适的镜像仓库地址
从ECS推送镜像时,可以选择使用镜像仓库内网地址。推送速度将得到提升并且将不会损耗您的公网流量。
如果您使用的机器位于VPC网络,请使用 registry-vpc.cn-hangzhou.aliyuncs.com 作为Registry的域名录。

2. 私有镜像仓库

# 安装镜像仓库镜像
docker run -d \
  --restart=always \
  --name registry	\
  -p 5000:5000 \
  -v registry-data:/var/lib/registry \
  registry
# 镜像仓库默认会自动启动,如何查看镜像仓库中有哪些镜像呢?
	访问: http://你的宿主机地址:5000/v2/_catalog
# 配置允许指定ip向本地镜像仓库提交镜像
# 打开要修改的文件
		vi /etc/docker/daemon.json
# 添加内容: json格式,需要加 逗号 
		"insecure-registries":["http://宿主机ip地址:5000"]
# 重加载
		systemctl daemon-reload
# 重启docker
		systemctl restart docker
# 推送
	docker push 宿主机ip地址:5000/nginx:1.0
# 拉取
	docker pull 宿主机ip地址:5000/nginx:1.0
# 镜像若想存放到本地镜像仓库,需满足本地仓库的格式
	格式: docker tag nginx:latest 宿主机ip地址:5000/nginx:1.0
(1)拉取私有仓库镜像(此步省略)
docker pull registry

(2)启动私有仓库容器
docker run -di --name=registry -p 5000:5000 registry

(3)打开浏览器 输入地址http://192.168.200.150:5000/v2/_catalog看到`{"repositories":[]}` 表示私有仓库搭建成功并且内容为空

(4)修改daemon.json
vi /etc/docker/daemon.json
添加以下内容,保存退出。
"insecure-registries":["http://192.168.200.150:5000"]
此步用于让 docker信任私有仓库地址

(5)修改配置 ` vi /lib/systemd/system/docker.service`
内容:
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
执行:
systemctl daemon-reload

(6)重启docker 服务
systemctl restart docker

镜像上传至私有仓库
(1)标记此镜像为私有仓库的镜像
docker tag jdk8 192.168.200.150:5000/jdk8

(2)再次启动私服容器
docker start registry

(3)上传标记的镜像
docker push 192.168.200.150:5000/jdk8

八、应用部署(常用镜像安装)

1. MySQ部署

====================================================
# 关闭或禁用Linux上已经安装的mysql,因为端口被占用了
# 关闭
systemctl stop [mysql/mysqld]
# 禁用
systemctl disable [mysql/mysqld]
=====================方式一:=========================

#1.拉取或从本地加载MySQL镜像。因为镜像文件较大,推荐从本地加载
	docker pull mysql:5.6  
#2.创建两个数据卷mysql-data、mysql-conf
	docker volume create mysql-data
	docker volume create mysql-conf
#3.进入mysql-conf数据卷所在目录,新建一个my.cnf文件
	# 查看数据卷对应目录
	docker volume inspect mysql-conf
	# 进入
	cd /var/lib/docker/volumes/mysql-conf/_data
	# 创建核心配置文件  my.cnf(Linux环境下mysql的核心配置文件)
	touch my.cnf
#4.编辑my.cnf文件,设置mysql编码等配置属性
    # mysql配置文件内容:
    --------------
    [mysqld]
    skip-name-resolve
    character_set_server=utf8
    datadir=/var/lib/mysql
    server-id=1000
	---------------
#5.创建并运行容器。【具体参数及挂载目录参考DockerHub网站的说明】
docker run \
--name mysql5.6 \
-p 3307:3307 \
-d \
-e MYSQL_ROOT_PASSWORD=root \
-v mysql-data:/var/lib/mysql \
-v mysql-conf:/etc/mysql/conf.d \
--privileged \
mysql:5.6


=====================方式二:================================
# 加载镜像
cd /tmp
docker load -i mysql.tar
# 创建新用户
useradd 你的用户名
passwd 你的密码
cd /home/你的用户名
# 创建文件夹并进入
mkdir mysql
cd mysql
# 运行mysql容器
# 在当前/home/leyou/mysql 目录下然后执行docker命令:
mkdir mysqldocker run \
 -p 3306:3306 \
 --name mysql \
 -v $PWD/conf:/etc/mysql/conf.d \
 -v $PWD/data:/var/lib/mysql \
 -e MYSQL_ROOT_PASSWORD=123 \
 --privileged \
 -d \
 mysql:[tag]
# 自定义配置文件: 
vi conf/my.cnf
-----内容------
[mysqld]
skip-name-resolve
character_set_server=utf8
datadir=/var/lib/mysql
server-id=1000
---------------
# 重启mysql:
docker restart ly-mysql

通过Navicat或其它工具,尝试连接mysql。

2. Redis部署

# 直接下载 或 本地加载
docker pull redis:5.0
docker load -i redis.tar
# 挂载本地文件
cd /home/你的用户名
# 创建一个文件夹
mkdir redis
cd redis
mkdir data
# 创建redis 的配置文件
touch redis.conf
# 修改配置
vi redis.conf
---------添加内容---------------
databases 1
dir /data
appendonly yes
appendfilename appendonly.aof
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
-------------------------------
# 进入redis.conf所在目录,然后执行docker命令,运行容器
docker run \
 -p 6379:6379 \
 --name redis \
 -v $PWD/redis.conf:/usr/local/etc/redis/redis.conf \
 -v $PWD/data:/data \
 --privileged \
 -d \
 redis \
 redis-server /usr/local/etc/redis/redis.conf
 
# 安装完成后,可以再控制台执行命令测试
docker exec -it ly-redis redis-cli
# 输入ping
回应:PONG

3. RabbitMQ部署

# 镜像
docker pull rabbitmq:3-management
docker load -i mq.tar
# 运行RabbitMQ容器
docker run \
 -e RABBITMQ_DEFAULT_USER=guest \
 -e RABBITMQ_DEFAULT_PASS=guest \
 --name mq \
 --hostname mq1 \
 -p 15672:15672 \
 -p 5672:5672 \
 -id \
 rabbitmq:3-management
# 测试 在浏览器访问
http://你的ip:15672

3. RocketMQ部署

创建namesrv服务
# 拉取镜像
docker pull rocketmqinc/rocketmq

# 创建namesrv数据存储路径
mkdir -p  /srv/docker/rocketmq/data/namesrv/logs   /srv/docker/rocketmq/data/namesrv/store

# 构建namesrv容器
docker run -d \
--restart=always \
--name rmqnamesrv2 \
-p 9876:9876 \
-v /srv/docker/rocketmq/data/namesrv/logs:/root/logs \
-v /srv/docker/rocketmq/data/namesrv/store:/root/store \
-e "MAX_POSSIBLE_HEAP=100000000" \
rocketmqinc/rocketmq \
sh mqnamesrv 

命令说明:

image-20210615001218171
创建broker节点
# 创建broker数据存储路径
mkdir -p  /srv/docker/rocketmq/data/broker/logs   /srv/docker/rocketmq/data/broker/store /docker/rocketmq/conf

# 创建配置文件
vi /srv/docker/rocketmq/conf/broker.conf
内容如下:
-------------------------------------------
# 所属集群名称,如果节点较多可以配置多个
brokerClusterName = DefaultCluster
#broker名称,master和slave使用相同的名称,表明他们的主从关系
brokerName = broker-a
#0表示Master,大于0表示不同的slave
brokerId = 0
#表示几点做消息删除动作,默认是凌晨4点
deleteWhen = 04
#在磁盘上保留消息的时长,单位是小时
fileReservedTime = 48
#有三个值:SYNC_MASTER,ASYNC_MASTER,SLAVE;同步和异步表示Master和Slave之间同步数据的机制;
brokerRole = ASYNC_MASTER
#刷盘策略,取值为:ASYNC_FLUSH,SYNC_FLUSH表示同步刷盘和异步刷盘;SYNC_FLUSH消息写
入磁盘后才返回成功状态,ASYNC_FLUSH不需要;
flushDiskType = ASYNC_FLUSH
# 设置broker节点所在服务器的ip地址
brokerIP1 = 192.168.182.140
-------------------------------------------

# 构建broker容器
docker run -d  \
--restart=always \
--name rmqbroker5 \
--link rmqnamesrv:namesrv \
-p 10911:10911 \
-p 10909:10909 \
-v  /srv/docker/rocketmq/data/broker/logs:/root/logs \
-v  /srv/docker/rocketmq/data/broker/store:/root/store \
-v /srv/docker/rocketmq/conf/broker.conf:/opt/rocketmq-4.4.0/conf/broker.conf \
-e "NAMESRV_ADDR=namesrv:9876" \
-e "MAX_POSSIBLE_HEAP=200000000" \
rocketmqinc/rocketmq \
sh mqbroker -c /opt/rocketmq-4.4.0/conf/broker.conf 

命令说明:

image-20210615001522983

创建rockermq-console服务
# 拉取镜像
docker pull pangliang/rocketmq-console-ng

# 构建rockermq-console容器
docker run -d \
--restart=always \
--name rmqadmin \
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=192.168.182.140:9876 \
-Dcom.rocketmq.sendMessageWithVIPChannel=false" \
-p 9999:8080 \
pangliang/rocketmq-console-ng

命令说明:

image-20210615001804914

测试访问

需要先关闭防火墙或者开放namesrv和broker端口

如果不设置,控制台服务将无法访问namesrv服务, 异常信息如下 :org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to failed

# 关闭防火墙
systemctl stop firewalld.service
# 或者  开放指定端口
firewall-cmd --permanent --zone=public --add-port=9876/tcp
firewall-cmd --permanent --zone=public --add-port=10911/tcp

# 立即生效
firewall-cmd --reload

此时可访问 http://192.168.182.140:9999/ 查看控制台信息

4. Tomcat部署

# 拉取镜像
docker pull tomcat:7-jre7
# 创建容器  -p表示地址映射
docker run -di --name=mytomcat -p 9000:8080 \
-v /usr/local/webapps:/usr/local/tomcat/webapps tomcat:7-jre7

5. Nginx部署

# 下载Nginx的docker镜像:
docker pull nginx

# 先运行一次容器(为了拷贝配置文件):
docker run -p 80:80 --name nginx \
-v /mydata1/nginx/html:/usr/share/nginx/html \
-v /mydata1/nginx/logs:/var/log/nginx  \
-id nginx

# 将容器内的配置文件拷贝到指定目录:
docker cp nginx:/etc/nginx /mydata1/nginx/

# 修改文件名称:
cd /mydata1/nginx/
mv nginx conf

# 终止并删除容器:
docker rm -f nginx

# 使用如下命令启动Nginx服务:
docker run -id -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx  \
-v /mydata/nginx/conf:/etc/nginx \
--privileged=true nginx

# 命令解释:
-v /mydata/nginx/html:/usr/share/nginx/html:将宿主机 /mydata/nginx/html 目录挂载到容器内部,用于存放 静态的页面
* `-v /mydata/nginx/logs:/var/log/nginx`:日志目录挂载
* `-v /mydata/nginx/conf:/etc/nginx`:配置文件存放到 `/mydata/nginx/conf`
* `-p 80:80`:端口映射

# 在 /mydata/nginx/html 目录下创建 index.html 文件,添加任意内容

# 测试 浏览器访问
http://你的ip/

总结

image-20210614234441188
Docker(码头工人): 容器化管理技术
		相关名词:
				镜像: 对现有的环境和程序进行打包,打好的包叫做镜像.
						在镜像中进行分层,先有层需要基于前一层,对前一层做了只读拷贝
				容器: 根据镜像创建对应的运行环境
							将镜像做了只读拷贝后,提供了一个可写层,在可写层中可以操作这个软件
				镜像服务:
						本质上就是一个存放有镜像文件的远程仓库,在该仓库中提供了无数个可用的镜像文件
						镜像仓库: 一款软件对应一个镜像仓库
								镜像文件: xxx:tag
										xxx: 软件的名称
										tag: 软件的版本号
		Docker工作原理:
				Docker是使用go语言开发的一款C/S架构的软件.使用之前必须先启动docker服务.
				通过在客户端发送docker命令给服务器,服务器解析后,完成对应的功能
命令常用方式: 命令提示
		docker --help : 查询帮助
    docker xxx --help : 查询xxx命令的作用和使用方式★★★★★
操作Docker镜像的常用命令有:
    docker search : 在镜像仓库搜索镜像
    docker pull : 从镜像仓库拉取镜像
    docker push : 将本地镜像推送到远程镜像库
    docker images : 查看本地镜像列表
    docker rmi 镜像名称:tag : 删除本地镜像
    docker save : 保存一个或多个镜像到一个tar文件
    docker load : 加载本地tar文件中包含的镜像
    docker build : 构建一个镜像
    docker tag : 给镜像打新标签
    	docker tag nginx mynginx:1.0
操作Docker容器的常用命令有:
    docker run --name mn -p 80:80 -d 镜像名称 : 创建并运行容器
      --name 容器名称
      -p 端口映射
      -d 后台运行
    docker stop 容器名称:停止容器
    docker start 容器名称:启动容器
    docker ps :查看运行中的容器
    docker ps -a : 查看所有容器
    docker rm 容器名称:删除容器
    docker rm -f 容器名称 : 强制删除容器(无论运行与否) 
    docker exec :执行容器内的指定指令
    docker commit :提交一个容器为镜像

Docker高级

一、容器编排概述

Docker只是一个对项目做打包和运行的小工具,如果止步于此,那么充其量就是一个开发者手里的小玩具

因为真实的项目都是要集群部署的,还要考虑负载均衡、水平扩展、动态伸缩、集群容错等问题,而Docker并不具备这样的功能。

而要想让Docker在集群中的部署如同单机部署一样的方便,那就需要用到容器编排技术了。

“编排”(Orchestration)在云计算行业里不算是新词汇,它主要是指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义、配置、创建、删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。

而容器时代,“编排”显然就是对 Docker 容器的一系列定义、配置和创建动作的管理。目前容器编排技术比较知名的包括:

  • Docker公司自己的:docker-compose + swarm组合
  • Google牵头的Kubernetes技术,简称为k8s

二、 Docker Compose

Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速的部署分布式应用,

官网地址: https://github.com/docker/compose ,其前身是开源项目 Fig。

本节将介绍 Compose 项目情况以及安装和使用。

网址:https://docs.docker.com/compose/compose-file/

1. 为什么要用Docker Compose

作用: 定义一组相关联的应用容器为一个项目,定义各个容器的依赖关系

Compose 恰好满足了Docker集群化的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

场景:

通过Dockerfile我们可以将一个项目很方便的打包为一个Docker镜像。但是在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。如何**定义各个容器的依赖关系,**这就需要用到docker-compose了。

2. Docker Compose安装

MAC下或者Windows下的Docker自带Compose功能,无需安装。

Linux下需要通过命令安装:

# 安装
curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# 修改权限
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

3. Docker Compose快速入门

假设我们要部署一个SpringBoot项目,并且依赖于Redis。

导入微服务工程

工程的基本功能就是统计用户的访问量,代码在资料中,直接解压到没有中文的目录下,使用Idea导入即可。

编写Dockerfile

(1)在任意位置创建一个新目录,将app.jar复制到该目录 {自己可以书写打包app.jar}

(2)在该目录中,新建一个Dockerfile文件,并编写下面的内容:

FROM java:8-alpine
COPY ./app.jar /tmp/app.jar
EXPOSE 9090
ENTRYPOINT ["java","-jar","/tmp/app.jar"]
编写docker-compose

在刚才的目录中,创建一个docker-compose.yml文件并填写内容:

version: '3'
services:
  web:
    build: .
    ports:
      - "9090:9090"
  redis:
    image: "redis"
    
命令解读:
- version:compose的版本
- services:服务列表,包括两个服务:
  - web:自己写的Java项目
    - build:这个服务镜像是临时构建的,构建目录是当前目录,会利用当前目录的Dockerfile来完成构建。
    - ports:端口映射,对外开放8080端口
  - redis:redis服务

此时的结构docker文件夹有:

app.jar docker-compose adocker-commpose.yml Dockerfile

启动测试

将刚刚准备好的文件夹上传到Linux的/opt/docker-compose目录:

image-20201109001424236

然后执行命令:

docker-compose up
docker ps

构建完成后,可以看到项目运行的日志信息:

image-20210615110711494

此时,访问浏览器 http://192.168.182.40:9090/hello,

如果多次访问,这个次数会累加。

按次CTRL+C后可以停止运行程序,并且Docker运行的容器中也会关闭。

通过docker-compose up -d命令,可以后台启动,这样就不会显示日志:

通过docker-compose stop 关闭容器

通过docker-compose down关闭容器并删除

4. Docker Composer 相关命令

通过:docker-compose —help 查看

[root@localhost docker-demo]# docker-compose --help
利用Docker来定义和构建一个多容器的应用

使用方式:
  docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
  docker-compose -h|--help

Options:
  -f, --file FILE             指定一个 compose 文件,
                              (默认: docker-compose.yml)
  -p, --project-name NAME     指定project名字
                              (默认: 目录名称)
  --verbose                   显示更多日志
  --log-level LEVEL           日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  -v, --version               打印版本并退出
  -H, --host HOST             Daemon socket to connect to
Commands:
  build              构建多个service
  config             校验 Compose 文件,格式是否正确,若正确则显示配置,
  					 若格式错误显示错误原因
  down               停止并删除 容器, 网络, 镜像, 和 数据卷
  exec               进入一个指定的容器
  help               Get help on a command
  .............
  .............

5. Docker Compose常用语法

Compose版本

详细语法参考文档:https://docs.docker.com/compose/compose-file/

Compose模板文件是Compose的核心,
包括有多种版本的Compose文件格式–:1,2,2.x和3.x。
对应的Docker版本也不一样,对照表:
编写时,需要根据自己的docker版本来选择指定的Compose版本。

| **Compose file format** | **Docker Engine release** |
| :---------------------- | :------------------------ |
| 3.8                     | 19.03.0+                  |
| 3.7                     | 18.06.0+                  |
| 3.6                     | 18.02.0+                  |
| 3.5                     | 17.12.0+                  |
| 3.4                     | 17.09.0+                  |
| 3.3                     | 17.06.0+                  |
| 3.2                     | 17.04.0+                  |
| 3.1                     | 1.13.1+                   |
| 3.0                     | 1.13.0+                   |
| 2.4                     | 17.12.0+                  |
| 2.3                     | 17.06.0+                  |
| 2.2                     | 1.13.0+                   |
| 2.1                     | 1.12.0+                   |
| 2.0                     | 1.10.0+                   |
| 1.0                     | 1.9.1.+                   |
Compose两个重要的概念
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

Compose文件是一个YAML文件,定义 一个或多个服务(service),网络(network)和 卷(volume)。

撰写文件的默认路径为./docker-compose.yml

提示:您可以为此文件使用a .yml.yaml扩展名。他们俩都工作。

简单来说,一个`project`包含多个`service`,每个`service`都是一个组件。
例如入门案例中的Java项目和Redis都是`service`。部署时,可能每个service都会有多个容器去运行,
形成负载均衡的集群。
因此,我们定义service,就是在定义这个service在容器运行时的规则参数,
就像是给`docker run`命令设置参数一样。
我们定义network和volume类似于 `docker network create``docker volume create`这两个命令的效果。
只不过,我们定义规则,执行命令则由docker compose来完成。
Compose的模板文件语法
version: '3'
services:
  web:
    build: .
    ports:
      - "9090:9090"
    command: ["java", "-jar", "-Xmx256m", "/tmp/app.jar"]
    depends_on:
      - mysql
      - redis
  # redis服务
  redis:
    image: redis
  # mysql服务
  mysql:
    image: mysql:5.7
# 1
version:版本信息,详见上面提到的Compose版本与Docker的对应关系。

# 2
build:指定 `Dockerfile` 所在文件夹的路径(可以是绝对路径,或者相对 `docker-compose.yml` 文件的路径)。 `Compose` 将会利用它自动构建这个镜像,然后使用这个镜像。因为当前`Dockerfile`和`docker-compose.yml`是在一个目录,因此build值指定为`.`
----也可以先制定目录,然后在指定Dockerfile文件------
services:
  web:
    build:
      context: .  #指定compose上下文目录,相对路径是相对于
      dockerfile: Dockerfile
      args:
        buildno: 1
----------------------------------------------
build:Dockerfile配置
	context:用来指定Compose的工作环境目录,如果不指定或使用了相对路径则默认为`docker-compose.yml`所在目录。
	dockerfile:指定Dockerfile的文件名称

# 3
command:覆盖容器运行时的默认命令。

# 4
depends_on:解决容器的依赖、启动先后的问题。 例如上面:会先启动 `redis` `mysql` 再启动 `web`

# 5
ENTRYPOINT:指定服务容器启动后执行的入口文件或者启动命令
# 例如:
entrypoint: /code/entrypoint.sh
# 或者
entrypoint: ["php", "-d", "memory_limit=-1", "vendor/bin/phpunit"]

# 6
environment:添加环境变量。您可以使用数组或字典。任何布尔值(true,false,yes,no)都需要用引号引起来,以确保YML解析器不会将其转换为True或False。仅具有键的环境变量在运行Compose的计算机上解析为它们的值,这对于秘密或特定于主机的值很有用。
# 例如:
environment:
  RACK_ENV: development
  SHOW: 'true'
  SESSION_SECRET:
# 或者
environment:
  - RACK_ENV=development
  - SHOW=true
  - SESSION_SECRET

# 7
expose:指定内部端口,不将其发布到宿主机上,只有链接的其它服务才能访问它们。
# 例如:
expose:
  - "3000"
  - "8000"
  
# 8
extra_hosts:类似 Docker 中的 `--add-host` 参数,指定额外的 host 名称映射信息。
extra_hosts:
 - "googledns:8.8.8.8"
 - "dockerhub:52.1.157.61"
# 说明:会在启动后的服务容器中 `/etc/hosts` 文件中添加如下两条条目。
8.8.8.8 googledns
52.1.157.61 dock9

# 9
image:指定用于启动容器的图像。可以是镜像名称(仓库:tag)或镜像ID。如果镜像在本地不存在,而且你没有指定[build](https://docs.docker.com/compose/compose-file/#build)参数,那么Compose会尝试`docker pull`来拉取镜像

# 10
logging:配置日志选项。
# 例如:
logging:
  driver: syslog
  options:
    syslog-address: "tcp://192.168.0.42:123"
# 目前支持三种日志驱动类型。
driver: "json-file" # 记录为json文件
driver: "syslog" # 发送到syslog服务
driver: "none" # 没有日志记录
# 默认采用`json-file`的日志方式,可以通过`options` 配置日志文件的限制参数。
options:
  max-size: "200k"
  max-file: "10"
  
# 11
network_mode:网络模式。使用与`docker --network`参数相同的值
# 例如:
network_mode: "bridge"
network_mode: "host"
network_mode: "none"

# 12
networks:要加入的网络,引用Compose文件中的顶级项目networks下的定义的网络名称。
在定义网络时可以指定`ip`网段,而加入网络的容器则需要在网段中选择一个固定ip地址

services:
  app:
    image: nginx:alpine
    networks:
      app_net:
        ipv4_address: 172.16.238.10 # 指定一个IPv4子网地址
        ipv6_address: 2001:3984:3989::10 # 指定一个IPv6子网地址

networks:
  app_net:
    ipam:
      driver: default
      config:
        - subnet: "172.16.238.0/24" # 定义IPv4的地址网段   
        - subnet: "2001:3984:3989::/64" # 定义IPv6的地址网段
version: "3.8"

services:
  web:
    image: "nginx:alpine"
    networks:
      - new # 加入名称为new的网络

  worker:
    image: "my-worker-image:latest"
    networks:
      - legacy # 加入名称为legacy的网络

  db:
    image: mysql
    networks:
      new: # 加入名称为new的网络
        aliases: # 在new网络中的别名
          - database
      legacy: # 加入名称为legacy的网络
        aliases: # 在legacy网络中的别名
          - mysql

networks:
  new: # 定义一个网络,名称为new
  legacy: # 定义一个网络,名称为legacy
# 13
ports:暴露的端口信息,会映射到宿主机端口,另外为了避免语法出错,所有端口配置都必须使用字符串格式:
ports:
  - "3000"
  - "3000-3005"
  - "8000:8000"
  - "9090-9091:8080-8081"
  - "49100:22"
  - "127.0.0.1:8001:8001"
  - "127.0.0.1:5000-5010:5000-5010"
  - "6060:6060/udp"
  - "12400-12500:1240"
# 如果仅指定了容器端口,则会随机选择一个宿主机端口。

# 14
restart:指定容器退出后的重启策略。
# 包括下面的几种选项:
restart: "no" # 在任何情况下都不会重新启动容器
restart: always # 容器总是重新启动。
restart: on-failure # 遇到故障后重启
restart: unless-stopped # 总是重新启动容器,除非容器停止
# 生产环境建议配置为:`always`或者`unless-stopped`

# 15
volumes:指定要挂载的数据卷或目录。数据卷可以是某个service的局部数据卷,也可以是提前定义的全局数据卷(通过顶级参数volumes来指定)。
# 例如:
version: "3.8"
services:
  web:
    image: nginx:alpine
    volumes: # 完整的数据卷配置语法
      - type: volume
        source: mydata # 数据卷
        target: /data # 容器内目录
        volume:
          nocopy: true
      - type: bind
        source: ./static # 宿主机目录
        target: /opt/app/static # 容器内目录

  db:
    image: postgres:latest
    volumes: # 简化的数据卷语法
      # 将一个宿主机目录映射到容器内的某个目录
      - "/var/run/postgres.sock:/var/run/postgres/postgres.sock"
      # 将一个全局卷映射到容器内某个目录
      - "dbdata:/var/lib/postgresql/data"

volumes:
  mydata: # 定义全局的数据卷mydata
  dbdata: # 定义全局的数据卷dbdata

上面只是Compose的部分模板语法。

三、Docker Swarm

Docker-Compose负责定义Project和Service(服务)。

但是服务具体运行在哪个服务节点?需要多少个Docker容器来部署?这就要靠Docker Swarm来管理了。

Swarm 是使用 SwarmKit 构建的 Docker 引擎内置(原生)的集群管理和编排工具。

https://docs.docker.com/engine/swarm/

1. Docker Swarm概念

Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。

使用 Swarm 集群之前需要了解以下几个概念:

【1】 Node节点

什么是节点?

运行 Docker 的主机可以主动初始化一个 Swarm 集群或者加入一个已存在的 Swarm 集群**,这样这个运行 Docker 的主机就成为一个 Swarm 集群的节点 (node) 。**

节点的分类:

节点分为管理 (manager) 节点工作 (worker) 节点

**管理节点:**用于 Swarm 集群的管理,docker swarm 命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave 可以在工作节点执行)。一个 Swarm 集群可以有多个管理节点(高可用),但只有一个管理节点可以成为 leaderleader 通过 raft 协议实现。

**工作节点:**是任务执行节点,管理节点将服务 (service) 下发至工作节点执行。**管理节点默认也作为工作节点。**你也可以通过配置让服务只运行在管理节点。

Docker-Swarm的官方架构图:

image-20210615140501682

【2】 Service服务和Task任务

任务 (Task):是 Swarm 中的最小的调度单位,可以理解为一个单一的容器。

服务 (Services): 是指一组任务的集合,服务定义了任务的属性。服务有两种模式:

  • replicated services 按照一定规则在各个工作节点上运行指定个数的任务。
  • global services 每个工作节点上运行一个任务

两种模式通过 docker service create--mode 参数指定。

容器、任务、服务的关系图:

image-20210615140640291

2. 创建Swarm集群

我们知道 Swarm 集群由 管理节点工作节点 组成。

我们来创建一个包含一个管理节点和两个工作节点的最小 Swarm 集群。

启动3台虚拟机,计划如下:

虚拟机IP节点角色
192.168.200.150管理节点
192.168.200.151工作节点
192.168.200.152工作节点

注意:节点的IP请定义为自己的虚拟机IP。

【1】 创建管理节点

我们在节点192.168.200.150上运行一个命令:

docker swarm init --advertise-addr 192.168.200.150

因为我们的虚拟机可能有多个IP地址,这里通过--advertise-addr指定一个IP地址,

这里我选择的是我的NAT网卡的地址。

image-20201109005717431

执行命令效果如下:

image-20201109005806662

【2】 创建工作节点

通过上面执行的结果可以看到这样的提示:

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-40jgt6v1n59mb7aaw41yg10coxo2524tdgw2t6g2sorbiuflhj-5rymf91h0w2l9ic3adbkik39y 192.168.200.150:2377

所以,我们需要在另外两台机器192.168.200.151和192.168.200.152上执行命令:

docker swarm join --token SWMTKN-1-40jgt6v1n59mb7aaw41yg10coxo2524tdgw2t6g2sorbiuflhj-5rymf91h0w2l9ic3adbkik39y 192.168.200.150:2377

效果:

image-20201109010042542

【3】查看swarm集群

在管理节点:192.168.200.150上执行命令,查看swarm集群信息:

docker node ls

结果:

image-20201109010132298

此时,我们已经创建了一个最小的 Swarm 集群,包含一个管理节点和两个工作节点。

3. 部署单个服务

通过docker service create命令,可以创建一个service,并在swarm集群中运行。

【1】创建服务

在管理节点:192.168.200.150上运行代码:

docker service create --replicas 3 -p 80:80 --name nginx nginx

解读:

  • --replicas 3:代表这个服务要创建3个副本,也就是启动3个容器来运行nginx

如图:

image-20201109010318388

【2】 查看服务

通过docker service ls可以查看服务状态:

image-20201109010353253

通过docker service ps nginx命令可以查看nginx服务的运行节点信息:

image-20201109010429209

此时,我们通过浏览器访问:

http://192.168.200.150或者http://192.168.200.151或者http://192.168.200.152 都可以看到一样的效果:

image-20201109010457123

其它命令:我们可以使用 docker service scale 对一个服务运行的容器数量进行伸缩。

当业务处于高峰期时,我们需要扩展服务运行的容器数量。

docker service scale nginx=5

当业务平稳时,我们需要减少服务运行的容器数量。

docker service scale nginx=2

使用 docker service rm 来从 Swarm 集群移除某个服务。

docker service rm nginx

4. 部署多个服务

使用 docker service create 一次只能部署一个服务,

使用 docker-compose.yml 我们可以一次启动多个关联的服务并部署到swarm集群中。

接下来,我们就来搭建一个多服务的集群,包括下面的服务:

  • web:就是之前在docker-compose案例中的Java项目,依赖于redis进行计数。部署3个
  • redis:redis数据库,记录某个IP的访问次数,部署1个,在管理节点。
  • nginx:nginx服务,对3个web服务反向代理,部署1个,在管理节点

部署计划表:

服务名称部署数量节点IP
web3192.168.200.150, 192.168.200.151, 192.168.200.152
redis1192.168.200.150
nginx1192.168.200.150

结构如下:

image-20210615141241172

【1】 准备镜像

首先,我们需要在3个docker节点上都准备java项目的镜像。

1)上传

找到之前准备的docker-demo这个文件夹:

image-20201109001027719

分别上传到3个docker节点的 /opt/docker-compose 目录:

image-20201109191940004

2)构建镜像

然后分别在3个docker节点中运行下面的命令:

docker build -t web:latest .

通过docker images查看镜像:

image-20200722135509465

【2】 编写nginx配置

我们需要用nginx反向代理3个web节点,因此需要编写一个nginx的配置文件。

nginx部署在管理节点:192.168.200.150,所以进入这个节点的/opt/docker-compose/swarm目录下,

创建一个nginx.conf文件,内容如下:

worker_processes  1;
events {
    worker_connections 1024;
}  
http {
    default_type  text/html; # 默认响应类型是html
	
	server {
		listen 80;
		location /hello {
            # 代理/hello路径,会代理到web服务的9090端口
			proxy_pass http://web:9090;
		}
		location / {
			root	/usr/share/nginx/html;
		}
	}
}

注意:proxy_pass http://web:9090:**会把请求代理到web服务的9090端口。**Docker-Swarm会自动对3个docker节点的web服务负载均衡

【3】 编写docker-compose

swarm下的docke-swarm会有一些变化,

修改管理节点(192.168.200.150)下的docker-compose.yml文件,内容如下:

version: '3'
services:
  web:
    image: "web:latest"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 3
  redis:
    image: "redis:latest"
    networks:
      - overlay
    deploy:
      placement:
        constraints: [node.role == manager]
  nginx:
    image: "nginx:latest"
    networks:
      - overlay
    ports:
      - "80:80"
    volumes:
      - $PWD/nginx.conf:/etc/nginx/nginx.conf
    deploy:
      placement:
        constraints: [node.role == manager]
networks:
  overlay:
  
说明:
- service:服务,包括3个
  - web:java项目
    - image:指定web服务的镜像,就是刚刚自己打包的`web:latest`
    - networks: 网络配置,这里是用了默认的overlay格式,是swarm模式的固定格式
    - deploy:swarm下的部署配置
      - mode:replicated代表在多个节点上做备份
      - replicas: 3 ,备份数量为3,即web服务会部署到swarm集群的随机3个节点
  - redis:redis数据库
    - image: "redis:latest",指定用到的镜像是redis最新镜像
    - deploy:swarm下的部署配置
      - placement: 指定部署位置
        -  constraints: [node.role == manager] 部署到manager节点
  - nginx:nginx服务
    - image: "nginx:latest",指定镜像名称
    - networks: 指定网络,这里是用了默认的overlay格式,是swarm模式的固定格式
    - ports: 对外暴露的端口为80
    - volumes: 数据卷,指定当前目录下的nginx.conf文件挂载到容器中
    - deploy: 部署,指定部署位置到manager节点

【4】 部署运行

多服务运行与单个服务命令不同,在管理节点(192.168.200.150)运行下面的命令:

docker stack deploy -c docker-compose.yml counter

说明:

  • docker stack:就是通过docker-compose部署的命令
  • -c docker-compose.yml:指定docker-compose文件位置
  • counter:给部署的集群起个名字

运行过程如图:

image-20201109193630473

通过docker stack ls可以查看到当前集群信息:

image-20201109193723407

通过docker stack ps [集群名] 可以查看集群中的服务信息:

docker stack ps counter
# 或者 docker stack services counter

image-20201109195315745

此时,访问浏览器:http://192.168.200.150/hello

通过命令可以查看运行日志:

docker service logs -f counter_web

image-20201109195354830

多次访问浏览器,可以看到,Docker-Swarm会自己对3个web服务做负载均衡:

image-20201109195456557

四、持续集成&持续部署

1. 什么是持续集成&持续部署

随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件
开发的质量已经慢慢成为开发过程中不可回避的问题。互联网软件的开发和发布,已经形成了一套标准流程。

如: 在互联网企业中,每时每刻都有需求的变更,bug的修复, 为了将改动及时更新到生产服务器上,下面的图片我们需要每天执行N多次,开发人员完整代码自测后提交到git,然后需要将git中最新的代码生成镜像并部署到测试服务器,如果测试通过了还需要将最新代码部署到生产服务器。如果采用手动方式操作,那将会浪费大量的时间浪费在运维部署方面。

image-20210615141927480

现在的互联网企业,基本都会采用以下方案解决:

持续集成(Continuous integration,简称 CI)。

持续部署(continuous deployment, 简称 CD)

1. 持续集成

持续集成:频繁地(一天多次)将代码集成到主干

好处主要有两个:

  • 快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。

  • 防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

持续集成的目的:

就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。

Martin Fowler 说过,”持续集成并不能消除 Bug,而是让它们非常容易发现和改正。”

与持续集成相关的,还有两个概念,分别是持续交付和持续部署。

2. 持续交付

持续交付(Continuous delivery)指的是**,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。**

如果评审通过,代码就进入生产阶段。

持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。

3. 持续部署

持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。

持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。

持续部署的前提是能自动化完成测试、构建、部署等步骤。

4. 演示流程说明

持续集成中的任何一个环节都是自动完成,无需太多的人工干预,有利于减少重复过程以节省时间、费用和工作量;演示一套基本的自动化持续集成和持续部署方案,理解互联网企业的软件部署方案。

作用:保证团队开发人员提交代码的质量,减轻了软件发布时的压力;

流程如下:

image-20210615142706267

实现流程:

  1. 开发人员将代码提交到 git 指定分支 如: dev
  2. git仓库触发push事件,发送webhooks通知到持续集成软件
  3. 持续集成软件触发构建任务,对dev分支的代码进行构建、编译、单元测试
  4. 如果构建失败,发送邮件提醒代码提交人员或管理员
  5. 如果构建成功,最新代码将会被构建Docker镜像并上传到注册中心
  6. 构建成功触发webhooks通知容器编排软件,进行服务升级
  7. 容器编排软件,触发对应的服务升级任务, 将创建对应服务的新容器替换之前的容器
  8. 完成最新代码的自动构建与自动部署,全程无工作人员干预

要实现上面流程,我们需要了解两款新的软件 jenkinsrancher

2. CI&CD jenkins

1. jenkins介绍

Jenkins,原名Hudson,2011年改为现在的名字,它是一个开源的实现持续集成的软件工具。

官方网站:http://jenkins-ci.org/ 。

Jenkins 能实施监控集成中存在的错误,提供详细的日志文件和提醒功能,

还能用表的形式形象地展示项目构建的趋势和稳定性。

特点:

  • 易配置:提供友好的GUI配置界面;
  • 变更支持:Jenkins能从代码仓库(Subversion/CVS)中获取并产生代码更新列表并
    输出到编译输出信息中;
    支持永久链接:用户是通过web来访问Jenkins的,而这些web页面的链接地址都是
    永久链接地址,因此,你可以在各种文档中直接使用该链接;
  • 集成E-Mail/RSS/IM:当完成一次集成时,可通过这些工具实时告诉你集成结果(据
    我所知,构建一次集成需要花费一定时间,有了这个功能,你就可以在等待结果过程
    中,干别的事情);
  • JUnit/TestNG测试报告:也就是用以图表等形式提供详细的测试报表功能;
  • 支持分布式构建:Jenkins可以把集成构建等工作分发到多台计算机中完成;
    文件指纹信息:Jenkins会保存哪次集成构建产生了哪些jars文件,哪一次集成构建使
    用了哪个版本的jars文件等构建记录;
  • 支持第三方插件:使得 Jenkins 变得越来越强大
【1】jenkins安装配置

jenkins的官方文档中提供了多种安装方式,本文选择docker的安装方式来使用jenkins

拉取jenkins镜像

docker pull jenkins/jenkins:lts-centos7 

创建jenkins容器

docker run -d --name myjenkins -p 8888:8080 \
jenkins/jenkins:lts-centos7

查看jenkins启动日志

docker logs -f myjenkins

启动成功后 访问:

http://your_ip:8888

配置镜像加速

安装完毕后需要先配置一下镜像加速,默认的镜像中心是国外的网址,国内使用非常卡。

我们选择的镜像中心是 清华大学开源软件镜像站

配置方式:

(1)进入到数据卷路径

# 启动容器
docker exec -it -u root myjenkins bash
# 查看数据卷路径
# 进入到该路径
cd /var/jenkins_home/

1605852711191

(2)修改镜像加速配置

修改 jenkins 数据目录中的hudson.model.UpdateCenter.xml值为:
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

# 修改配置文件
vi hudson.model.UpdateCenter.xml 

# 将url标签内网址替换成上面网址

1605509017789

(3)将/var/jenkins_home/updates/default.json中的网址内容替换

# 编辑配置文件
vi ./updates/default.json

# 将内容中所有google的地址改为baidu   直接":"复制下面命令 并回车
:%s#http://www.google.com#http://www.baidu.com#g

# 将配置中所有的官网路径替换为镜像中心的下载路径 直接":"复制下面命令 并回车
:%s#https://updates.jenkins.io/download#https://mirrors.tuna.tsinghua.edu.cn/jenkins#g

# 注意 上面两个命令的 ":"号为手敲的,请复制":"号后面内容

# 操作完成 保存退出
:wq

# 退出容器
exit

1605852883731

(4)重启jenkins容器 ,然后访问:http://your_ip:8888 准备解锁

docker restart myjenkins
【2】解锁jenkins

第一次运行时,需要先解锁jenkins

具体步骤:

  1. 去容器中 指定文件查看管理员密码
  2. 将密码拷贝到文本框
  3. 点击继续即可
image-20210615143953648

具体解锁的管理员密码,在jenkins的安装目录中,因为我们是采用的容器安装,所以需要进入到容器中查看

# 进入到jenkins容器
docker exec -it myjenkins bash

# 查看密码
cat /var/jenkins_home/secrets/initialAdminPassword

# 将密码复制到上图管理员密码文本框,然后点击继续 完成解锁

1605492836529

【3】安装推荐插件

jenkins的各项功能,依赖各种插件,可以手工选择安装也可以按照推荐安装

1605853350105

课程中直接安装推荐插件, 注意如果加速没配置成功,这里将会非常慢,或者下载失败

1605853419987

可能因为网络会安装失败,我们课程主要使用git 和 chinese中文插件,可以直接继续忽略错误插件,或者点击重试尝试重新安装

1605855113170

创建管理员用户

插件安装完毕后,会进入到设置管理员用户页面,按自己需求设置就好,后续登录可以使用

设置完毕后点击保存并完成则进入到jenkins欢迎页

1605855220823

接下来,jenkins会让我们确认jenkins服务端的地址,直接下一步就好,

1605855267177

然后点击开始使用jenkins进入到jenkins页面

1605855290646

进入到jenkins页面, 如果这个时候你的页面都是英文的话,重启下就好

(因为上面安装默认插件中已经安装了 中文插件)

1605855341537

【4】配置maven环境

对于git中项目的构建我们要使用到maven命令,那么在jenkins中需要下载对应的maven插件,以及jenkins所在的容器也要有maven环境

(1) 下载maven插件:

点击系统管理 --> 点击插件管理 --> 进入到插件管理页面

1605855531632

1605855558517

点击可选插件 --> 输入maven --> 勾选Maven Integration --> 下载待重启安装

1605856223602

等待下载完成后,重启jenkins容器即可

1605856272958

(2) 安装maven环境

将资源中的maven安装包,拷贝到容器中解压即可,在配置好阿里云镜像

1605511349048

将maven压缩包拷贝容器解压

# 目录根据自己实际情况来
docker cp ./apache-maven-3.6.3-bin.tar.gz myjenkins:/var/jenkins_home/
# 进入到容器
docker exec -it -u root myjenkins bash
# 将maven解压
tar -zxvf /var/jenkins_home/apache-maven-3.6.3-bin.tar.gz 

配置maven镜像

# 配置阿里云镜像
vi /var/jenkins_home/apache-maven-3.6.3/conf/settings.xml 
# 阿里云镜像
<mirror>
	<id>alimaven</id>
	<mirrorOf>central</mirrorOf>
	<name>aliyun maven</name>  		    <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>

1605511710918

设置maven环境变量

# 设置maven_home环境变量
vi /etc/profile
#点击i进入编辑模式 输入
MAVEN_HOME=/var/jenkins_home/apache-maven-3.6.3
export MAVEN_HOME
export PATH=${PATH}:${MAVEN_HOME}/bin
#保存退出
:wq
# 是资源文件生效(这样就不用重启系统了)
source /etc/profile 
# 查看是否配置成功
mvn -v

# 将maven的路径设置的jenjins中 /var/jenkins_home/apache-maven-3.6.3

(3) jenkins中配置maven环境

系统管理中点击全局工具配置

1605856856869

  1. 新增maven
  2. name随意,MAVEN_HOME: /var/jenkins_home/apache-maven-3.6.3
  3. 取消勾选自动安装
  4. 保存即可

1605857052762

完成后,我们就可以通过jenkins创建构建任务啦~~~

2. jenkins快速入门

【1】 准备要部署的工程

准备工作,导入资源中的docker-demo工程, 在pom中添加docker-maven插件配置,

注意将IP部分变成自己虚拟机的IP

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itheima.sh</groupId>
    <artifactId>docker_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>app</finalName>
        <plugins>
            <!-- 打jar包时如果不配置该插件,打出来的jar包没有清单文件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- 插件网址:https://github.com/spotify/docker-maven-plugin -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.0</version>
                <configuration>
                    <imageName>192.168.200.129:5000/${project.artifactId}:${project.version}</imageName>
                    <baseImage>java:8-alpine </baseImage>
                    <entryPoint>["java","-jar","/${project.build.finalName}.jar"]</entryPoint>
                    <resources>
                        <resource>
                               <targetPath>/</targetPath>
                               <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                    <dockerHost>http://192.168.200.129:2375</dockerHost>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

将项目上传到码云(gitee.com)中

Git中的地址: https://gitee.com/xiaoT_CJ/docker_demo.git

1605857194795

【2】 创建maven构建任务

(1) 新建jenkins任务

在jenkins的首页的第一个页签就是用于构建任务,点击新建任务:

1605857248023

定义任务名名称,勾选构建模板 保存任务

1605857313183

(2) 设置任务的构建信息:

描述信息设置

1605857417849

**源码设置 ***

jenkins可以根据配置的源码地址获取源码,来用于构建,配置如下:

  1. 选择git仓库

  2. 设置git仓库地址

  3. 如果是私有仓库需要添加凭证

  4. 选择仓库分支

1605857556647

构建触发器:

什么情况可以触发此任务,或者定时触发此任务,暂不设置

构建设置

  1. Pre Steps 构建的前置任务,可以在构建执行前触发一些通知或脚本的执行
  2. build 要执行的构建任务
  3. PostSteps 构建的后置任务,可以在完成构建后触发的一些通知或脚本的执行

构建任务配置如下:

Root POM: 本次构建要使用的git仓库中的pom文件

Goals and options: 要执行的mvn命令 不用写前面的mvn

# maven命令 
clean package -DskipTests docker:build -DpushImage

# 依次:
# 清除 打包 跳过单元测试 远程构建镜像  上传镜像到注册中心

1605857730695

构建结果通知

可以将构建结果,通知给配置的管理员或触发此任务的代码上传人员,本文不配置

1605857813161

保存任务

点击保存即可

【3】 执行maven构建任务

(1)执行构建任务

当我们保存完毕任务之后,会进入到任务的详情页面, 点击立即构建即可执行该构建任务

1605858494552

或者返回首页面板,也能看到任务列表,列表后面的图标也可以用于构建

1605858525007

(2) 查看任务执行日志

点击构建后,在页面左下会出现任务的执行状态,点击进度条进入到任务构建详情中

1605858565132

可以通过控制台输出页面,查看控制台信息,和我们在idea控制中看到的信息类似

第一次执行会下载很多maven依赖

1605858604063

实际上,jenkins是从我们配置的git中拉取了源码信息,在使用maven的命令进行构建

(3) 查看任务构建结果

控制台出现 BUILD SUCCESS 代表构建成功啦

1605858832629

对应的虚拟机中已经有了这个镜像

1605858872571

对应的注册中心中也上传了此镜像

1605858902175

OK 那么接下来基于这个镜像构建出容器,我们就完成了部署。

3. 容器编排平台 Rancher

1. Rancher介绍

前面我们了解了容器编排的概念,如: docker 的Swarm google的k8s, 但是这些软件的入门门槛很高,需要我们记住很多命令,那么下面我们介绍一款软件 Rancher,它可以基于上面的容器编排软件,提供可视化的操作页面 实现容器的编排和管理。

Rancher是一个开源的企业级全栈化容器部署及管理平台。Rancher为容器提供一揽
子基础架构服务:CNI兼容的网络服务、存储服务、主机管理、负载均衡、防护墙……
Rancher让上述服务跨越公有云、私有云、虚拟机、物理机环境运行,真正实现一键式应
用部署和管理。
https://www.cnrancher.com/

2. Rancher快速入门

【1】 安装Rancher

下载rancher

docker pull rancher/server

创建rancher容器

docker run -d --name=myrancher -p 9090:8080 rancher/server

查看rancher启动日志

docker logs -f myrancher

访问Rancher: http://your_ip:9090/

1605859055814

页面右下角 点击下拉框 选择简体中文

1605859091466

【2】 配置环境

在互联网项目中,可能会有多套部署环境 如: 测试环境 、 生产环境,不同的环境下会有不同的服务器 Rancher支持多环境多服务器管理

默认 我们处于default的默认环境中,点击环境管理可以创建环境

1605859140946

点击添加环境可以定义一个环境

1605859175441

构建环境时,需要设置环境的名称、环境描述、及环境模板

可以看到 环境模板支持多套,所谓的环境模板就是底层使用哪种编排工具

rancher支持 cattle、swarm、k8s、mesos等,默认使用cattle

1605859229797

入门案例我们使用内置的Cattle模板即可,添加后列表出现刚创建的环境

1605859274224

切换到prod环境中

1605859327642

【3】配置主机

在不同的环境中可以会有不同的服务器,要想让我们的rancher能够管理这些服务器,需要在基础架构中添加主机

(1) 添加主机

点击基础架构下拉框中的主机 --> 在点击添加主机

1605859380135

(2) 复制脚本

确认站点地址是否正确,然后点击保存

1605859418202

复制脚本:

  1. 要管理的主机IP 如: 要管理 192.168.200.153的虚拟机
  2. 复制脚本,将脚本复制到192.168.200.153的机器上执行
  3. 执行完毕后关闭此页面,等待主机连接

1605859501301

(3) 到主机中执行脚本

如: 到我的192.168.200.153的虚拟机中 执行如下命令:

1605859702912

运行完毕后,在rancher的页面上,关闭窗口 可以在主机列表中看到对应服务器信息

(需要等待主机中下载镜像及启动相关容器)

1605859795273

显示active 代表服务器当前状态可用, 如果报红 或显示reconnecting则为重连状态,等待一会即可

【4】 管理容器

连接成功后,我们可以点击基础架构下的容器 进行容器的管理

1605859864458

说明:

(1)页面提供了对应主机上的容器管理功能,额外创建的容器都是系统容器,用于rancher的管理,可以通过 取消勾选显示系统容器进行过滤

(2)点击添加容器,可以通过简单配置构建一个容器

​ 如: 构建一个redis容器

  1. 点击添加容器
  2. 配置容器名称、描述、镜像、端口映射即可

1605860222158

1605860305990

(3)容器列表结尾提供了容器的 重启、删除、查看日志等功能

1605860374959

3. Rancher中的应用与服务

【1】应用与服务的概念

上面的容器管理,仅仅是提供了容器的管理页面,但对于企业级的项目部署 会涉及到集群扩容缩容、服务升级、负载均衡等等高可用的管理。需要在Rancher中通过定义应用与服务的设置来管理。

应用(Project): 代表一个项目 如: 电商项目

服务(Service):代表一个服务 如: 电商项目下的订单微服务

1605841694459

【2】 创建应用与服务

和我们学习的swarm类似,我们可以创建一个应用project 一个应用下可以包含多个服务

service , 一个服务下可以运行多个相同的容器container

创建应用

1605860470039

点击到环境首页,创建应用 : 应用名称、描述 点击创建

1605860527144

添加服务

在刚创建好的myPro应用中添加服务

1605860574808

设置服务信息:

  1. 容器名称(rancher中显示的名称)
  2. 描述
  3. 构建创建前拉取最新镜像
  4. 镜像的名称

1605860684047

点击创建,可以看到容器已经运行

1605860739570

在docker中也有对应的服务

1605861203059

【3】演示服务扩容

点击左侧的 数量加减 会自动对服务进行扩容 缩容

1605861284552

【4】 演示服务负载均衡

不过我们当前服务集群 并没有配置端口映射,因此外部无法访问,需要配置负载均衡

回到服务列表,添加负载均衡

1605861417894

配置负载均衡

​ 1.负载均衡名称 : lbdockerDemo

​ 2.负载均衡描述 : dockerDemo的负载均衡

​ 3.访问端口: 9001

​ 4.目标服务: myPro/dockerDemo

​ 5.映射服务容器端口: 9090

1605861694062

访问测试: http://192.168.200.153:9001/hello 多次点击

1605862007802

依次查看3个容器的日志

1605862093699

1605862150892

1605862172571

1605862198473

​ 已经实现了负载均衡效果~~~~

【5】演示服务升级

访问当前服务 http://192.168.200.153:9001/hello

1605862007802

变更当前代码

1605862350110

push提交到git

1605862398258

执行jenkins构建任务,将最新的代码打包成新镜像,并上传到注册中心

1605862470028

构建成功后,在rancher中进行服务升级 在详情页面或列表页面都有向上的箭头代表服务升级

1605862595138

填写升级信息, 启动行为勾选:

这样会先根据最新镜像创建容器,创建完毕后,在将之前的容器删除,来完成服务的更新

点击升级

1605862644211

最后,点击完成升级 旧的容器将被删除掉

1605862717768

刷新页面,可以看到服务已经升级完毕

1605862795808

也就意味着完成服务的一键部署

4. 自动集成及自动部署

上面的演示中,当我们把idea上的代码提交到git中之后, 手动的点击了jenkins中的构建任务,完成镜像的构建和上传注册中心。 然后,在到rancher软件中,根据最新的镜像完成一键升级。 那么自动化的流程就是让这两部也变成自动的,我们只需要将代码上传到指定分支将会自动化的完成构建与升级部署。

1. 自动通知jenkins触发任务

主流的git软件都提供了webhooks功能(web钩子), 通俗点说就是git在发生某些事件的时候可以通过POST请求调用我们指定的URL路径,那在这个案例中,我们可以在push事件上指定jenkins的任务通知路径。

【1】jenkins配置Gitee插件

jenkins下载webhooks插件

gitee插件介绍: https://gitee.com/help/articles/4193#article-header0

jenkins也支持通过url路径来启动任务,具体设置方法:

jenkins的默认下载中仅下载了github的通知触发,我们需要先下载一个插件

(1) 下载gitee插件

系统管理–>插件管理–>可选插件–>搜索 Gitee 下载–>重启jenkins

1605863059692

(2) gitee生成访问令牌

首先,去下面网址生成gitee访问令牌

https://gitee.com/profile/personal_access_tokens

1605863332642

添加令牌描述,提交,弹出框输入密码

1605863372394

复制令牌

1605863446752

(3) jenkins中配置Gitee

系统管理 --> 系统配置 --> Gitee配置

  1. 链接名: gitee
  2. 域名: https://gitee.com
  3. 令牌: Gitee Api 令牌 (需要点击添加按下图配置)
  4. 配置好后测试连接
  5. 测试成功后保存配置

1605864020886

令牌配置:

  1. 类型选择Gitee API令牌
  2. 私人令牌: 将码云中生成的令牌复制过来
  3. 点击添加

1605863756159

【2】 修改jenkins构建任务

修改配置接收webhooks通知

任务详情中点击配置来修改任务

1605864126335

点击构建触发器页签,勾选Gitee webhook

1605864258058

生成Gitee Webhook密码

1605864316485

保存好触发路径和webhook密码,到gitee中配置webhook通知

如:

触发路径: http://192.168.200.151:8888/gitee-project/dockerDemo

触发密码: a591baa17f90e094500e0a11b831af9c

【3】 Gitee添加webhooks通知

gitee仓库配置webhooks通知

点击仓库页面的管理

1605864527636

添加webhook

  1. 点击webhooks菜单,然后点击添加
  2. 配置jenkins通知地址
  3. 填写密码
  4. 点击添加

1605864641490

但在点击添加时,提示失败 gitee中需要配置一个公有IP或域名,这里我们可以通过内网穿透来解决

1605877091111

【4】 配置内网穿透

内网穿透的小工具很多,这里面我们使用 https://u.tools/ 提供的内网穿透功能

第一次安装后,需要在搜索框搜索内网穿透插件进行安装

1605865384912

安装完毕后,点击内网穿透

1605865373106

配置内网穿透:

节点选择: utools.club(测试)

外网域名: 自定义

内网地址: jenkins的ip

内网端口: jenkins的port

1605864913171

连接成功: 即可使用外网地址访问我们的jenkins

1605864953965

在gitee中将上面的外网地址替换之前的ip和端口部分,再次添加

1605865030530

添加成功

1605865068688

【5】 测试自动构建

添加完毕后测试一下:

点击webhooks,发送测试请求

1605865165520

点击查看更多结果,200代表请求成功

1605865187110

不过这个时候jenkins中的任务是没被触发的,我们尝试从idea中上传代码,看看任务是否自动构建

1605865240447

上传代码

1605865274308

代码上传到git后,自动触发了jenkins中的构建任务

1605865321314

2. 自动通知Rancher触发升级

【1】 Rancher配置接收器

在rancher中,配置接收器来接收webhooks通知

在api下拉菜单下,点击webhooks添加接收器

1605865468861

  1. 名称:自定义即可

  2. 类型:支持扩容,缩容,和服务升级 我们演示服务升级

  3. 参数格式: Docker Hub即可

  4. 镜像标签: 对应镜像的标签

  5. 服务选择器: 我们的服务也可以设置标签, 如: 当前标签service=demo

​ 当这个接收器被触发时,所有服务包含此标签的 service=demo 则会触发服务升级

  1. 后面参数的概念:

先启动一个新容器, 启动成功后停止老容器,最后删除老容器完成升级

1605865636247

保存,复制触发url路径

1605865748613

触发路径:

http://192.168.200.151:9090/v1-webhooks/endpoint?key=e4NhUC14Z9kLdXcAC0fwY0i1DHiF3blZ0Dw63O8M&projectId=1a7

【2】 服务添加标签

最后,给我们的服务设置标签,删除之前的服务,重新添加服务

注意在下面标签下的内容,一致要和接收器设置的标签和值一致此服务才会触发升级

标签: service demo

1605865883584

【3】 测试服务升级

通过POSTMAN进行测试

在触发请求时还需要携带一些必要的参数:

  1. 镜像的标签 tag: 这个标签的值要和上面接收器中的标签值一致才可以触发
  2. 仓库的名称 repo_name: 镜像的仓库名称
{
    "push_data": {
        "tag": "1.0-SNAPSHOT"
    },
    "repository": {
        "repo_name": "192.168.200.153:5000/docker_demo"
    }
}

1605876553176

点击完毕后观察rancher中服务列表变化,会发现服务将自动完成升级

1605876692157

【4】 配置jenkins的后置处理

最后,让jenkins来触发rancher,修改jenkins中的配置

  1. 在构建完毕的后置处理步骤中添加 执行Shell脚本
  2. 选择Run only if build succeeds 仅在构建成功时运行下面脚本
  3. 执行脚本

注意: 调用的路径是我们接收器所生成的路径

tag: 是镜像的tag标签

repo_name: 是对应镜像的仓库名称

要根据自己的实际情况修改哦~~~~~

curl "http://192.168.200.151:9090/v1-webhooks/endpoint?key=e4NhUC14Z9kLdXcAC0fwY0i1DHiF3blZ0Dw63O8M&projectId=1a7" \
-H "Content-Type:application/json" \
-d "{\"push_data\": {\"tag\": \"1.0-SNAPSHOT\"},\"repository\": {\"repo_name\": \"192.168.200.153:5000/docker_demo\"}}"

1605876863912

3. 自动集成&自动部署演示

操作步骤:

  1. 变更代码并上传到git
  2. 注意jenkins任务是否被触发
  3. 注意rancher自动升级是否被触发
  4. 访问项目查看变更是否生效

OK,如果成功了,说明你只需要提交代码就可以了, 和部署相关 编译,测试,构建,上传镜像,服务升级,扩容缩容全部交给工具吧~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值