在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。这些资源的新虚拟部份是不受现有资源的架设方式,地域或物理组态所限制。一般所指的虚拟化资源包括计算能力和资料存储。
在实际的生产环境中,虚拟化技术主要用来解决高性能的物理硬件产能过剩和老的旧的硬件产能过低的重组重用,透明化底层物理硬件,从而最大化的利用物理硬件 对资源充分利用
虚拟化技术种类很多,例如:软件虚拟化、硬件虚拟化、内存虚拟化、网络虚拟化(vip)、桌面虚拟化、服务虚拟化、虚拟机等等。
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技术比虚拟机技术更为轻便、快捷。
容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。
虚拟机: 虚拟机是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
**Docker:Docker没有虚拟的硬件,也没有模拟操作系统,而是直接运行在宿主机上。**Docker会为每个应用进程形成隔离环境,让的应用进程以为自己是独立机器。因此Docker要比传统虚拟机更为轻便。
与传统的虚拟机相比,Docker优势体现为启动速度快、占用体积小。
特性 | Docker容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB |
一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
Docker是一个客户端-服务器(C/S)架构程序。Docker客户端(client)只需要向Docker服务器或者后台进程发出请求,服务器或者后台进程将完成所有工作并返回结果。
Docker中有三个很重要的概念:
Image
)Container
)Repository
)理解了这三个概念,就理解了 Docker 的整个生命周期。
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
Container
)镜像(Image
)和容器(Container
)的关系,就像是面向对象程序设计中的 类
和 实例
一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,Docker会保证隔离每一个容器进程。
容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root
文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。**这种特性使得容器封装的应用比直接在宿主运行更加安全。**也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。
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 下来就可以了。
技术存在的必然性,一个技术的存在都是为了解决指定的问题.
#什么是镜像?
将Linux程序基于运行环境打包,就是镜像,特征:
只读
分层,每一层都基于前一层,层称为Layer
#什么是容器?
容器是镜像运行的一个实例。
是将镜像做只读拷贝后创建一层可写的Layer层,然后创建独立内存、网络等空间并运行。
特征:
容器是宿主机的一个独立进程。
多个容器间相互独立
容器操作不影响镜像
#Docker作用?
软件或程序环境迁移
Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。
Docker CE 分为 stable
test
nightly
三个更新频道。
官方网站上有各种环境下的 安装指南,这里主要介绍 Docker CE 在 Linux
和 macOS
上的安装。
Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10, CentOS 7 满足最低内核的要求。
这里的 \
是换行的作用
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
# 安装基本依赖库
yum install -y yum-utils device-mapper-persistent-data lvm2 --skip-broken
# 更新XFS文件系统管理工具
yum update xfsprogs -y
# 更新本地镜像源
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
启动服务前先关闭防火墙
# 查看防火墙状态
systemctl status firewalld
# 关闭本地防火墙
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld
# 启动docker服务
systemctl start docker
# 设置开机自启动
systemctl enable docker
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
系统服务管理docker
# 启动docker
systemctl start docker
# 停止docker
systemctl stop docker
# 重启docker
systemctl restart docker
# 查看docker状态
systemctl status docker
# 开机启动
systemctl enable docker
操作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
操作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###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
#(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地址
# 查看容器运行的各种数据
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
数据卷
是一个可供一个或多个容器使用的特殊目录,一般是在宿主机的某个特定的目录下。
把变化的数据记录在容器之外的宿主机上,实现容器与数据的分离。
可以提供很多有用的特性:
数据卷
可以在容器之间共享和重用数据卷
的修改会立马在挂载数据卷的容器中可见数据卷
的更新,不会影响镜像数据卷
默认会一直存在,即使容器被删除通过docker volume
命令可以管理数据卷。
数据卷是一个虚拟的概念,一个数据卷指向宿主机上的一个文件夹
#创建数据卷
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地址
注:
在前面镜像原理的中,我们可以了解到,镜像的本质是一层层的Layer。
基于一个rootfs这个基础的Layer定制每一层所添加的配置、文件,要执行的操作等。
如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,
那么这个脚本就是 Dockerfile。
因此,Dockerfile就是一个描述镜像构建的文件。其中一定会有一个基础镜像(BaseImage),
然后在基础镜像上每完成一次修改或安装命令,就形成一层新的Layer,直到镜像构建完成。
作用:
对于开发人员:可以为开发团队提供一个完全一致的开发环境;
对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件构建一个新的镜像开始工作了;
对于运维人员:在部署时,可以实现应用的无缝移植。
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 | 设置工作目录 |
例如:
需求1:基于Nginx镜像构建一个新镜像,修改其中的index.html文件
#1.在一个空文件夹新建一个文件,命名为Dockerfile,内容如下
# 创建空文件夹
mkdir /tmp/nginxfile
# 进入空文件夹
cd /tmp/nginxfile
# 创建Dockerfile文件【文件名不能是其他】
vi Dockerfile
-----------------
FROM nginx:1.20.1
RUN echo 'Hello, Docker!
' > /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 命令将'Hello, Docker!
'写入容器的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
步骤:
(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
https://cr.console.aliyun.com/cn-hangzhou/instance
相关命令
将镜像推送到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的域名录。
# 安装镜像仓库镜像
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
====================================================
# 关闭或禁用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。
# 直接下载 或 本地加载
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
# 镜像
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
# 拉取镜像
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
命令说明:
# 创建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
命令说明:
# 拉取镜像
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
命令说明:
需要先关闭防火墙或者开放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/ 查看控制台信息
# 拉取镜像
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
# 下载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/
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在集群中的部署如同单机部署一样的方便,那就需要用到容器编排技术了。
“编排”(Orchestration)在云计算行业里不算是新词汇,它主要是指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义、配置、创建、删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。
而容器时代,“编排”显然就是对 Docker 容器的一系列定义、配置和创建动作的管理。目前容器编排技术比较知名的包括:
Docker Compose
是 Docker 官方编排(Orchestration)项目之一,负责快速的部署分布式应用,
官网地址: https://github.com/docker/compose ,其前身是开源项目 Fig。
本节将介绍 Compose
项目情况以及安装和使用。
网址:https://docs.docker.com/compose/compose-file/
作用: 定义一组相关联的应用容器为一个项目,定义各个容器的依赖关系
Compose
恰好满足了Docker集群化的需求。它允许用户通过一个单独的 docker-compose.yml
模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
场景:
通过Dockerfile我们可以将一个项目很方便的打包为一个Docker镜像。但是在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。如何**定义各个容器的依赖关系,**这就需要用到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
假设我们要部署一个SpringBoot项目,并且依赖于Redis。
工程的基本功能就是统计用户的访问量,代码在资料
中,直接解压到没有中文的目录下,使用Idea导入即可。
(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.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
目录:
然后执行命令:
docker-compose up
docker ps
构建完成后,可以看到项目运行的日志信息:
此时,访问浏览器 http://192.168.182.40:9090/hello,
如果多次访问,这个次数会累加。
按次CTRL+C
后可以停止运行程序,并且Docker运行的容器中也会关闭。
通过docker-compose up -d
命令,可以后台启动,这样就不会显示日志:
通过docker-compose stop
关闭容器
通过docker-compose down
关闭容器并删除
通过:docker-compose —help
查看
[root@localhost docker-demo]# docker-compose --help
利用Docker来定义和构建一个多容器的应用
使用方式:
docker-compose [-f ...] [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
.............
.............
详细语法参考文档: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.+ |
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来完成。
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-Compose负责定义Project和Service(服务)。
但是服务具体运行在哪个服务节点?需要多少个Docker容器来部署?这就要靠Docker Swarm来管理了。
Swarm
是使用 SwarmKit
构建的 Docker 引擎内置(原生)的集群管理和编排工具。
https://docs.docker.com/engine/swarm/
Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。
使用 Swarm
集群之前需要了解以下几个概念:
什么是节点?
运行 Docker 的主机可以主动初始化一个 Swarm
集群或者加入一个已存在的 Swarm
集群**,这样这个运行 Docker 的主机就成为一个 Swarm
集群的节点 (node
) 。**
节点的分类:
节点分为管理 (manager
) 节点和工作 (worker
) 节点。
**管理节点:**用于 Swarm
集群的管理,docker swarm
命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave
可以在工作节点执行)。一个 Swarm
集群可以有多个管理节点(高可用),但只有一个管理节点可以成为 leader
,leader
通过 raft
协议实现。
**工作节点:**是任务执行节点,管理节点将服务 (service
) 下发至工作节点执行。**管理节点默认也作为工作节点。**你也可以通过配置让服务只运行在管理节点。
Docker-Swarm的官方架构图:
任务 (Task
):是 Swarm
中的最小的调度单位,可以理解为一个单一的容器。
服务 (Services
): 是指一组任务的集合,服务定义了任务的属性。服务有两种模式:
replicated services
按照一定规则在各个工作节点上运行指定个数的任务。global services
每个工作节点上运行一个任务两种模式通过 docker service create
的 --mode
参数指定。
容器、任务、服务的关系图:
我们知道 Swarm
集群由 管理节点 和 工作节点 组成。
我们来创建一个包含一个管理节点和两个工作节点的最小 Swarm
集群。
启动3台虚拟机,计划如下:
虚拟机IP | 节点角色 |
---|---|
192.168.200.150 | 管理节点 |
192.168.200.151 | 工作节点 |
192.168.200.152 | 工作节点 |
注意:节点的IP请定义为自己的虚拟机IP。
我们在节点192.168.200.150上运行一个命令:
docker swarm init --advertise-addr 192.168.200.150
因为我们的虚拟机可能有多个IP地址,这里通过--advertise-addr
指定一个IP地址,
这里我选择的是我的NAT网卡的地址。
执行命令效果如下:
通过上面执行的结果可以看到这样的提示:
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
效果:
在管理节点:192.168.200.150上执行命令,查看swarm集群信息:
docker node ls
结果:
此时,我们已经创建了一个最小的 Swarm
集群,包含一个管理节点和两个工作节点。
通过docker service create
命令,可以创建一个service,并在swarm集群中运行。
在管理节点:192.168.200.150上运行代码:
docker service create --replicas 3 -p 80:80 --name nginx nginx
解读:
--replicas 3
:代表这个服务要创建3个副本,也就是启动3个容器来运行nginx如图:
通过docker service ls
可以查看服务状态:
通过docker service ps nginx
命令可以查看nginx服务的运行节点信息:
此时,我们通过浏览器访问:
http://192.168.200.150或者http://192.168.200.151或者http://192.168.200.152 都可以看到一样的效果:
其它命令:我们可以使用 docker service scale
对一个服务运行的容器数量进行伸缩。
当业务处于高峰期时,我们需要扩展服务运行的容器数量。
docker service scale nginx=5
当业务平稳时,我们需要减少服务运行的容器数量。
docker service scale nginx=2
使用 docker service rm
来从 Swarm
集群移除某个服务。
docker service rm nginx
使用 docker service create
一次只能部署一个服务,
使用 docker-compose.yml
我们可以一次启动多个关联的服务并部署到swarm集群中。
接下来,我们就来搭建一个多服务的集群,包括下面的服务:
部署计划表:
服务名称 | 部署数量 | 节点IP |
---|---|---|
web | 3 | 192.168.200.150, 192.168.200.151, 192.168.200.152 |
redis | 1 | 192.168.200.150 |
nginx | 1 | 192.168.200.150 |
结构如下:
首先,我们需要在3个docker节点上都准备java项目的镜像。
1)上传
找到之前准备的docker-demo
这个文件夹:
分别上传到3个docker节点的 /opt/docker-compose
目录:
2)构建镜像
然后分别在3个docker节点中运行下面的命令:
docker build -t web:latest .
通过docker images
查看镜像:
我们需要用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服务负载均衡
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节点
多服务运行与单个服务命令不同,在管理节点(192.168.200.150)运行下面的命令:
docker stack deploy -c docker-compose.yml counter
说明:
docker stack
:就是通过docker-compose部署的命令-c docker-compose.yml
:指定docker-compose文件位置counter
:给部署的集群起个名字运行过程如图:
通过docker stack ls
可以查看到当前集群信息:
通过docker stack ps [集群名]
可以查看集群中的服务信息:
docker stack ps counter
# 或者 docker stack services counter
此时,访问浏览器:http://192.168.200.150/hello
通过命令可以查看运行日志:
docker service logs -f counter_web
多次访问浏览器,可以看到,Docker-Swarm会自己对3个web服务做负载均衡:
随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件
开发的质量已经慢慢成为开发过程中不可回避的问题。互联网软件的开发和发布,已经形成了一套标准流程。
如: 在互联网企业中,每时每刻都有需求的变更,bug的修复, 为了将改动及时更新到生产服务器上,下面的图片我们需要每天执行N多次,开发人员完整代码自测后提交到git,然后需要将git中最新的代码生成镜像并部署到测试服务器,如果测试通过了还需要将最新代码部署到生产服务器。如果采用手动方式操作,那将会浪费大量的时间浪费在运维部署方面。
现在的互联网企业,基本都会采用以下方案解决:
持续集成(Continuous integration,简称 CI)。
持续部署(continuous deployment, 简称 CD)
持续集成:频繁地(一天多次)将代码集成到主干。
好处主要有两个:
快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。
防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
持续集成的目的:
就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
Martin Fowler 说过,”持续集成并不能消除 Bug,而是让它们非常容易发现和改正。”
与持续集成相关的,还有两个概念,分别是持续交付和持续部署。
持续交付(Continuous delivery)指的是**,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。**
如果评审通过,代码就进入生产阶段。
持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。
持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。
持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。
持续部署的前提是能自动化完成测试、构建、部署等步骤。
持续集成中的任何一个环节都是自动完成,无需太多的人工干预,有利于减少重复过程以节省时间、费用和工作量;演示一套基本的自动化持续集成和持续部署方案,理解互联网企业的软件部署方案。
作用:保证团队开发人员提交代码的质量,减轻了软件发布时的压力;
流程如下:
实现流程:
要实现上面流程,我们需要了解两款新的软件 jenkins
和 rancher
Jenkins,原名Hudson,2011年改为现在的名字,它是一个开源的实现持续集成的软件工具。
官方网站:http://jenkins-ci.org/ 。
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/
(2)修改镜像加速配置
修改 jenkins 数据目录中的hudson.model.UpdateCenter.xml值为:
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
# 修改配置文件
vi hudson.model.UpdateCenter.xml
# 将url标签内网址替换成上面网址
(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
(4)重启jenkins容器 ,然后访问:http://your_ip:8888 准备解锁
docker restart myjenkins
第一次运行时,需要先解锁jenkins
具体步骤:
具体解锁的管理员密码,在jenkins的安装目录中,因为我们是采用的容器安装,所以需要进入到容器中查看
# 进入到jenkins容器
docker exec -it myjenkins bash
# 查看密码
cat /var/jenkins_home/secrets/initialAdminPassword
# 将密码复制到上图管理员密码文本框,然后点击继续 完成解锁
jenkins的各项功能,依赖各种插件,可以手工选择安装也可以按照推荐安装
课程中直接安装推荐插件, 注意如果加速没配置成功,这里将会非常慢,或者下载失败
可能因为网络会安装失败,我们课程主要使用git 和 chinese中文插件,可以直接继续忽略错误插件,或者点击重试尝试重新安装
创建管理员用户
插件安装完毕后,会进入到设置管理员用户页面,按自己需求设置就好,后续登录可以使用
设置完毕后点击保存并完成则进入到jenkins欢迎页
接下来,jenkins会让我们确认jenkins服务端的地址,直接下一步就好,
然后点击开始使用jenkins进入到jenkins页面
进入到jenkins页面, 如果这个时候你的页面都是英文的话,重启下就好
(因为上面安装默认插件中已经安装了 中文插件)
对于git中项目的构建我们要使用到maven命令,那么在jenkins中需要下载对应的maven插件,以及jenkins所在的容器也要有maven环境
(1) 下载maven插件:
点击系统管理 --> 点击插件管理 --> 进入到插件管理页面
点击可选插件 --> 输入maven --> 勾选Maven Integration --> 下载待重启安装
等待下载完成后,重启jenkins容器即可
(2) 安装maven环境
将资源中的maven安装包,拷贝到容器中解压即可,在配置好阿里云镜像
将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>
设置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环境
系统管理中点击全局工具配置
完成后,我们就可以通过jenkins创建构建任务啦~~~
准备工作,导入资源中的docker-demo工程, 在pom中添加docker-maven插件配置,
注意将IP部分变成自己虚拟机的IP
<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.0modelVersion>
<groupId>com.itheima.shgroupId>
<artifactId>docker_demoartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.5.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
dependencies>
<build>
<finalName>appfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>com.spotifygroupId>
<artifactId>docker-maven-pluginartifactId>
<version>1.2.0version>
<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}.jarinclude>
resource>
resources>
<dockerHost>http://192.168.200.129:2375dockerHost>
configuration>
plugin>
plugins>
build>
project>
将项目上传到码云(gitee.com)中
Git中的地址: https://gitee.com/xiaoT_CJ/docker_demo.git
(1) 新建jenkins任务
在jenkins的首页的第一个页签就是用于构建任务,点击新建任务:
定义任务名名称,勾选构建模板 保存任务
(2) 设置任务的构建信息:
描述信息设置
**源码设置 ***
jenkins可以根据配置的源码地址获取源码,来用于构建,配置如下:
选择git仓库
设置git仓库地址
如果是私有仓库需要添加凭证
选择仓库分支
构建触发器:
什么情况可以触发此任务,或者定时触发此任务,暂不设置
构建设置
构建任务配置如下:
Root POM
: 本次构建要使用的git仓库中的pom文件
Goals and options
: 要执行的mvn命令 不用写前面的mvn
# maven命令
clean package -DskipTests docker:build -DpushImage
# 依次:
# 清除 打包 跳过单元测试 远程构建镜像 上传镜像到注册中心
构建结果通知
可以将构建结果,通知给配置的管理员或触发此任务的代码上传人员,本文不配置
保存任务
点击保存即可
(1)执行构建任务
当我们保存完毕任务之后,会进入到任务的详情页面, 点击立即构建即可执行该构建任务
或者返回首页面板,也能看到任务列表,列表后面的图标也可以用于构建
(2) 查看任务执行日志
点击构建后,在页面左下会出现任务的执行状态,点击进度条进入到任务构建详情中
可以通过控制台输出页面,查看控制台信息,和我们在idea控制中看到的信息类似
第一次执行会下载很多maven依赖
实际上,jenkins是从我们配置的git中拉取了源码信息,在使用maven的命令进行构建
(3) 查看任务构建结果
控制台出现 BUILD SUCCESS
代表构建成功啦
对应的虚拟机中已经有了这个镜像
对应的注册中心中也上传了此镜像
OK 那么接下来基于这个镜像构建出容器,我们就完成了部署。
前面我们了解了容器编排的概念,如: docker 的Swarm google的k8s, 但是这些软件的入门门槛很高,需要我们记住很多命令,那么下面我们介绍一款软件 Rancher,它可以基于上面的容器编排软件,提供可视化的操作页面 实现容器的编排和管理。
Rancher是一个开源的企业级全栈化容器部署及管理平台。Rancher为容器提供一揽
子基础架构服务:CNI兼容的网络服务、存储服务、主机管理、负载均衡、防护墙……
Rancher让上述服务跨越公有云、私有云、虚拟机、物理机环境运行,真正实现一键式应
用部署和管理。
https://www.cnrancher.com/
下载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/
页面右下角 点击下拉框 选择简体中文
在互联网项目中,可能会有多套部署环境 如: 测试环境 、 生产环境,不同的环境下会有不同的服务器 Rancher支持多环境多服务器管理
默认 我们处于default的默认环境中,点击环境管理可以创建环境
点击添加环境可以定义一个环境
构建环境时,需要设置环境的名称、环境描述、及环境模板
可以看到 环境模板支持多套,所谓的环境模板就是底层使用哪种编排工具
rancher支持 cattle、swarm、k8s、mesos等,默认使用cattle
入门案例我们使用内置的Cattle模板即可,添加后列表出现刚创建的环境
切换到prod环境中
在不同的环境中可以会有不同的服务器,要想让我们的rancher能够管理这些服务器,需要在基础架构中添加主机
(1) 添加主机
点击基础架构下拉框中的主机
--> 在点击添加主机
(2) 复制脚本
确认站点地址是否正确,然后点击保存
复制脚本:
(3) 到主机中执行脚本
如: 到我的192.168.200.153的虚拟机中 执行如下命令:
运行完毕后,在rancher的页面上,关闭窗口 可以在主机列表中看到对应服务器信息
(需要等待主机中下载镜像及启动相关容器)
显示active
代表服务器当前状态可用, 如果报红 或显示reconnecting
则为重连状态,等待一会即可
连接成功后,我们可以点击基础架构
下的容器
进行容器的管理
说明:
(1)页面提供了对应主机上的容器管理功能,额外创建的容器都是系统容器,用于rancher的管理,可以通过 取消勾选显示系统容器进行过滤
(2)点击添加容器,可以通过简单配置构建一个容器
如: 构建一个redis容器
(3)容器列表结尾提供了容器的 重启、删除、查看日志等功能
上面的容器管理,仅仅是提供了容器的管理页面,但对于企业级的项目部署 会涉及到集群扩容缩容、服务升级、负载均衡等等高可用的管理。需要在Rancher中通过定义应用与服务的设置来管理。
应用(Project): 代表一个项目 如: 电商项目
服务(Service):代表一个服务 如: 电商项目下的订单微服务
和我们学习的swarm类似,我们可以创建一个应用project
一个应用下可以包含多个服务
service
, 一个服务下可以运行多个相同的容器container
创建应用
点击到环境首页,创建应用 : 应用名称、描述 点击创建
添加服务
在刚创建好的myPro应用中添加服务
设置服务信息:
点击创建,可以看到容器已经运行
在docker中也有对应的服务
点击左侧的 数量加减 会自动对服务进行扩容 缩容
不过我们当前服务集群 并没有配置端口映射,因此外部无法访问,需要配置负载均衡
回到服务列表,添加负载均衡
配置负载均衡
1.负载均衡名称 : lbdockerDemo
2.负载均衡描述 : dockerDemo的负载均衡
3.访问端口: 9001
4.目标服务: myPro/dockerDemo
5.映射服务容器端口: 9090
访问测试: http://192.168.200.153:9001/hello 多次点击
依次查看3个容器的日志
已经实现了负载均衡效果~~~~
访问当前服务 http://192.168.200.153:9001/hello
变更当前代码
push提交到git
执行jenkins构建任务,将最新的代码打包成新镜像,并上传到注册中心
构建成功后,在rancher中进行服务升级 在详情页面或列表页面都有向上的箭头代表服务升级
填写升级信息, 启动行为勾选:
这样会先根据最新镜像创建容器,创建完毕后,在将之前的容器删除,来完成服务的更新
点击升级
最后,点击完成升级 旧的容器将被删除掉
刷新页面,可以看到服务已经升级完毕
也就意味着完成服务的一键部署
上面的演示中,当我们把idea上的代码提交到git中之后, 手动的点击了jenkins中的构建任务,完成镜像的构建和上传注册中心。 然后,在到rancher软件中,根据最新的镜像完成一键升级。 那么自动化的流程就是让这两部也变成自动的,我们只需要将代码上传到指定分支将会自动化的完成构建与升级部署。
主流的git软件都提供了webhooks功能(web钩子), 通俗点说就是git在发生某些事件的时候可以通过POST请求调用我们指定的URL路径,那在这个案例中,我们可以在push事件上指定jenkins的任务通知路径。
jenkins下载webhooks插件
gitee插件介绍: https://gitee.com/help/articles/4193#article-header0
jenkins也支持通过url路径来启动任务,具体设置方法:
jenkins的默认下载中仅下载了github的通知触发,我们需要先下载一个插件
(1) 下载gitee插件
系统管理–>插件管理–>可选插件–>搜索 Gitee
下载–>重启jenkins
(2) gitee生成访问令牌
首先,去下面网址生成gitee访问令牌
https://gitee.com/profile/personal_access_tokens
添加令牌描述,提交,弹出框输入密码
复制令牌
(3) jenkins中配置Gitee
系统管理 --> 系统配置 --> Gitee配置
令牌配置:
修改配置接收webhooks通知
任务详情中点击配置来修改任务
点击构建触发器页签,勾选Gitee webhook
生成Gitee Webhook密码
保存好触发路径和webhook密码,到gitee中配置webhook通知
如:
触发路径: http://192.168.200.151:8888/gitee-project/dockerDemo
触发密码: a591baa17f90e094500e0a11b831af9c
gitee仓库配置webhooks通知
点击仓库页面的管理
添加webhook
但在点击添加时,提示失败 gitee中需要配置一个公有IP或域名,这里我们可以通过内网穿透来解决
内网穿透的小工具很多,这里面我们使用 https://u.tools/ 提供的内网穿透功能
第一次安装后,需要在搜索框搜索内网穿透插件进行安装
安装完毕后,点击内网穿透
配置内网穿透:
节点选择: utools.club(测试)
外网域名: 自定义
内网地址: jenkins的ip
内网端口: jenkins的port
连接成功: 即可使用外网地址访问我们的jenkins
在gitee中将上面的外网地址替换之前的ip和端口部分,再次添加
添加成功
添加完毕后测试一下:
点击webhooks,发送测试请求
点击查看更多结果,200代表请求成功
不过这个时候jenkins中的任务是没被触发的,我们尝试从idea中上传代码,看看任务是否自动构建
上传代码
代码上传到git后,自动触发了jenkins中的构建任务
在rancher中,配置接收器来接收webhooks通知
在api下拉菜单下,点击webhooks添加接收器
名称:自定义即可
类型:支持扩容,缩容,和服务升级 我们演示服务升级
参数格式: Docker Hub即可
镜像标签: 对应镜像的标签
服务选择器: 我们的服务也可以设置标签, 如: 当前标签service=demo
当这个接收器被触发时,所有服务包含此标签的 service=demo 则会触发服务升级
先启动一个新容器, 启动成功后停止老容器,最后删除老容器完成升级
保存,复制触发url路径
触发路径:
http://192.168.200.151:9090/v1-webhooks/endpoint?key=e4NhUC14Z9kLdXcAC0fwY0i1DHiF3blZ0Dw63O8M&projectId=1a7
最后,给我们的服务设置标签,删除之前的服务,重新添加服务
注意在下面标签下的内容,一致要和接收器设置的标签和值一致此服务才会触发升级
标签: service demo
通过POSTMAN进行测试
在触发请求时还需要携带一些必要的参数:
{
"push_data": {
"tag": "1.0-SNAPSHOT"
},
"repository": {
"repo_name": "192.168.200.153:5000/docker_demo"
}
}
点击完毕后观察rancher中服务列表变化,会发现服务将自动完成升级
最后,让jenkins来触发rancher,修改jenkins中的配置
注意: 调用的路径是我们接收器所生成的路径
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\"}}"
操作步骤:
OK,如果成功了,说明你只需要提交代码就可以了, 和部署相关 编译,测试,构建,上传镜像,服务升级,扩容缩容全部交给工具吧~~~