Docker入门与进阶(基础+实战+进阶)
- 一、Docker入门
- 1.1 Docker 概述
- 1.2 Docker 安装、配置、卸载
- 1.3 Docker 使用流程
- 1.4 Docker 访问原理
- 1.5 Docker 常用命令
- 1.5.1 基础命令
- 1.5.2 镜像命令
- 1.5.3 容器命令
- 1.5.4 其他常用命令
- 1.5.5 镜像导出、导入
- 1.6 制作Docker镜像
- 二、容器数据卷
- 2.1 数据卷介绍
- 2.2 数据卷使用
- 2.3 docker volume 命令
- 2.4 具名挂载和匿名挂载
- 2.5 数据卷之Dockerfile
- 2.6 数据卷容器
- 三、Dockerfile
- 3.1 Dockerfile 介绍
- 3.2 Dockerfile 指令
- 3.3 Dockerfile 实战
- 实战1:基于官方centos镜像构建定制化centos
- 实战2:CMD指令和ENTRYPOINT指令的区别
- 实战3:Dockerfile 制作Tomcat镜像
- 实战4:SpringBoot项目打包成Docker镜像
- 实战5:发布镜像
- 四、Docker 总结
- 五、Docker 网络
- 5.1 了解Docker网络
- 5.2 容器互联 --link
- 5.3 容器互联 自定义网络
- 5.4 网络连通
- 5.5 Docker网络 实战
- 实战1:Redis集群部署
- 六、Docker Compose 单机部署
- 6.1 Docker Compose 介绍、安装
- 6.2 Docker Compose 快速体验
- 6.3 Docker Compose 默认命名规则
- 6.4 docker-compose.yml 配置规则
- 6.5 实战:编写springboot项目通过Compose构建运行
- 七、Docker Swarm 集群部署
- 7.1 Swarm 相关概念
- 7.2 Swarm 工作模式
- 7.3 Swarm 集群搭建
- 7.4 了解Raft一致性协议
- 7.5 Swarm集群动态扩缩容服务
- 八、Docker 其他命令(了解)
- 8.1 Docker Stack
- 8.2 Docker Secret
- 8.3 Docker Config
一、Docker入门
1.1 Docker 概述
Docker 是一个开源的轻量级的应用容器引擎
。
应用场景
- Web 应用的自动化打包和发布。
- 自动化测试和持续集成、发布。
- 在服务型环境中部署和调整数据库或其他的后台应用。
Docker和虚拟机的对比
- 传统虚拟机,虚拟出硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件。
- Docker内的容器直接运行在宿主机内,容器是没有自己的内核的,也没有虚拟硬件。每个容器都是相互隔离的,每个容器都有属于自己的文件系统,互不影响。
容器化的好处
- 应用更快速的交付和部署
- 更便捷的升级和扩展
- 更简单的系统运维
- 更高效的资源利用
Docker的组成 仓库、镜像和容器
- 镜像
Docker镜像里包含了已打包的应用程序及其所依赖的环境。类似于Win的程序安装包。
- 镜像仓库
Docker镜像仓库用于存放Docker镜像,以及促进不同人和不同电脑之间共享这些镜像。类似于Win放安装包的仓库。
- 容器
Docker容器通常是一个Linux容器,它基于Docker镜像被创建。一个运行中的容器是一个运行在Docker主机上的进程。类似于Win安装好的程序。
1.2 Docker 安装、配置、卸载
Docker的安装步骤
0.删除旧版本,可以避免出现安装失败的情况
yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine
1.安装docker
,-y表示不询问安装,直到安装成功
yum install -y docker-ce docker-ce-cli containerd.io
2.启动docker
,并查看版本信息
systemctl start docker
docker version
3.配置国内镜像仓库
vim /etc/docker/daemon.json
{"registry-mirrors": ["https://registry.docker-cn.com"]
}
配置完成后需重启docker服务
systemctl restart docker # 重启docker服务
systemctl status docker # 确认docker服务正常运行
4.将docker设置为开机启动
systemctl enable docker
5.卸载Docker
# 1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2. 删除资源 . /var/lib/docker是docker的默认工作路径
rm -rf /var/lib/docker
1.3 Docker 使用流程
1.4 Docker 访问原理
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问!Docker Server接收到Docker-Client的指令,就会执行这个指令!
1.5 Docker 常用命令
Docker命令的官方地址
1.5.1 基础命令
docker version
# 查看docker的版本信息
docker info
# 查看docker的系统信息,包括镜像和容器的数量
docker 命令 --help
# 帮助命令(可查看可选的参数)
1.5.2 镜像命令
docker images
查看本地所有镜像
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 6 months ago 13.3kB
# 解释:
1.REPOSITORY 镜像的仓库源
2.TAG 镜像的标签
3.IMAGE ID 镜像的id
4.CREATED 镜像的创建时间
5.SIZE 镜像的大小# 可选参数
-a/--all 列出所有镜像
-q/--quiet 只显示镜像的id
docker search
搜索镜像
[root@localhost ~]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10308 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3819 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 754 [OK]
percona Percona Server is a fork of the MySQL relati… 517 [OK]
centos/mysql-57-centos7 MySQL 5.7 SQL database server 86
mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 79
centurylink/mysql Image containing mysql. Optimized to be link… 60 [OK]# 可选参数
Options:-f, --filter filter Filter output based on conditions provided--format string Pretty-print search using a Go template--limit int Max number of search results (default 25)--no-trunc Don't truncate output# 搜索收藏数大于3000的镜像
[root@localhost ~]# docker search mysql --filter=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10308 [OK]
mariadb MariaDB is a community-developed fordockerk of MyS… 3819 [OK]
docker pull 镜像名[:tag]
下载镜像
分层下载,docker image的核心-联合文件系统(UnionFS)
# 如果不写tag默认就是下载最新版 latest
docker pull mysql
# 指定版本下载
docker pull mysql:5.7
docker rmi
删除镜像
# 1.删除指定的镜像id
docker rmi -f 镜像id
# 2.删除多个镜像id
docker rmi -f 镜像id 镜像id 镜像id
# 3.删除全部的镜像id
docker rmi -f $(docker images -aq)
1.5.3 容器命令
容器是基于Docker镜像被创建的。
# 先拉取一个centos镜像
docker pull centos
docker run [Options] image
运行容器
docker run [Options] image#参数说明
--name="名字" 指定容器名字
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口-p ip:主机端口:容器端口 配置主机端口映射到容器端口-p 主机端口:容器端口(常用)-p 容器端口
-P 随机指定端口
-e 环境设置
-v 容器数据卷挂载
运行并进入容器centos
[root@localhost ~]# docker run -it centos /bin/bash
[root@ce2bbae9f151 /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
退出容器
exit # 停止容器并退出(后台方式运行则仅退出)
Ctrl+P+Q # 不停止容器退出
docker ps
查看运行的容器
# 查看当前正在运行的容器
docker ps -a # 查看所有容器的运行记录
-n=? # 显示最近创建的n个容器
-q # 只显示容器的id
docker start 容器id
启动容器
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前运行的容器
docker kill 容器id # 强制停止当前容器
1.5.4 其他常用命令
docker logs
查看日志
docker logs -tf 容器id
docker logs --tail num 容器id # num为要显示的日志条数
docker top
查看容器中进程信息
docker top 容器id
docker inspect
查看容器的元数据
docker inspect 容器id
进入容器,因为通常我们的容器都是使用后台方式来运行的,有时需要进入容器修改配置
docker exec
# docker exec 进入容器后开启一个新的终端,可以在里面操作
docker exec -it 容器id /bin/bash
docker attach
# docker attach 进入容器正在执行的终端
docker attach 容器id
docker cp
拷贝操作
# 拷贝容器的文件到宿主机中
docker cp 容器id:容器内路径 宿主机路径# 拷贝宿主机的文件到容器中
docker cp 宿主机路径 容器id:容器内路径# 注意:源文件在哪就在哪进行复制操作
# 在主机中创建test.txt文件,并复制到centos容器的/home路径下
touch test.txt
docker cp /home/test.txt 08d1f5d4e7b1:/home/
1.5.5 镜像导出、导入
1. 使用export和import
这两个命令是通过容器来导出、导入镜像
docker export 容器id > xxx.tar [路径]
docker import [- 镜像名] < xxx.tar
2. 使用save和load
这两个命令是通过镜像来导出、导入镜像
docker save 镜像id > xxx.tar [路径]
docker load < xxx.tar
1.6 制作Docker镜像
Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统是UnionFS联合文件系统。
可以使用docker image inspect
查看镜像的元数据
docker image inspect nginx:latest# 镜像的分层信息 ,层级文件可以共享
"RootFS": {"Type": "layers","Layers": ["sha256:87c8a1d8f54f3aa4e05569e8919397b65056aa71cdf48b7f061432c98475eee9","sha256:5c4e5adc71a82a96f02632433de31c998c5a9e2fccdcbaee780ae83158fac4fa","sha256:7d2b207c26790f693ab1942bbe26af8e2b6a14248969e542416155a912fec30d","sha256:2c7498eef94aef8c40d106f3e42f7da62b3eee8fd36012bf7379becc4cd639a2","sha256:4eaf0ea085df254fd5d2beba4e2c11db70a620dfa411a8ad44149e26428caee4"]
}
镜像的特点
- 所有的Docker镜像都起始于一个基础
镜像层
,当进行增加或修改内容时,会在当前镜像层之上,创建新的镜像层。 - Docker镜像都是只读的,当容器启动时,一个新的可写层(
容器层
)被加载到镜像的顶部。
提交镜像 docker commit
# 使用docker commit 命令提交容器成为一个新的镜像版本
docker commit -m=“提交的描述信息” -a="作者" 容器id 目标镜像名:[TAG]
默认的Tomcat镜像的webapps文件夹中没有任何内容,需要从webapps.dist中拷贝文件到webapps文件夹。下面自行制作镜像:就是从webapps.dist中拷贝文件到webapps文件夹下,并提交该镜像作为一个新的镜像。使得该镜像默认的webapps文件夹下就有文件。
# 1.复制项目到webapps下
[root@localhost ~]# docker run -it tomcat /bin/bash
root@3762239532cf:/usr/local/tomcat# cd webapps
root@3762239532cf:/usr/local/tomcat/webapps# ls
root@3762239532cf:/usr/local/tomcat/webapps# cp -r ../webapps.dist/* .
root@3762239532cf:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
# 2.项目访问 http://192.168.0.105:8080/
# 3.提交容器作为一个新的镜像
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41d0b9c0da0e tomcat "catalina.sh run" 4 minutes ago Up 4 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp agitated_mccarthy
[root@localhost ~]# docker commit -m="add webapps" -a="buckletime" 41d0b9c0da0e mytomcat:1.0
sha256:6bbddb87eb6f909f77c6f851b25edd5a02ad9632f397b68f65f4169b9874f02a
# 4.查看镜像列表
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 6bbddb87eb6f 31 seconds ago 684MB
tomcat latest fb5657adc892 3 months ago 680MB
centos latest 5d0da3dc9764 6 months ago 231MB
# 5.运行新的容器并查看文件
[root@localhost ~]# docker run -it mytomcat:1.0 /bin/bash
root@5c04b86e6369:/usr/local/tomcat# ls webapps
ROOT docs examples host-manager manager
二、容器数据卷
2.1 数据卷介绍
Docker将运用与运行的环境打包形成容器运行, Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来, 那么当容器删除后,数据自然也就没有了。 为了能保存数据在Docker中我们使用卷。|
卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但卷不属于联合文件系统(Union FileSystem),因此能够绕过联合文件系统提供一些用于持续存储或共享数据的特性:。
卷的设计目的就是 数据的持久化和同步,容器间可以数据共享
。
数据卷的特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
2.2 数据卷使用
运行容器,指定挂载数据卷命令:
docker run -it -v 主机目录:容器目录
# 1.运行centos容器,并指定挂载数据卷
[root@localhost ~]# docker run -it -v /home/main_data/:/home/docker_data centos /bin/bash
# 2.使用docker inspect查看容器的元数据,查看是否挂载成功
[root@localhost ~]# docker inspect 9f80a90b6c54
"Mounts": [{"Type": "bind","Source": "/home/main_data","Destination": "/home/docker_data","Mode": "","RW": true,"Propagation": "rprivate"}]
# 3.在主机中创建文件
[root@localhost main_data]# touch main.txt
[root@localhost main_data]# ls
main.txt
# 4.查看容器中的文件
[root@9f80a90b6c54 /]# ls /home/docker_data/
main.txt
示例:MySQL容器建立数据卷同步数据
在Linux下的MySQL默认的数据文档存储目录为/var/lib/mysql,默认的配置文件的置/etc/mysql/conf.d,为了避免MySQL镜像或容器删除后,造成的数据丢失,下面建立数据卷保存MySQL的数据和文件。
# 1.启动mysql 挂载数据卷
docker run -d -p 3306:3306 \-v /home/mysql/conf:/etc/mysql/conf.d \-v /home/mysql/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 mysql
# 2.远程连接mysql服务,若无权限,进入mysql容器中修改远程连接权限
docker exec -ti 36d4806c765a /bin/bash
# 登录mysql
mysql -u root -p
# 修改root 可以通过任何客户端连接
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
# 3.使用客户端创建mytest数据库并查看主机中同步的数据,数据同步成功
[root@localhost data]# ls /home/mysql/data
2.3 docker volume 命令
[root@localhost data]# docker volume --helpCommands:create # 创建数据卷inspect # 查看数据卷详情ls # 查看所有数据卷列表prune # 删除所有未使用的卷rm # 删除数据卷
docker volume create
创建数据卷
[root@localhost data]# docker volume create my-vol
docker volume ls
查看所有数据卷列表
[root@localhost data]# docker volume ls
docker volume inspect
查看数据卷详情
[root@localhost data]# docker volume inspect my-vol
[{"CreatedAt": "2022-04-07T12:52:42+08:00","Driver": "local","Labels": {},"Mountpoint": "/var/lib/docker/volumes/my-vol/_data","Name": "my-vol","Options": {},"Scope": "local"}
]
docker volume rm
删除数据卷
[root@localhost data]# docker volume rm my-vol
docker volume prune
删除所有未使用的卷
[root@localhost data]# docker volume prune
docker rm -v
删除容器时也删除相关的卷
2.4 具名挂载和匿名挂载
匿名挂载
匿名挂载就是在指定数据卷的时候,只指定容器路径,不指定对应的主机路径,这样对应映射的主机路径就是默认的路径/var/lib/docker/volumes/
中自动生成一个随机命名
的文件夹。
# 运行并匿名挂载Nginx容器
[root@localhost data]# docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看卷列表
[root@localhost data]# docker volume ls
DRIVER VOLUME NAME
local 0e102dae2f6731494400f7c98c11c835293c030b736588d80d4296b96f10c71d
local my-vol
具名挂载
具名挂载,就是指定文件夹名称,区别于指定路径挂载,这里的指定文件夹名称是在Docker指定的也是默认数据卷路径下的。通过docker volume ls命令可以查看当前数据卷的目录情况。
# 运行并具名挂载Nginx容器
[root@localhost data]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
# 查看卷列表
[root@localhost data]# docker volume ls
DRIVER VOLUME NAME
local 0e102dae2f6731494400f7c98c11c835293c030b736588d80d4296b96f10c71d
local juming-nginx
local my-vol
# 查看数据卷详情,注意主机路径也是默认数据卷路径下
[root@localhost data]# docker volume inspect juming-nginx
[{"CreatedAt": "2022-04-07T13:10:39+08:00","Driver": "local","Labels": null,"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data","Name": "juming-nginx","Options": null,"Scope": "local"}
]
匿名挂载,具名挂载,指定路径挂载的命令区别如下:
- 匿名挂载
-v 容器内路径
,不建议使用 - 具名挂载
-v 卷名:容器内路径
- 指定路径挂载
-v 宿主机路径:容器内路径
扩展:指定数据卷映射的相关参数:ro
/ rw
- ro —— readonly 只读。设置了只读则说明此路径只能通过宿主机来操作,不能通过容器操作。
- rw ----- readwrite 可读可写
[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
2.5 数据卷之Dockerfile
Dockerfile
是一个构建docker镜像的构建文件,是一个命令脚本文件。通过这个脚本可以生成镜像。
可以在Dockerfile中使用VOLUME
指令来给镜像添加一个或多个数据卷。
dockerfile脚本
# 脚本中指令(大写)
# 基础镜像
FROM centos
# 匿名挂载
VOLUME ["volume01","volume02"]
CMD echo "----end----"
# 命令行环境
CMD /bin/bash
执行脚本构建镜像 docker build
[root@localhost docker_test_volume]# docker build -f dockerfile1 -t buckletime-centos:1.0 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos---> 5d0da3dc9764
Step 2/4 : VOLUME ["volume01","volume02"]---> Running in 0af875dd3c35
Removing intermediate container 0af875dd3c35---> 3876cf15e836
Step 3/4 : CMD echo "----end----"---> Running in 73344c7d325a
Removing intermediate container 73344c7d325a---> ce432169d4d9
Step 4/4 : CMD /bin/bash---> Running in 8e12aeb63375
Removing intermediate container 8e12aeb63375---> b74eed3e6de1
Successfully built b74eed3e6de1
Successfully tagged buckletime-centos:1.0
# 查看镜像
[root@localhost docker_test_volume]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
buckletime-centos 1.0 b74eed3e6de1 15 seconds ago 231MB
mytomcat 1.0 6bbddb87eb6f 3 hours ago 684MB
nginx latest 12766a6745ee 8 days ago 142MB
tomcat latest fb5657adc892 3 months ago 680MB
mysql latest 3218b38490ce 3 months ago 516MB
centos latest 5d0da3dc9764 6 months ago 231MB
查看数据卷
# 启动自己构建的镜像并进入容器
[root@localhost docker_test_volume]# docker run -it b74eed3e6de1 /bin/bash
# 查看目录
[root@20978f76e318 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02
# 查看数据卷挂载信息
[root@localhost docker_test_volume]# docker inspect 20978f76e318
"Mounts": [{"Type": "volume","Name": "9bdb13dbdd9a543a00b01e6a84475c6877547a5b722617d1f2afa0546f5cbb47","Source": "/var/lib/docker/volumes/9bdb13dbdd9a543a00b01e6a84475c6877547a5b722617d1f2afa0546f5cbb47/_data","Destination": "volume01","Driver": "local","Mode": "","RW": true,"Propagation": ""},{"Type": "volume","Name": "2edc8939b90a1a6f3b684a279819b7f0f20fd89f9eebc9a78a4318fb77cf22ba","Source": "/var/lib/docker/volumes/2edc8939b90a1a6f3b684a279819b7f0f20fd89f9eebc9a78a4318fb77cf22ba/_data","Destination": "volume02","Driver": "local","Mode": "","RW": true,"Propagation": ""}
]
可以看到Mounts下有宿主机的挂载目录。因为dockerfile中没有指定宿主机目录,所以属于匿名挂载,在/var/lib/docker/volumes/目录下生成了随机命名的路径。
2.6 数据卷容器
容器数据卷是指建立数据卷,来同步多个容器间的数据,实现容器间的数据同步。
首先启动容器1,volume01、volume02为挂载目录
docker run -it --name cnetos01 buckletime-centos:1.0
然后启动容器2,通过参数--volumes-from
,设置容器2和容器1建立数据卷挂载关系
docker run -it --name centos02 --volumes-from cnetos01 buckletime-centos:1.0
数据卷容器总结:
- 容器之间配置文件和数据的同步,数据卷容器的生命周期一直持续到没有容器使用为止
- 如果使用-v 持久化到主机中,主机中的数据不会被删除,永久有效。
三、Dockerfile
3.1 Dockerfile 介绍
Dockerfile
是一个构建docker镜像的构建文件,是一个命令脚本文件
。通过这个脚本可以生成镜像。
构建步骤
编写dockerfile文件
docker build 构建镜像
docker run 运行镜像
docker push 发布镜像
Dockerfile 基础知识点
- 指令必须是大写
- 指令从上到下顺序执行
- # 表示注释
- 每个指令都会创建并提交一个新的镜像层
3.2 Dockerfile 指令
FROM
基础镜像,一切从这里构建
MAINTAINER
镜像维护者描述,姓名+邮箱
RUN
镜像构建的时候需要运行的命令
COPY
将文件复制到目标镜像中
ADD
添加文件到目标镜像中,支持使用tar文件和URL路径
WORKDIR
指定镜像的工作目录
VOLUME
挂载的目录,只能指定容器内的路径,宿主机的路径为默认挂载目录
EXPOSE
指定容器对外暴露的端口
CMD
指定启动容器时要运行的命令,只有最后一个命令会生效,可以被替代
ENTRYPOINT
类似CMD,可以追加命令
ENV
构建的时候设置环境变量
3.3 Dockerfile 实战
实战1:基于官方centos镜像构建定制化centos
官方的centos镜像是最小使用版本,缺失很多命令。我们可以基于官方centos镜像定制化一个contos
1.编写dockerfile文件 dockerfile-mycentos
FROM centos:7
MAINTAINER buckletime<1872192281@qq.com>ENV MYPATH /usr/local
WORKDIR $MYPATHRUN yum install -y vim
RUN yum install -y net-toolsEXPOSE 80CMD echo "-----end------"
CMD /bin/bash
2.通过dockerfile文件构建镜像
docker build -f Dockfile文件 -t 目标镜像:[tag] 目标位置
[root@localhost dockerfile]# docker build -f dockerfile-mycentos -t mycentos:0.1 .
...
Step 9/9 : CMD /bin/bash---> Running in d5083707b308
Removing intermediate container d5083707b308---> b6a1205a01ec
Successfully built b6a1205a01ec
Successfully tagged mycentos:0.1
# 查看镜像
[root@localhost dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 0.1 b6a1205a01ec 3 minutes ago 580MB
centos 7 eeb6ee3f44bd 6 months ago 204MB
3.运行测试
4.可以通过docker history
命令来分析一个镜像的构建过程
# 通过 docker history 命令来分析刚刚构建的镜像过程
[root@localhost dockerfile]# docker history b6a1205a01ec
IMAGE CREATED CREATED BY SIZE COMMENT
b6a1205a01ec 23 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B
8c604ec85c0d 23 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
ad5af97ad072 23 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
3cdf414340ac 23 minutes ago /bin/sh -c yum -y install vim 216MB
cdc69b9b3a21 24 minutes ago /bin/sh -c yum -y install net-tools 161MB
ff54b51b10da 24 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B
d62c8129ba70 24 minutes ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0B
5bc36fed9ecf 24 minutes ago /bin/sh -c #(nop) MAINTAINER buckletime<187… 0B
eeb6ee3f44bd 6 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 6 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 6 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
实战2:CMD指令和ENTRYPOINT指令的区别
CMD
指定启动容器时要运行的命令,只有最后一个命令会生效,可以被替代
ENTRYPOINT
类似CMD,可以追加命令
CMD指令测试
1.vim dockerfile-cmd
FROM centos:7
CMD ["pwd"]
CMD ["ls","-a"]
2.构建镜像
[root@localhost dockerfile]# docker build -f dockerfile-cmd -t cmd-test:1.0 .
3.运行测试
[root@localhost dockerfile]# docker run -it cbe86f605790
. .dockerenv bin etc lib media opt root sbin sys usr
.. anaconda-post.log dev home lib64 mnt proc run srv tmp var
# 要想追加命令 -l ,CMD指令会报错,只能使用全部命令去替换 ls -al
[root@localhost dockerfile]# docker run -it cbe86f605790 -l
docker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
[root@localhost dockerfile]# docker run -it cbe86f605790 ls -al
total 12
drwxr-xr-x. 1 root root 6 Apr 7 09:02 .
drwxr-xr-x. 1 root root 6 Apr 7 09:02 ..
-rwxr-xr-x. 1 root root 0 Apr 7 09:02 .dockerenv
-rw-r--r--. 1 root root 12114 Nov 13 2020 anaconda-post.log
lrwxrwxrwx. 1 root root 7 Nov 13 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 360 Apr 7 09:02 dev
drwxr-xr-x. 1 root root 66 Apr 7 09:02 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
lrwxrwxrwx. 1 root root 7 Nov 13 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 13 2020 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x. 2 root root 6 Apr 11 2018 opt
dr-xr-xr-x. 241 root root 0 Apr 7 09:02 proc
dr-xr-x---. 2 root root 114 Nov 13 2020 root
drwxr-xr-x. 11 root root 148 Nov 13 2020 run
lrwxrwxrwx. 1 root root 8 Nov 13 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x. 13 root root 0 Apr 7 01:43 sys
drwxrwxrwt. 7 root root 132 Nov 13 2020 tmp
drwxr-xr-x. 13 root root 155 Nov 13 2020 usr
drwxr-xr-x. 18 root root 238 Nov 13 2020 var
ENTRYPOINT指令测试
1.vim dockerfile-entrypoint
FROM centos:7
ENTRYPOINT ["pwd"]
ENTRYPOINT ["ls","-a"]
2.构建镜像
[root@localhost dockerfile]# docker build -f dockerfile-entrypoint -t entrypoint-test:1.0 .
3.运行测试
[root@localhost dockerfile]# docker run -it 1ff2ec561a44
. .dockerenv bin etc lib media opt root sbin sys usr
.. anaconda-post.log dev home lib64 mnt proc run srv tmp var
# 追加命令 -l
[root@localhost dockerfile]# docker run -it 1ff2ec561a44 -l
total 12
drwxr-xr-x. 1 root root 6 Apr 7 09:06 .
drwxr-xr-x. 1 root root 6 Apr 7 09:06 ..
-rwxr-xr-x. 1 root root 0 Apr 7 09:06 .dockerenv
-rw-r--r--. 1 root root 12114 Nov 13 2020 anaconda-post.log
lrwxrwxrwx. 1 root root 7 Nov 13 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 360 Apr 7 09:06 dev
drwxr-xr-x. 1 root root 66 Apr 7 09:06 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
lrwxrwxrwx. 1 root root 7 Nov 13 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 13 2020 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x. 2 root root 6 Apr 11 2018 opt
dr-xr-xr-x. 242 root root 0 Apr 7 09:06 proc
dr-xr-x---. 2 root root 114 Nov 13 2020 root
drwxr-xr-x. 11 root root 148 Nov 13 2020 run
lrwxrwxrwx. 1 root root 8 Nov 13 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x. 13 root root 0 Apr 7 01:43 sys
drwxrwxrwt. 7 root root 132 Nov 13 2020 tmp
drwxr-xr-x. 13 root root 155 Nov 13 2020 usr
drwxr-xr-x. 18 root root 238 Nov 13 2020 var
实战3:Dockerfile 制作Tomcat镜像
1. 准备环境
准备Tomcat和jdk的压缩包
[root@localhost dockerfile]# ll
总用量 188324
-rwxr-xr-x. 1 root root 11560971 4月 7 17:26 apache-tomcat-9.0.62.tar.gz
-rwxr-xr-x. 1 root root 181260798 4月 7 17:26 jdk-8u65-linux-x64.tar.gz
-rw-r--r--. 1 root root 0 4月 7 18:39 readme.txt
2. 编写Dockerfile文件
官方名字是Dockerfile
,直接使用此名字,构建时就不用再指定 -f
FROM centos:7
MAINTAINER buckletime<1872192281@qq.com>ENV MYPATH /usr/local
WORKDIR $MYPATHCOPY readme.txt /usr/local/readme.txtADD jdk-8u65-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.62.tar.gz /usr/local/RUN yum -y install vimENV JAVA_HOME /usr/local/jdk1.8.0_65
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.62
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.62
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/binEXPOSE 8080CMD /usr/local/apache-tomcat-9.0.62/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.62/logs/catalina.out
3. 构建镜像
[root@localhost dockerfile]# docker build -t mytomcat:2.0 .
Successfully built 874b2eaffc8f
Successfully tagged mytomcat:2.0
4. 启动镜像
[root@localhost dockerfile]# docker run -d -p 9090:8080 --name mytomcat \
-v /home/buckletime/dockerbuild/tomcat/project:/usr/local/apache-tomcat-9.0.62/webapps/project \
-v /home/buckletime/dockerbuild/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.62/logs mytomcat:2.0
访问测试:http://192.168.0.105:9090 成功进入Tomcat主页
5. 发布项目
由于做了卷挂载,直接将项目放在本地就可以发布项目了
实战4:SpringBoot项目打包成Docker镜像
-
Springboot项目打包,这里以jar包为例
-
上传到Linux中,并编写Dockerfile文件
[root@localhost idea]# ls demo-0.0.1-SNAPSHOT.jar Dockerfile
FROM java:8# 将demo-0.0.1-SNAPSHOT.jar 复制 到容器中并重命名为 app.jar COPY demo-0.0.1-SNAPSHOT.jar app.jarCMD ["--server.port=8080"]EXPOSE 8080ENTRYPOINT ["java","-jar","app.jar"]
-
构建镜像
[root@localhost idea]# docker build -t springbootdemo:1.0 . [root@localhost idea]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE springbootdemo 1.0 d9648a49a226 50 seconds ago 661MB
-
运行、测试
[root@localhost idea]# docker run -d -p:8888:8080 --name mydemo springbootdemo:1.0 [root@localhost idea]# curl localhost:8888/hello hello buckletime![root@localhost idea]#
实战5:发布镜像
发布镜像到Docker Hub
-
Docker Hub官网,注册账号
-
使用
docker login
登录账号[root@localhost ~]# docker login --helpUsage: docker login [OPTIONS] [SERVER]Log in to a Docker registry. If no server is specified, the default is defined by the daemon.Options:-p, --password string Password--password-stdin Take the password from stdin-u, --username string Username
-
使用
docker push
提交镜像# 发布镜像最好带上版本号,可以使用docker tag 命令修改镜像名称和版本号 docker tag 6d27817ecb31 buckletime/mycentos:2.0 # docker push 发布镜像 docker push buckletime/mycentos:2.0
发布镜像到阿里云容器服务
- 登录阿里云,找到容器镜像服务
- 创建命名空间
- 创建容器镜像
- 根据容器镜像内的描述,发布镜像
四、Docker 总结
五、Docker 网络
先清空所有容器和镜像,方便学习
# 清空所有容器
docker rm $(docker ps -aq)
# 清空所有镜像
docker rmi $(docker images -aq)
5.1 了解Docker网络
1.运行一个Tomcat容器,tomcat01 ,并查看容器的地址
[root@localhost ~]# docker run -d -P --name tomcat01 tomcat
[root@localhost ~]# docker exec -it tomcat01 ip addr
运行时使用ip addr
直接查看容器地址,有可能出现报错找不到ip命令,需要进入容器中安装iproute2
官方Tomcat中没有yum命令,使用apt-get
命令安装iproute2和ping命令
[root@localhost ~]# docker exec -it tomcat01 /bin/bash
root@8e57c8b48890:/usr/local/tomcat# apt-get update
root@8e57c8b48890:/usr/local/tomcat# apt-get -y install iproute2 iproute2-doc
root@8e57c8b48890:/usr/local/tomcat# apt-get -y install inetutils-ping
由于容器的ip是docker分配的,容器与主机在同一个网段。Linux主机与容器之间能 ping 通
[root@localhost ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.081 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.046 ms
2.再运行一个Tomcat容器,tomcat02 ,并查看容器的地址
[root@localhost ~]# docker run -d -P --name tomcat02 tomcat
[root@localhost ~]# docker exec -it tomcat02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever
70: eth0@if71: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever
可以发现:
- 我们发现这个容器带来网卡,都是一对对的
evth-pair
就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的- OpenStac,Docker容器之间的连接,OVS的连接,都是使用 evth-pair 技术
3.两个tomcat01 和tomcat02之间能否ping通? 可以ping同,也在同一网段
[root@localhost ~]# docker exec -it tomcat02 ping 127.17.0.2
PING 127.17.0.2 (127.17.0.2): 56 data bytes
64 bytes from 127.17.0.2: icmp_seq=0 ttl=64 time=0.099 ms
64 bytes from 127.17.0.2: icmp_seq=1 ttl=64 time=0.051 ms
结论
- 所有容器不指定网络的情况下,都是由docker0路由的,docker会给容器分配一个可用IP
- Docker使用的是Linux的桥接
- Docker中所有网络接口都是虚拟的,转发效率高
5.2 容器互联 --link
--link
命令可以连接容器,使得容器之间可以使用容器名访问
[root@localhost ~]# docker exec -it tomcat02 ping tomcat01
ping: unknown host
# --link命令 连接容器 tomcat03 连接 tomcat02
[root@localhost ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
# tomcat03 能通过容器名访问 tomcat02
[root@localhost ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.137 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.061 ms
# 但是tomcat02 不能通过容器名访问 tomcat03
[root@localhost ~]# docker exec -it tomcat02 ping tomcat03
ping: unknown host
本质原理:--link是在hosts中增加了一个容器名称的映射关系,是单向连接的
[root@localhost ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat02 03da12909222
172.17.0.4 8e77f2a544a5
真实开发中,不推荐使用--link,配置是修改hosts文件,且是单向配置
5.3 容器互联 自定义网络
不使用docker0,因为docker0不支持使用容器名连接访问。使用自定义网络。
docker network
命令
[root@localhost ~]# docker network --helpUsage: docker network COMMANDManage networksCommands:connect Connect a container to a networkcreate Create a networkdisconnect Disconnect a container from a networkinspect Display detailed information on one or more networksls List networksprune Remove all unused networksrm Remove one or more networks[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9eeca5a5158c bridge bridge local
c60f472b3848 host host local
a959f5564b21 none null local
网络模式
- bridge:桥接(docker默认,自定义网络也是用桥接模式)
- host:和宿主机共享网络
- none:不设置网络
- container:容器网络连接(局限性大,很少使用)
创建网络
docker network create
创建网络
--driver 模式
(默认bridge)--subnet 子网
--gateway 网关
# docker network create 创建网络
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
2b9f9c88b69fbb9917c550d0b8017471e246aeb2c8b17c1667ece8a19b086bca
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9eeca5a5158c bridge bridge local
c60f472b3848 host host local
2b9f9c88b69f mynet bridge local
a959f5564b21 none null local
我们自己的网络就创建好了:
docker network inspect mynet
查看网络详情信息
启动容器指定网络 --net
[root@localhost ~]# docker run -d -P --name tomcat-net01 --net mynet tomcat
972542a6d6516b6d03d81493d03c1f60cecb5160e4ecdad44fb4d18e4430b03f
[root@localhost ~]# docker run -d -P --name tomcat-net02 --net mynet tomcat
f4fd35dcefcd8059af0b0a0c607b137b9c8d4c9d6ba0ae2cf6be23d8a3498992
# 这样两个容器可以直接使用容器名互相连接访问
[root@localhost ~]# docker exec -it tomcat-net01 ping tomcat-net02
PING tomcat-net02 (192.168.0.3): 56 data bytes
64 bytes from 192.168.0.3: icmp_seq=0 ttl=64 time=0.137 ms
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.061 ms
自定义网络好处
- 不同的集群使用不同的网络,保证集群是安全和健康的
5.4 网络连通
docker network connect 网络 容器
将容器连接到网络中
[root@localhost ~]# docker network connect --helpUsage: docker network connect [OPTIONS] NETWORK CONTAINERConnect a container to a networkOptions:--alias strings Add network-scoped alias for the container--driver-opt strings driver options for the network--ip string IPv4 address (e.g., 172.30.100.104)--ip6 string IPv6 address (e.g., 2001:db8::33)--link list Add link to another container--link-local-ip strings Add a link-local address for the container
测试
# 使用docker0启动两个tomcat
[root@localhost ~]# docker run -d -P --name tomcat04 tomcat
[root@localhost ~]# docker run -d -P --name tomcat05 tomcat
# tomcat04和 自定义网络mynet下的tomcat-net01连接,此时肯定是不通的
[root@localhost ~]# docker exec -it tomcat04 ping tomcat-net01
ping: unknown host
# docker network connect 将容器tomcat04连接到mynet网络中
docker network connect mynet tomcat04
# 再次连接,可以连通
[root@localhost ~]# docker exec -it tomcat04 ping tomcat-net01
PING tomcat-net01 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.137 ms
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.061 ms
docker network inspect mynet 查看网络详情信息,发现容器tomcat04被添加到mynet网络中,即:一个容器,有两个ip地址
5.5 Docker网络 实战
实战1:Redis集群部署
# 1.创建redis网络
[root@localhost ~]# docker network create redis_net --subnet 172.38.0.0/16 --gateway 172.38.0.1
# 2.通过shell脚本创建6个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >>/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 3.通过shell脚本启动6个redis容器
for port in $(seq 1 6); \
do \
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis_net --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done
# 4.配置集群。进入一个redis容器中,注意,redis没有/bin/bash 命令,使用/bin/sh
[root@localhost ~]# docker exec -it redis-1 /bin/sh
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
配置集群命令执行后,出现下图信息说明,集群配置成功
5.redis集群测试
redis-cli -c
是进入redis集群, redis-cli
是进入单机版redis
cluster info
:查看集群信息cluster nodes
:查看集群节点信息
/data # redis-cli -c
127.0.0.1:6379> cluster nodes
8dea9b0ac434985556f08543f663a1d149772b75 172.38.0.11:6379@16379 myself,master - 0 1649398430000 1 connected 0-5460
29c361a494c043eb2597a3702537bf9553b89c95 172.38.0.16:6379@16379 slave c356c34a7fe0bf89b0abdcf538a910c1444da20e 0 1649398429000 6 connected
187da435dedcc35a48d0236bb8cbb2a2410d354e 172.38.0.15:6379@16379 slave 8dea9b0ac434985556f08543f663a1d149772b75 0 1649398430636 5 connected
17c460274af7f601846685dd91a39cc244823e17 172.38.0.14:6379@16379 slave 554f73de745a0dbdbe8bb8d805b93c622cb98a73 0 1649398429530 4 connected
554f73de745a0dbdbe8bb8d805b93c622cb98a73 172.38.0.13:6379@16379 master - 0 1649398429127 3 connected 10923-16383
c356c34a7fe0bf89b0abdcf538a910c1444da20e 172.38.0.12:6379@16379 master - 0 1649398430133 2 connected 5461-10922
127.0.0.1:6379> set name buckletime
-> Redirected to slot [5798] located at 172.38.0.12:6379
OK
在集群中set值,是随机处理(172.38.0.12)的。此时把172.38.0.12上的redis-2容器停止,模拟redis服务宕机,看看数据是否还在,是否还能得到刚才的值。
[root@localhost ~]# docker stop redis-2
redis-2
127.0.0.1:6379> get name
-> Redirected to slot [5798] located at 172.38.0.16:6379
"buckletime"
再次进入集群中,发现可以获得刚刚的值,说明数据没有受到影响,是高可用的。
再次查看集群节点信息,如下图:redis-2节点状态是fail,集群自动又选举出一个master
六、Docker Compose 单机部署
6.1 Docker Compose 介绍、安装
Compose 是用于定义和运行多容器 Docker 应用程序的工具
。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务
。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
详细介绍可以参考Docker Compose官网,官网教程非常详细,可以多看官网。
Compose 使用的三个步骤:
- 使用
Dockerfile
定义应用程序的环境。 - 使用
docker-compose.yml
定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。 - 最后,执行
docker-compose up
命令来启动并运行整个应用程序。
docker-compose.yml 的配置案例如下:
version: '3'
services:web:build: .ports:- "5000:5000"volumes:- .:/code- logvolume01:/var/loglinks:- redisredis:image: redis
volumes:logvolume01: {}
理解两个概念
- 服务
service
,项目中使用的单个服务模块,比如web、redis、mysql… - 项目
project
,一组关联的服务构成一个项目,比如博客…
Docker Compose 安装
Linux 中安装Docker Compose:1.下载
2.授权
# 下载 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 授权
sudo chmod +x /usr/local/bin/docker-compose
6.2 Docker Compose 快速体验
1.创建一个应用
。python + flask + redis 实现的一个计数器。
vim app.py,编写应用代码
import timeimport redis
from flask import Flaskapp = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)def get_hit_count():retries = 5while True:try:return cache.incr('hits')except redis.exceptions.ConnectionError as exc:if retries == 0:raise excretries -= 1time.sleep(0.5)@app.route('/')
def hello():count = get_hit_count()return 'Hello World! I have been seen {} times.\n'.format(count)
vim requirements.txt,所需依赖包
flask
redis
2.创建Dockerfile
vim Dockerfile,构建Docker 镜像
# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
3.定义docker-compose.yml
vim docker-compose.yml,在配置文件中定义服务信息
version: "3.9"
services:web:build: .ports:- "8000:5000"redis:image: "redis:alpine"
4.用Compose构建和运行应用程序
docker-compose up
-d
参数表示后台启动
[root@localhost demo_compose]# docker-compose up
Creating network "demo_compose_default" with the default driver
Building web
Sending build context to Docker daemon 4.608kB
Step 1/10 : FROM python:3.7-alpine
...
Creating demo_compose_web_1 ... done
Creating demo_compose_redis_1 ... done
...
web_1 | * Running on http://127.0.0.1:5000
web_1 | * Running on http://172.18.0.2:5000 (Press CTRL+C to quit)
由构建过程可以看出Compose的工作流程:
- 创建一个网络,名称为 “文件夹名称_default”
- 读取docker-compose.yml配置文件
- 根据配置文件中的服务定义,构建并启动服务
运行结果测试:
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 1 times.
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 2 times.
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 3 times.
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 4 times.
5.停止程序
Ctrl + C
非后台启动,可以使用此命令docker-compose stop
-d 后台启动可以使用此命令docker-compose down [--volumes]
stop和down区别在于使用down会完全删除容器
,使用stop是停止一次
。参数--volumes表示删除容器使用的数据卷
6.3 Docker Compose 默认命名规则
1.compose 服务名命名规则
使用docker ps
查看正在运行的服务可以发现,服务名称的命名规则是文件夹名_服务名_num
[root@localhost idea]# docker ps
CONTAINER ID IMAGE NAMES COMMAND CREATED STATUS PORTS
f8d252c277d0 redis:alpine demo_compose_redis_1 "docker-entrypoint.s…" 18 minutes ago Up 18 minutes 6379/tcp
e29dfaeda7c5 demo_compose_web demo_compose_web_1 "flask run" 18 minutes ago Up 18 minutes 0.0.0.0:8000->5000/tcp, :::8000->5000/tcp
compose启动服务是以集群的方式启动的,num表示副本数量
2.网络名命名规则
使用docker network ls
查看网络列表,网络名的命名规则是文件夹名_default
[root@localhost idea]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9eeca5a5158c bridge bridge local
5fcff058a02c demo_compose_default bridge local
c60f472b3848 host host local
这样,在同一个项目文件夹下,所有服务之间都可以通过域名进行访问
6.4 docker-compose.yml 配置规则
官网 docker-compose.yml 配置详细说明
version: "3.9" # 1.版本
services: # 2.服务web: # 服务名# 服务配置build: .ports:- "8000:5000"redis:image: "redis:alpine"
# 3.其他配置 网络/卷/全局规则等
volumes:
network:
config:
学习 docker-compose.yml 配置规则,最好的办法是多写多看!
- 多看官方文档
- 多看开源项目
6.5 实战:编写springboot项目通过Compose构建运行
1.编写微服务项目,自己实现一个计数器(redis)
引入redis依赖
<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>
编写controller代码
@RestController
public class CounterController {@AutowiredStringRedisTemplate redisTemplate;@RequestMapping("counter")public String counter(){Long views = redisTemplate.opsForValue().increment("views");return "hello, buckletime, views " + views + " times";}
}
application.properties配置文件
server.port=8080
# 配置redis 注意,不要写ip,直接写服务名再通过Compose构建服务
spring.redis.host=redis
最后将项目打成jar包
2.Dockerfile 构建镜像
FROM java:8COPY *.jar app.jarCMD ["--server.port=8080"]EXPOSE 8080ENTRYPOINT ["java","-jar","app.jar"]
3.编写 docker-compose.yml 配置
version: "3.8"
services:mycounter: # 服务名build: . # . 表示使用当前目录下的 Dockerfile文件构建镜像image: mycounter # 镜像depends_on:- redis # depends_on 依赖 表示需要依赖redis服务ports:- "8080:8080" # 端口映射redis:image: "redis:alpine"
4.通过Compose构建运行
[root@localhost mycounter]# ll
总用量 26884
-rwxr-xr-x. 1 root root 27520888 4月 8 19:50 demo-0.0.1-SNAPSHOT.jar
-rwxr-xr-x. 1 root root 336 4月 8 19:50 docker-compose.yml
-rwxr-xr-x. 1 root root 120 4月 8 19:50 Dockerfile
[root@localhost mycounter]# docker-compose up -d
5.访问测试,运行成功
[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 1 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 2 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 3 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 4 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 5 times[root@localhost mycounter]#
七、Docker Swarm 集群部署
7.1 Swarm 相关概念
swarm
集群的管理和编排。docker可以初始化一个swarm集群,其他节点可以加入。
Node
就是一个docker节点。多个节点就组成了一个网络集群。(管理、工作者)
Service
服务,可以在管理节点或者工作节点来运行,核心!用户访问!
Task
容器内的命令,细节任务
swarm和k8s原理一样的
- 命令 -> manager节点 -> api -> 调度 -> worker节点(创建维护Task)
7.2 Swarm 工作模式
Docker Swarm 工作模式 官方文档
1. Node工作模式
3. Service、Task、Container
将服务部署到 swarm 时,swarm 管理器会接受您的服务定义作为服务的所需状态。然后,它将 swarm 中节点上的服务计划为一个或多个副本任务。这些任务在群中的节点上彼此独立运行。
例如,假设您要在 HTTP 侦听器的三个实例之间实现负载平衡。下图显示了具有三个副本的 HTTP 侦听器服务。侦听器的三个实例中的每一个都是群中的一个任务。
3. Task、Scheduling
下图显示了 swarm 模式如何接受服务创建请求并将任务计划到工作节点。
7.3 Swarm 集群搭建
[root@localhost ~]# docker swarm --helpCommands:ca Display and rotate the root CAinit Initialize a swarmjoin Join a swarm as a node and/or managerjoin-token Manage join tokensleave Leave the swarmunlock Unlock swarmunlock-key Manage the unlock keyupdate Update the swarm
docker swarm init --advertise-addr 172.24.82.149
初始化一个节点
docker swarm join
加入一个节点
docker swarm join-token manager
获取manager令牌docker swarm join-token worker
获取worker令牌
在另外两台机器上分别再加入节点,一个manager,一个worker。得到一个4节点的swarm集群
集群搭建总结
docker swarm init
初始化主节点docker swarm join
加入节点(manager、worker)
7.4 了解Raft一致性协议
7.2示例中集群是两主两从,当Leader节点宕机时,另一个manager节点也无法工作,只有一个主节点存活无法重新选举出新的Leader;把其中一个worker节点更改为manager节点后,此时集群是三主一从,当Leader节点宕机时,另外两个manager节点都可以正常工作,因为此时可以选举出新的Leader。
leader选举:当前leader故障时必须选举出一个新的leader。
所以,要保证集群的高可用
- 主节点数量必须>=3
- 主节点存活数量必须>=2
简单来说,Raft协议:保证大多数节点存活才可以使用
7.5 Swarm集群动态扩缩容服务
[root@localhost ~]# docker service --helpCommands:create Create a new serviceinspect Display detailed information on one or more serviceslogs Fetch the logs of a service or taskls List servicesps List the tasks of one or more servicesrm Remove one or more servicesrollback Revert changes to a service's configurationscale Scale one or multiple replicated servicesupdate Update a service
docker service create
创建并运行一个服务
[root@localhost ~]# docker service create -p 8888:80 --name myngnix ngnix
- docker run 容器,不具备扩缩容
- docker service 服务,具备扩缩容、滚动更新功能
docker service ls
查看服务列表
[root@localhost ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
blkxxbxk897b myngnix replicated 1/1 ngnix:latest *:8888->80/tcp
动态扩缩容
docker service scale 服务名=num
num 表示扩缩容的服务数量docker service update --replicas num 服务名
num 表示扩缩容的服务数量
[root@localhost ~]# docker service scale myngnix=5
[root@localhost ~]# docker service update --replicas 3 myngnix
两个动态扩缩容命令等效。scale 方便一些
八、Docker 其他命令(了解)
8.1 Docker Stack
docker stack与 docker compose类似
- docker compose 单机容器编排
- docker stack 集群容器编排
[root@localhost ~]# docker stack --helpUsage: docker stack [OPTIONS] COMMANDManage Docker stacksOptions:--orchestrator string Orchestrator to use (swarm|kubernetes|all)Commands:deploy Deploy a new stack or update an existing stackls List stacksps List the tasks in the stackrm Remove one or more stacksservices List the services in the stack
8.2 Docker Secret
安全、密码配置、证书等
[root@localhost ~]# docker secret --helpUsage: docker secret COMMANDManage Docker secretsCommands:create Create a secret from a file or STDIN as contentinspect Display detailed information on one or more secretsls List secretsrm Remove one or more secrets
8.3 Docker Config
统一配置
[root@localhost ~]# docker config --helpUsage: docker config COMMANDManage Docker configsCommands:create Create a config from a file or STDINinspect Display detailed information on one or more configsls List configsrm Remove one or more configs