Docker使用入门到进阶 常用命令+网络+实战
Docker介绍
Docker是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
Docker入门
基本概念
Docker基本组成:
镜像 image
docker 镜像好比一个模板,可以通过这个目标创建容器服务。比如:nginx
镜像 ===》run
命令 ===》nginx01
容器(提供服务)
容器 container
docker利用容器技术,独立运行一个或一组应用。容器是通过镜像创建的。
容器基本命令有:启动、停止、删除
仓库 repository
仓库是用来存放镜像的地方。
仓库可以分为:共有仓库、私有仓库。
Docker安装
Debian
系统安装:
官方文档:https://docs.docker.com/engine/install/
# 卸载旧版本
apt-get remove docker docker-engine docker.io containerd runc
# 安装相关依赖和工具
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release software-properties-common
# ######我们用阿里云替换官方###########
# 添加阿里云GPG key https://mirrors.aliyun.com/docker-ce/linux/debian/
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/debian/gpg | apt-key add -
# 写入软件源信息
add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/debian $(lsb_release -cs) stable"
# ####默认使用官方源下载,####
# 添加Docker官方GPG key
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 写入软件源信息
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
# 配置镜像加速 可以在阿里云中的容器镜像服务下的镜像加速器替换"https://xxxxx.mirror.aliyuncs.com"
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]
}
EOF
# 重启docker
systemctl daemon-reload
systemctl restart docker
Docker常用命令
常用命令一览图:
文档地址:https://docs.docker.com/engine/reference/commandline/docker/
帮助命令
# 查看版本
docker version
# 查看docker信息
docker info
# 查看命令的帮助信息
docker 命令 --help
docker search
通过Docker Hub搜索Docker镜像。一般用的不是很多,可以直接通过Docker Hub中进行搜索。
## 搜索redis镜像
docker search redis
docker pull
从远程仓库拉取一个镜像。可以不用指定tag
名称,则用latest
,不过一般建议都带上指定tag
。
## 获取redis镜像,不带tag,默认latest
docker pull redis
## 获取redis镜像,带tag,指定具体tag
docker pull redis:6.2.1-alpine
docker images
列出本地镜像。
docker images
docker rmi
删除一个或多个镜像。
## 通过REPOSITORY和TAG名删除镜像
docker rmi redis:6.2.1-alpine
## 通过IMAGE ID删除镜像
docker rmi 621ceef7494a
docker run
创建一个新的容器并运行一个命令。
语法:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
常用OPTIONS说明:
- -d: 后台运行容器,并返回容器ID;
- -i: 以交互模式运行容器,通常与 -t 同时使用;
- -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
- -P: 大写P。随机端口映射,容器内部端口随机映射到主机的端口;
- -p: 小写p指定端口映射,格式为:主机(宿主)端口:容器端口;
- --name: 为容器指定一个名称;
- -e: 设置环境变量;
- -v或--volume: 绑定一个卷;
- -h: 指定容器host name;
docker run --name nginx01 -p 80:80 -v /data:/data -d nginx:latest
# --name 将启动的容器命名为nginx01
# -p 将容器80端口映射到主机80端口
# -v 将主机/data目录映射到容器/data目录
# -d 以后台模式启动
docker ps
列出容器。
docker ps
docker top
查看容器中的进程信息。
docker top 容器id
docker logs
获取容器日志。
docker start
、docker stop
、docker restart
docker start: 启动一个或多个已停止的容器;
docker stop: 停止一个或多个正在运行的容器;
docker restart: 重启一个或多个容器。
docker attach
连接到正在运行中的容器。
docker exec # 连接容器后开启一个新的终端(常用)
docker attach # 连接容器后,进入正在执行的终端,不会启动新的进程。
docker rm
删除一个或多个容器。
docker rm 容器id # 删除指定容器。正常情况不允许删除正在运行的容器
docker rm -f $(docker ps -aq) # 删除所有容器
docker ps -a -q|xargs docker rm # 删除所有容器
docker inspect
获取容器的元数据。
docker exec
在一个运行中的容器中执行命令。
OPTIONS说明:
- -d: 分离模式: 在后台运行;
- -i: 即使没有
attach
也保持STDIN 打开; - -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
docker exec -it 容器id /bin/bash
退出容器
exit # 容器直接停止并退出
Ctrl + P + Q #容器不停止退出
docker rename
给容器重命名。
docker rename tomcat9.0.43 tomcat9.0
docker cp
用于容器与宿主机之间拷贝文件。
# 将宿主机目录/home/user/data拷贝至容器目录/data/mydata/下
docker cp /home/user/data 96f7f14e99ab:/data/mydata/
# 将宿主机目录/home/user/data拷贝至容器目录中并重命名为/data/mydata
docker cp /home/user/data 96f7f14e99ab:/data/mydata
# 将容器目录/data/mydata拷贝至宿主机目录/tmp下
docker cp 96f7f14e99ab:/data/mydata /tmp/
docker pause
和 docker unpause
docker pause: 暂停容器中所有进程。
docker unpause: 恢复容器中所有的进程。
docker create
创建一个容器,但不启动容器。方法同docker run
。
docker commit
从容器中创建一个新的镜像。
OPTIONS说明:
- -a: 提交镜像的作者(例如:"John Hannibal Smith <hannibal@a-team.com>");
- -c: 使用Dockerfile指令来创建镜像;
- -m: 提交的说明信息;
- -p: 提交镜像时将容器暂停(默认:true)。
# 通过容器创建镜像
docker commit -m="提交的说明信息" -a="作者" 容器id 目标镜像:[TAG]
docker diff
检查容器里文件结构的更改。
Docker镜像
镜像是一种轻量级可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含某个软件所需要的所有内容,包括:运行的代码、库、环境变量、配置文件等。
所有应用直接打包docker镜像,就可以直接运行起来。
Docker获取镜像方式
- 从远程仓库下载
- 通过他人拷贝
- 通过
Dockerfile
自行制作
UnionFS 联合文件系统
UnionFS (联合文件系统) : Union文件系统(UnionFS) 是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一’ 次提交来一层层的叠加,同时可以将不同月录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
分层的镜像与容器
有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
Docker镜像都是只读的,当容器启动时,一个新的可写层镜像加载到镜像顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层。
Docker进阶
容器数据卷
卷技术:容器与宿主机之间可以通过数据卷,实现数据共享,将容器中产生的数据同步到本地。
具名和匿名挂载
# 匿名挂载:-v 挂载时,只设置了容器内路径,没有设置容器外路径
# -v 容器内路径(只有容器内路径,没有宿主机路径)
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看所有的 volume 信息
root@docker00:~# docker volume ls
DRIVER VOLUME NAME
local e3aa274a9c2cbd616657345d4a75bd8c00e0fee28d583a44bb8e0d482321cde7
# 具名挂载: -v 卷名:容器内路径
docker run -d -P --name nginx02 -v named-nginx:/etc/nginx nginx
root@docker00:~# docker volume ls
DRIVER VOLUME NAME
local named-nginx
# 查看卷名信息 docker volume inspect
root@docker00:~# docker volume inspect named-nginx
[
{
"CreatedAt": "2021-03-17T23:30:47+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/named-nginx/_data",
"Name": "named-nginx",
"Options": null,
"Scope": "local"
}
]
所有docker
容器内的卷,没有指定目录情况下默认都在/var/lib/docker/volumes/xxx/_data
。
可通过具名挂载可以方便的找到我们的一个卷,大多数情况建议都使用具名挂载。
# 区分:具名挂载、匿名挂载、指定路径挂载
-v 卷名:容器内路径 # 具名挂载
-v 容器内路径 # 匿名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载
# 通过 -v 容器内路径:ro rw 改变读写权限
ro readonly # 只读, 只能通过宿主机来操作,容器内无法操作
rw readwrite # 可读可写(默认)
docker run -d -P --name nginx02 -v named-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v named-nginx:/etc/nginx:rw nginx
初识DockerFile
Dockerfile 就是用来构建docker
镜像的构建文件。
通过这个脚本可以生产镜像,镜像是一层一层的,脚本就是一个个的命令,每个命令就是一层。
# 创建一个dockerfile文件,名称可以自定义,建议使用 Dockerfile
Dockerfile文件内容:
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "---end---"
CMD /bin/bash
查看容器挂载信息:docker container inspect 1444cbf50e22
这种方式使用非常多,因为我们通常会构建自己的镜像。
如果构建镜像时没有挂载卷,需要手动镜像挂载:-v 卷名:容器路径
。
数据卷容器
--volumes-from
:可以实现多个容器间的数据共享。
1、创建父容器mycentos01
2、创建子容器mycentos02
3、进入父容器mycentos01
挂载的数据卷创建文件file_from_mycentos01
root@docker00:/home/docker# docker start mycentos01
mycentos01
root@docker00:/home/docker# docker attach mycentos01
[root@645f0a865138 /]# cd volume01
[root@645f0a865138 volume01]# touch file_from_mycentos01
[root@645f0a865138 volume01]# vi file_from_mycentos01
# 设置内容:file_from_mycentos01
4、在子容器mycentos02
中查看目录volume01
mycentos01
中创建的文件同步至mycentos02
实战:多个mysql共享数据
docker run -d -p 3316:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d -p 3317:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
# 这样两个容器mysql01和mysql02就可以实现数据同步。
容器间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用该数据卷为止。
数据一旦持久化到本地,本地的数据就不会删除。
DockerFile
DockerFile介绍
Dockerfile 就是用来构建docker
镜像的构建文件。
构建步骤:
- 编写
Dockerfile
文件 docker build
构建成为一个镜像docker run
运行镜像docker push
发布镜像(DockerHub、阿里云镜像仓库)
背景:很多官方镜像都是基础包,很多功能都没有,我们通常会根据自己的需要搭建自己的镜像。
DockerFile构建过程
基础要求:
- 每个指令都必须大写
- 执行是从上到下顺序执行
- 每个指定都会创建一个新的镜像层,并提交
#
表示注释
Dockerfile
是面向开发的,发布项目时做镜像,就需要编写dockerfile文件。
Dockerfile
镜像逐渐成为企业交付的标准,必须熟练掌握。
步骤:
DockerFile:构建文件,定义所有步骤,相当于镜像源代码。
Docker Image镜像:通过DockerFile构建生成的镜像,最终发布和运行的产品。
Docker Container容器:通过镜像运行起来提供的服务。
DockerFile指令
FROM # 基础镜像,一切从这里开始
MAINTAINER # 镜像的作者。 姓名+邮箱
RUN # 镜像构建时需要运行的命令
ADD # 添加内容。比如制作tomcat镜像,需要添加tomcat压缩包
WORKDIR # 镜像工作的目录
VOLUME # 挂载的目录
EXPOSE # 暴露端口配置
CMD # 指定容器启动的时候要运行的命令。只有最后一个会生效,可被替代
ENTRYPOINT # 指定容器启动的时候要执行的命令,可以追加命令
ONBUILD # 当构建一个被继承 DockerFile 这个时候就会运行 ONBUILD 指令。触发指令
COPY # 类似 ADD ,将我们的文件拷贝到镜像中
ENV # 构建的时候设置环境变量
DockerFile实战
创建自己的centos
1、编写Dockerfile文件
FROM centos
LABEL maintainer="xxx@xxx.com"
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
CMD echo $MYPATH
CMD echo "---end---"
CMD ["/bin/bash"]
2、通过编写好的Dockerfile构建镜像
docker build -f dockerfile_mycentos -t mycentos:0.1 .
# -f 指定需要构建的Dockerfile文件路径
# -t 镜像名:tag
3、根据镜像运行容器
通过docker history
获取镜像变更历史:
(我们可以通过查看现有的镜像变更历史,来研究它们是怎么做的)
CMD
和ENTRYPOINT
区别
CMD
:指定这个容器启动的时候要执行的命令,只有最后一个会生效。ENTRYPOINT
:指定这个容器启动的时候要运行的命令,可以追加命令。我们追加的命令,是直接拼接在ENTRYPOINT
命令后面的。
使用CMD
:
Dockerfile内容:
FROM centos
CMD ["ls","-a"]
使用ENTRYPOINT
:
Dockerfile内容
FROM centos
ENTRYPOINT ["ls","-a"]
创建自己的Tomcat
镜像
1、准备好需要的文件:Tomcat、JDK或JRE压缩包
2、编写Dockerfile文件。官方命名Dockerfile
,build会自动寻找这个文件,就不需要通过-f
指定dockerfile文件。
FROM centos
LABEL maintainer="xxx<xxx@xxx.com>"
COPY readme.txt /usr/local/readme.txt
ADD server-jre-8u181-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.44.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_181
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HONE/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.44
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.44
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.44/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.44/bin/logs/catalina.out
3、构建镜像
docker build -t mytomcat:0.1 .
4、启动镜像
docker run -d -p 18888:8080 -v /home/docker/data/test:/usr/local/apache-tomcat-9.0.44/webapps/test -v /home/docker/data/tomcatlog:/usr/local/apache-tomcat-9.0.44/logs --name mytomcat01 mytomcat:0.1
5、访问
发布自己的镜像
发布镜像至DockerHub
1、需要有自己的账号
2、通过docker login
命令登录
3、使用docker push
发布镜像
提交的时候是按镜像层级进行提交的。
docker tag local-image:tagname new-repo:tagname
docker push new-repo:tagname
发布镜像至阿里云镜像服务
1、登录阿里云账号进入镜像服务
2、创建命名空间
3、创建镜像仓库
4、获取仓库信息
5、通过docker login
登录
6、使用docker push
发布镜像
Dockerfile小结
Docker网络
docker0网络
通过命令docker network
查看docker网络相关信息。
root@docker00:/home/docker# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
root@docker00:/home/docker# docker network ls
NETWORK ID NAME DRIVER SCOPE
804cd60f60ac bridge bridge local
e9112dc56247 host host local
9212c1c4c5f7 none null local
启动一个容器:
root@docker00:/home/docker# docker run -d -P --name tomcat01 tomcat
# 查看容器内网络地址 ip addr
# 可以看到容器启动的时候会得到一个 eth0@if19 ip地址。 这个是docker分配的
root@docker00:/home/docker# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 通过宿主机可以ping同docker容器
root@docker00:/home/docker# ping -c 4 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.186 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.080 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.112 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.208 ms
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3022ms
rtt min/avg/max/mdev = 0.080/0.146/0.208/0.053 ms
再启动一个容器:又多了一对网卡。
查看docker0网卡信息docker network inspect 804cd60f60ac
原理说明
- 只要安装了docker,就会有一个网卡
docker0
,桥接模式; - 每启动一个docker容器,docker就会给容器分配一个ip;
- 每启动一个docker容器,docker带来的网卡都是成对的,使用的技术是
evth-pair
技术; - 多个docker容器是公用一个路由器,即
docker0
; - 所有容器如果不指定网络的情况下,都是
docker0
路由的,docker会给我们的容器分配一个默认的可用IP。 - docker中所有的网络接口都是虚拟的。虚拟的网络接口转发效率高。
evth-pair技术
evth-pair
就是一对虚拟设备接口,它们都是成对出现的,一端连着协议,另一端彼此相连。
我们可以利用这个特性,使evth-pair
充当一个桥梁,连接各种虚拟网络设备的。
--link
问题:我们的一个服务连接数据库,如果做到项目不重启,更改掉数据库。
解决方法:我们可以通过名称进行访问。
root@docker00:/home/docker# docker run -d -P --name tomcat03 --link tomcat02 tomcat
017be3dbf8a6f94c48cb58afa704dde9900a676eae343cc670ddc3e2d996a557
root@docker00:/home/docker# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.194 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.094 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.140 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=4 ttl=64 time=0.207 ms
root@docker00:/home/docker# 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 8666f2a63042
172.17.0.4 017be3dbf8a6
--link本质:在hosts配置中增加一条记录,比如上面的172.17.0.3 tomcat02 8666f2a63042
。
注意:--link现在不建议使用。
docker0的问题:不支持容器名访问。
自定义网络
网络模式:
- bridge:桥接模式(默认,我们自定义网络也适用bridge模式)
- none:不配置网络
- host:和宿主机共享网络
- container:容器网络连通(用得少,局限比较多)
# 直接启动容器的命令 --net bridge, 这个bridge就是docker0网络
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0的特点:默认不能通过域名访问, --link可以打通链接。
docker 网络相关命令:docker network
和docker network create
定义自己的网络:
docker network create --driver bridge --subnet 192.168.6.0/24 --gateway 192.168.6.1 mynet
# --driver bridge 定义网络模式
# --subnet 192.168.6.0/24 子网
# --gateway 192.168.6.1 网关
root@docker00:/home/docker# docker network create --driver bridge --subnet 192.168.6.0/24 --gateway 192.168.6.1 mynet
3c9fe291cfbe918693055e85551a3a1b1e5894cdf3c1742f873e3d2f9c7de232
root@docker00:/home/docker# docker run -d -P --name tomcat01 --net mynet tomcat
ac83ca2e3a007e49d3a76eee4e51357ff54f7a320bb4d595094f459de08e75f1
root@docker00:/home/docker# docker run -d -P --name tomcat02 --net mynet tomcat
0f7a6d2165bdb488ae58ef6cf42d35fd42bc5afbd88adaa29f5b70033c7a1d0a
root@docker00:/home/docker# docker network ls
NETWORK ID NAME DRIVER SCOPE
804cd60f60ac bridge bridge local
e9112dc56247 host host local
3c9fe291cfbe mynet bridge local
9212c1c4c5f7 none null local
root@docker00:/home/docker# docker exec -it tomcat01 ping -c 4 tomcat02
PING tomcat02 (192.168.6.3) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.6.3): icmp_seq=1 ttl=64 time=0.125 ms
64 bytes from tomcat02.mynet (192.168.6.3): icmp_seq=2 ttl=64 time=0.161 ms
64 bytes from tomcat02.mynet (192.168.6.3): icmp_seq=3 ttl=64 time=0.096 ms
64 bytes from tomcat02.mynet (192.168.6.3): icmp_seq=4 ttl=64 time=0.107 ms
--- tomcat02 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 40ms
rtt min/avg/max/mdev = 0.096/0.122/0.161/0.025 ms
root@docker00:/home/docker# docker exec -it tomcat02 ping -c 4 tomcat01
PING tomcat01 (192.168.6.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=1 ttl=64 time=0.039 ms
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=2 ttl=64 time=0.150 ms
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=3 ttl=64 time=0.145 ms
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=4 ttl=64 time=0.153 ms
--- tomcat01 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 36ms
rtt min/avg/max/mdev = 0.039/0.121/0.153/0.049 ms
我们自定义网络docker都已经帮我们维护好了对应关系,推荐使用我们自定义的网络。
优点:
可以使不同的应用使用不同的网络。
比如:
Redis/MySQL:不同的集群使用不同的网络,保障集群是安全、健康的。
网络连通
docker network connect
root@docker00:/home/docker# docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--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
# 创建2个使用默认 bridge 网络的 tomcat 容器
root@docker00:/home/docker# docker run -d -P --name tomcat01bridge tomcat
65c996904744eee0e1f9f47ddd15dc76805c9d363c45ece4a9e245d8b5449db3
root@docker00:/home/docker# docker run -d -P --name tomcat02bridge tomcat
a7336a1a8dc3f4120d7b61051c3a082f911d31865f5e5447a363a4483cd2c66e
# 将容器 tomcat01bridge 连通到网络 mynet
root@docker00:/home/docker# docker network connect mynet tomcat01bridge
# 在容器 tomcat01 中 ping tomcat01bridge
root@docker00:/home/docker# docker exec -it tomcat01 ping -c4 tomcat01bridge
PING tomcat01bridge (192.168.6.4) 56(84) bytes of data.
64 bytes from tomcat01bridge.mynet (192.168.6.4): icmp_seq=1 ttl=64 time=0.163 ms
64 bytes from tomcat01bridge.mynet (192.168.6.4): icmp_seq=2 ttl=64 time=0.108 ms
64 bytes from tomcat01bridge.mynet (192.168.6.4): icmp_seq=3 ttl=64 time=0.146 ms
64 bytes from tomcat01bridge.mynet (192.168.6.4): icmp_seq=4 ttl=64 time=0.107 ms
# 在容器 tomcat01bridge 中 ping tomcat01
root@docker00:/home/docker# docker exec -it tomcat01bridge ping -c 4 tomcat01
PING tomcat01 (192.168.6.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=1 ttl=64 time=0.109 ms
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=2 ttl=64 time=0.155 ms
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=3 ttl=64 time=0.109 ms
64 bytes from tomcat01.mynet (192.168.6.2): icmp_seq=4 ttl=64 time=0.129 ms
# 再次查看mynet的信息
root@docker00:/home/docker# docker network inspect mynet
小技巧:要跨网络操作别人的容器,就需要使用docker network connect
来进行连通。
Docker实战
实战创建Redis
集群
创建网卡:
docker network create redis --driver bridge --subnet 172.68.0.0/16
# 创建网卡
root@docker00:~# docker network create redis --driver bridge --subnet 172.68.0.0/16
d7a4cf0688143f703cf4f9426da8f93404fdc7697fbff576952dc5dc055fabcf
# 创建Redis配置(通过脚步创建6个)
for port in $(seq 1 6); \
do \
mkdir -p /data/redis/node-${port}/conf
touch /data/redis/node-${port}/conf/redis.conf
cat << EOF >/data/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.68.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 创建Redis容器,一共有6个。
root@docker00:/data/redis# docker run -p 6371:6379 -p 16371:16379 --name redis-1 -v /data/redis/node-1/data:/data -v /data/redis/node-1/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.68.0.11 redis:5.0.12-alpine3.13 redis-server /etc/redis/redis.conf
root@docker00:/data/redis# docker run -p 6372:6379 -p 16372:16379 --name redis-2 -v /data/redis/node-2/data:/data -v /data/redis/node-2/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.68.0.12 redis:5.0.12-alpine3.13 redis-server /etc/redis/redis.conf
root@docker00:/data/redis# docker run -p 6373:6379 -p 16373:16379 --name redis-3 -v /data/redis/node-3/data:/data -v /data/redis/node-3/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.68.0.13 redis:5.0.12-alpine3.13 redis-server /etc/redis/redis.conf
root@docker00:/data/redis# docker run -p 6374:6379 -p 16374:16379 --name redis-4 -v /data/redis/node-4/data:/data -v /data/redis/node-4/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.68.0.14 redis:5.0.12-alpine3.13 redis-server /etc/redis/redis.conf
root@docker00:/data/redis# docker run -p 6375:6379 -p 16375:16379 --name redis-5 -v /data/redis/node-5/data:/data -v /data/redis/node-5/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.68.0.15 redis:5.0.12-alpine3.13 redis-server /etc/redis/redis.conf
root@docker00:/data/redis# docker run -p 6376:6379 -p 16376:16379 --name redis-6 -v /data/redis/node-6/data:/data -v /data/redis/node-6/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.68.0.16 redis:5.0.12-alpine3.13 redis-server /etc/redis/redis.conf
# 创建集群
/data # redis-cli --cluster create 172.68.0.11:6379 172.68.0.12:6379 172.68.0.13:6379 172.68.0.14:6379 172.68.0.15:6379 172.68.0.16
:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.68.0.15:6379 to 172.68.0.11:6379
Adding replica 172.68.0.16:6379 to 172.68.0.12:6379
Adding replica 172.68.0.14:6379 to 172.68.0.13:6379
M: a56213ba8e6512f47e9b113242cbd26a04c9b1c4 172.68.0.11:6379
slots:[0-5460] (5461 slots) master
M: 9970c171e1d4d3b14d01d64f008e98287edfd6e3 172.68.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 8041851b334790ee99be68e525252a80a0ca6c1d 172.68.0.13:6379
slots:[10923-16383] (5461 slots) master
S: f9eca8ade53518d881abe06a7702960989b0670a 172.68.0.14:6379
replicates 8041851b334790ee99be68e525252a80a0ca6c1d
S: 374d5e6755744ceee4c2d6c3c33fa7e01ff968f9 172.68.0.15:6379
replicates a56213ba8e6512f47e9b113242cbd26a04c9b1c4
S: 11adc56af02e65684b5353096cd396de354f5eba 172.68.0.16:6379
replicates 9970c171e1d4d3b14d01d64f008e98287edfd6e3
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.68.0.11:6379)
M: a56213ba8e6512f47e9b113242cbd26a04c9b1c4 172.68.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: f9eca8ade53518d881abe06a7702960989b0670a 172.68.0.14:6379
slots: (0 slots) slave
replicates 8041851b334790ee99be68e525252a80a0ca6c1d
S: 11adc56af02e65684b5353096cd396de354f5eba 172.68.0.16:6379
slots: (0 slots) slave
replicates 9970c171e1d4d3b14d01d64f008e98287edfd6e3
M: 9970c171e1d4d3b14d01d64f008e98287edfd6e3 172.68.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: 8041851b334790ee99be68e525252a80a0ca6c1d 172.68.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 374d5e6755744ceee4c2d6c3c33fa7e01ff968f9 172.68.0.15:6379
slots: (0 slots) slave
replicates a56213ba8e6512f47e9b113242cbd26a04c9b1c4
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
连接集群:redis-cli -c
,查看集群信息cluster info
、集群节点cluster nodes
。
# 集群测试
# 设置值
127.0.0.1:6379> set k1 v1
-> Redirected to slot [12706] located at 172.68.0.13:6379
OK
# 将172.68.0.13对应的容器停止
root@docker00:~# docker stop redis-3
# 获取值
/data # redis-cli -c
127.0.0.1:6379> get k1
-> Redirected to slot [12706] located at 172.68.0.14:6379
"v1"
# 查看集群节点
172.68.0.14:6379> cluster nodes
a56213ba8e6512f47e9b113242cbd26a04c9b1c4 172.68.0.11:6379@16379 master - 0 1616504607000 1 connected 0-5460
374d5e6755744ceee4c2d6c3c33fa7e01ff968f9 172.68.0.15:6379@16379 slave a56213ba8e6512f47e9b113242cbd26a04c9b1c4 0 1616504607000 5 connected
8041851b334790ee99be68e525252a80a0ca6c1d 172.68.0.13:6379@16379 master,fail - 1616504393932 1616504392000 3 connected
11adc56af02e65684b5353096cd396de354f5eba 172.68.0.16:6379@16379 slave 9970c171e1d4d3b14d01d64f008e98287edfd6e3 0 1616504608745 6 connected
9970c171e1d4d3b14d01d64f008e98287edfd6e3 172.68.0.12:6379@16379 master - 0 1616504607730 2 connected 5461-10922
f9eca8ade53518d881abe06a7702960989b0670a 172.68.0.14:6379@16379 myself,master - 0 1616504608000 7 connected 10923-16383
SpringBoot打包Docker镜像
步骤:
- 开发项目
- 打包应用
- 编写Dockerfile
- 构建镜像
- 运行
编写Dockerfile
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
构建镜像
# 查看工作目录文件
root@docker00:/data/docker/springboot# ll
total 19884
-rw-r--r-- 1 root root 112 Mar 23 21:31 Dockerfile
-rw-r--r-- 1 root root 20357002 Mar 23 21:31 springboot-demo-1.0-SNAPSHOT.jar
# 打包镜像
root@docker00:/data/docker/springboot# docker build -t demospringboot:1.0 .
Sending build context to Docker daemon 20.36MB
Step 1/5 : FROM java:8
8: Pulling from library/java
5040bd298390: Pull complete
fce5728aad85: Pull complete
76610ec20bf5: Pull complete
60170fec2151: Pull complete
e98f73de8f0d: Pull complete
11f7af24ed9c: Pull complete
49e2d6393f32: Pull complete
bb9cdec9c7f3: Pull complete
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:8
---> d23bdf5b1b1b
Step 2/5 : COPY *.jar /app.jar
---> bd52eb60c058
Step 3/5 : CMD ["--server.port=8080"]
---> Running in 6dd1c6b0d94a
Removing intermediate container 6dd1c6b0d94a
---> 9d61c697466a
Step 4/5 : EXPOSE 8080
---> Running in 6e7460e821a5
Removing intermediate container 6e7460e821a5
---> ddf374755516
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
---> Running in 392e27aeefb4
Removing intermediate container 392e27aeefb4
---> e8ce8b7283a7
Successfully built e8ce8b7283a7
Successfully tagged demospringboot:1.0
运行测试
root@docker00:/data/docker/springboot# docker run -d -P --name demospringboot01 demospringboot:1.0
f88f4029e199c212483f79f40ed023eb079c1b1e9c7c089f351c57dd3fed1fec
root@docker00:/data/docker/springboot# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f88f4029e199 demospringboot:1.0 "java -jar /app.jar …" 25 seconds ago Up 24 seconds 0.0.0.0:32768->8080/tcp demospringboot01
root@docker00:/data/docker/springboot#
# 测试
root@docker00:/data/docker/springboot# curl http://localhost:32768
index >>> Welcome To SpringBoot!