Docker初步
为什么要有Docker?
传统运维模式:一堆帮助文档,安装程序
Docker:打包镜像发布测试,一键运行
- 更便捷的升级和扩容
- 使用了docker之后,我们部署应用和搭积木一样
- 更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上运行很多的容器实例,服务器性能可以压榨到极致
Docker架构
镜像
docker镜像好比一个模板,可以通过模板创建容器服务,tomcat镜像 ====> run ==> tomcat01 容器
tag
即标签,可以理解为当前镜像的版本。一个镜像的标准定义是==镜像名:tag==。如果不加tag,则默认tag是latest。通过给镜像打tag,后续能够实现将镜像推送到指定的仓库中。
容器
docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建。
启动,停止,删除,基本命令!
目前就可以把这个容器理解为一个简易的linux系统
仓库(repository):
仓库就是存放镜像的地方
仓库分为共有仓库和私有仓库
Docker Hub(默认是国外的)
阿里云 都有容器服务器(配置镜像加速)
注意:每个镜像有不同的版本(tag)。因此一个仓库(repository)即保存的是**一个镜像的全部版本**。换言之,一个镜像≈一个仓库。理解这一点在搭建阿里云私有仓库的时候非常有帮助。
Docker基本组成
Docker安装
查看系统配置
[root@aliyunECS ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
安装步骤:
# 1、yum 包更新到最新
yum update
# 2、安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
yum install -y yum-utils device-mapper-persistent-data lvm2
# 3、 设置yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 4、 安装docker,出现输入的界面都按 y
yum install -y docker-ce
# 5、 查看docker版本,验证是否验证成功
docker -v
Docker卸载
# 1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2. 删除资源 . /var/lib/docker是docker的默认工作路径
rm -rf /var/lib/docker
配置阿里云镜像加速
官方的Docker Hub访问比较慢,因此这里设置阿里云Docker镜像源加速。
- 访问:cr.console.aliyun.com/cn-shenzhen… 进入阿里云镜像加速器页面
参考页面下方配置即可。
Docker镜像原理
Linux系统的本质
- 一个Linux系统本质上就是一个文件系统。包含bootfs和rootfs
bootfs:包含bootloader(引导加载程序)和 kernel(内核)。rootfs: root文件系统,包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc等标准目录和文件。==不同的linux发行版,bootfs基本一样,而rootfs不同,如ubuntu,centos等==。
Docker镜像原理
- Docker镜像是由特殊的文件系统叠加而成
- 最底端是 bootfs,并使用宿主机的bootfs
- 第二层是 root文件系统rootfs,称为base image
- 然后再往上可以叠加其他的镜像文件
- 统一文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。
- 一个镜像可以放在另一个镜像的上面。位于下面的镜像称为父镜像,最底部的镜像成为基础镜像。
- 当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器。
我们搭建一个镜像,本质上就是将==个人项目+运行环境打包到一起==!
一个tomcat镜像,可以理解为一个安装了tomcat的Linux系统!
问题
-
Docker 中一个centos镜像为什么只有200MB,而一个centos操作系统的iso文件要几个个G?
答:Centos的iso镜像文件包含bootfs和rootfs,而docker的centos镜像复用操作系统的bootfs,只有rootfs和其他镜像层。
-
Docker 中一个tomcat镜像为什么有600MB,而一个tomcat安装包只有70多MB?
答:由于docker中镜像是分层的,tomcat虽然只有70多MB,但他需要依赖于父镜像和基础镜像,所有整个对外暴露的tomcat镜像大小600多M。
Docker常用命令
进程相关的命令
# 启动docker服务
$ systemctl start docker
# 停止docker服务
$ systemctl stop docker
# 重启docker服务
$ systemctl restart docker
# 查看docker服务状态
$ systemctl status docker
# 设置docker开机自启
$ systemctl enable docker
镜像相关的命令
镜像搜索:
docker search 镜像名
# 镜像搜索
[root@aliyunECS ~]# docker search tomcat
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
tomcat Apache Tomcat is an open source implementati… 3235 [OK]
tomee Apache TomEE is an all-Apache Java EE certif… 94 [OK]
dordoka/tomcat Ubuntu 14.04, Oracle JDK 8 and Tomcat 8 base… 57 [OK]
kubeguide/tomcat-app Tomcat image for Chapter 1 33
consol/tomcat-7.0 Tomcat 7.0.57, 8080, "admin/admin" 18 [OK]
cloudesire/tomcat Tomcat server, 6/7/8 15 [OK]
aallam/tomcat-mysql Debian, Oracle JDK, Tomcat & MySQL 12 [OK]
arm32v7/tomcat Apache Tomcat is an open source implementati… 11
rightctrl/tomcat CentOS , Oracle Java, tomcat application ssl… 7 [OK]
arm64v8/tomcat Apache Tomcat is an open source implementati… 7
unidata/tomcat-docker Security-hardened Tomcat Docker container. 5 [OK]
amd64/tomcat Apache Tomcat is an open source implementati… 3
jelastic/tomcat An image of the Tomcat Java application serv… 3
fabric8/tomcat-8 Fabric8 Tomcat 8 Image 2 [OK]
cfje/tomcat-resource Tomcat Concourse Resource 2
oobsri/tomcat8 Testing CI Jobs with different names. 2
chenyufeng/tomcat-centos tomcat基于centos6的镜像 1 [OK]
picoded/tomcat7 tomcat7 with jre8 and MANAGER_USER / MANAGER… 1 [OK]
camptocamp/tomcat-logback Docker image for tomcat with logback integra… 1 [OK]
ppc64le/tomcat Apache Tomcat is an open source implementati… 1
99taxis/tomcat7 Tomcat7 1 [OK]
appsvc/tomcat 1
secoresearch/tomcat-varnish Tomcat and Varnish 5.0 0 [OK]
s390x/tomcat Apache Tomcat is an open source implementati… 0
softwareplant/tomcat Tomcat images for jira-cloud testing 0 [OK]
镜像下载:
docker pull 镜像名[:tag]
如果不加tag,则默认下载的是有latest tag的镜像
[root@aliyunECS ~]# docker pull redis:5.0
5.0: Pulling from library/redis
a2abf6c4d29d: Pull complete
c7a4e4382001: Pull complete
4044b9ba67c9: Pull complete
106f2419edf3: Pull complete
9772114922b9: Pull complete
63031aedd0c4: Pull complete
Digest: sha256:a30e893aa92ea4b57baf51e5602f1657ec5553b65e62ba4581a71e161e82868a
Status: Downloaded newer image for redis:5.0
docker.io/library/redis:5.0
有的时候我们并不希望下载最新的(有latest标签)镜像,这时候应该去Docker Hub上搜索相关镜像,找到我们想要的标签。
以tomcat为例:
查看和删除镜像
# 查看所有镜像:docker images
[root@aliyunECS ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-tomcat 1.0 bef701518481 9 hours ago 910MB
centos 7 eeb6ee3f44bd 4 months ago 204MB
# 查看所有镜像,包括依赖的父镜像(比如拉取tomcat镜像时,同时会把它依赖的父镜像同时拉取)
# -a
[root@aliyunECS ~]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
my-tomcat 1.0 bef701518481 9 hours ago 910MB
<none> <none> 58449c2a61c6 9 hours ago 910MB
<none> <none> ccc88a0fd9da 9 hours ago 910MB
<none> <none> 3aca41579bc1 9 hours ago 910MB
<none> <none> b8aa6286b94e 9 hours ago 910MB
<none> <none> 8849edc3f1ff 9 hours ago 910MB
<none> <none> c528f3d30c0d 9 hours ago 910MB
<none> <none> d819111bed99 9 hours ago 910MB
<none> <none> bfd129fbe00f 9 hours ago 895MB
<none> <none> 6f6e68bad7a2 9 hours ago 571MB
<none> <none> ebc1884f2e36 9 hours ago 571MB
<none> <none> ce0faffab23f 9 hours ago 571MB
<none> <none> 50f181dda91d 9 hours ago 414MB
<none> <none> 2787e8087b44 9 hours ago 204MB
centos 7 eeb6ee3f44bd 4 months ago 204MB
# 查看所有镜像,只显示镜像id
# -q q表示quiet
[root@aliyunECS ~]# docker images -aq
b8aa6286b94e
3aca41579bc1
bef701518481
58449c2a61c6
ccc88a0fd9da
8849edc3f1ff
c528f3d30c0d
d819111bed99
bfd129fbe00f
ebc1884f2e36
6f6e68bad7a2
ce0faffab23f
50f181dda91d
2787e8087b44
eeb6ee3f44bd
# 删除镜像:docker rmi 镜像id或镜像名
# -f:强制删除
[root@aliyunECS ~]# docker rmi -f eeb6ee3f44bd
# 强制删除所有镜像
[root@aliyunECS ~]# docker rmi -f $(docker images -aq)
容器相关的命令
创建并启动容器
[root@aliyunECS ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-tomcat 1.0 bef701518481 9 hours ago 910MB
redis 5.0 c5da061a611a 4 weeks ago 110MB
centos 7 eeb6ee3f44bd 4 months ago 204MB
# docker run [选项] 镜像名[:tag] [命令]
# 选项说明:
# -i 以交互模式启动容器
# -t 生成一个虚拟的命令行。-it相当于进入容器内部操作。退出容器时容器会自动停止
# -d 以守护方式启动容器。退出容器时容器不会自动停止
# -p 将宿主机端口和容器内端口进行绑定,这样外部访问宿主机的端口时相当于就是访问了容器
# -v 挂载数据卷
# --name 给容器命名
[root@aliyunECS ~]# docker run -id --name=tomcat-01 -p 8080:8080 -v ~/webapps/:/usr/local/apache-tomcat-8.5.56/webapps -v ~/tomcatlogs/:/usr/local/apache-tomcat-8.5.56/logs my-tomcat:1.0
45a4d886223f04610ccde75e85dbe6f99829a796f9599aad1a1b723c8886638b
查看容器
# 查看正在执行的容器:docker ps
[root@aliyunECS ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45a4d886223f my-tomcat:1.0 "/bin/sh -c '$CATALI…" 7 seconds ago Up 6 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp tomcat-01
# 查看所有容器
# -a
[root@aliyunECS ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45a4d886223f my-tomcat:1.0 "/bin/sh -c '$CATALI…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp tomcat-01
# 查看所有的容器id
# -q
[root@aliyunECS ~]# docker ps -aq
45a4d886223f
启动和停止容器
[root@aliyunECS ~]# docker stop tomcat-01
tomcat-01
[root@aliyunECS ~]# docker start tomcat-01
tomcat-01
进入容器
[root@aliyunECS ~]# docker exec -it tomcat-01 /bin/bash
[root@45a4d886223f local]# ls
aegis apache-tomcat-8.5.56 bin etc games include jdk1.8.0_11 lib lib64 libexec sbin share src
注意第二行@符号后面的字符串,此时已经进入了容器
查看容器信息
[root@aliyunECS ~]# docker inspect tomcat-01
[
{
"Id": "45a4d886223f04610ccde75e85dbe6f99829a796f9599aad1a1b723c8886638b",
"Created": "2022-01-22T14:57:30.551446861Z",
"Path": "/bin/sh",
"Args": [
"-c",
"$CATALINA_HOME/bin/startup.sh && tail -F $CATALINA_HOME/logs/catalina.out"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 7592,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-01-22T15:01:20.917593196Z",
"FinishedAt": "2022-01-22T15:01:11.495914821Z"
},
"Image": "sha256:bef7015184813dcdca9900a500061296d4779f087bb2600a30133d9d4a36c1f6",
...
]
删除容器
# 强制删除一个容器。如果不加-f,则必须先停止容器再删除
[root@aliyunECS ~]# docker rm -f tomcat-01
tomcat-01
# 删除所有容器,和删除所有的镜像类似
[root@aliyunECS ~]# docker rm -f $(docker ps -aq)
其他常用命令
查看容器中的进程信息
[root@aliyunECS ~]# docker top tomcat-01
UID PID PPID C STIME TTY TIME CMD
root 8724 8706 0 23:10 ? 00:00:00 /bin/sh -c $CATALINA_HOME/bin/startup.sh && tail -F $CATALINA_HOME/logs/catalina.out
root 8756 8724 22 23:10 ? 00:00:02 /usr/local/jdk1.8.0_11/bin/java -Djava.util.logging.config.file=/usr/local/apache-tomcat-8.5.56/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/apache-tomcat-8.5.56/bin/bootstrap.jar:/usr/local/apache-tomcat-8.5.56/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/apache-tomcat-8.5.56 -Dcatalina.home=/usr/local/apache-tomcat-8.5.56 -Djava.io.tmpdir=/usr/local/apache-tomcat-8.5.56/temp org.apache.catalina.startup.Bootstrap start
root 8757 8724 0 23:10 ? 00:00:00 tail -F /usr/local/apache-tomcat-8.5.56/logs/catalina.out
查看日志
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker logs --help
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
-n, --tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
常用:
docker logs -tf 容器id
docker logs --tail number 容器id #num为要显示的日志条数
#docker容器后台运行,必须要有一个前台的进程,否则会自动停止
#编写shell脚本循环执行,使得centos容器保持运行状态
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker run -d centos /bin/sh -c "while true;do echo hi;sleep 5;done"
c703b5b1911ff84d584390263a35707b6024816e1f46542b61918a6327a570dc
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c703b5b1911f centos "/bin/sh -c 'while t…" 13 seconds ago Up 10 seconds pedantic_banach
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker logs -tf --tail 10 c703b5b1911f
2020-12-27T03:34:07.255599560Z hi
2020-12-27T03:34:12.257641517Z hi
2020-12-27T03:34:17.259706294Z hi
2020-12-27T03:34:22.261693707Z hi
2020-12-27T03:34:27.262609289Z hi
2020-12-27T03:34:32.267862677Z hi
2020-12-27T03:34:37.270382873Z hi
2020-12-27T03:34:42.272414182Z hi
2020-12-27T03:34:47.274823243Z hi
2020-12-27T03:34:52.277419274Z hi
拷贝操作
#拷贝容器的文件到主机中
docker cp 容器id:容器内路径 目的主机路径
#拷贝宿主机的文件到容器中
docker cp 目的主机路径 容器id:容器内路径
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker exec -it c703b5b1911f /bin/bash
[root@c703b5b1911f /]# cd home
[root@c703b5b1911f home]# ls
#touch 新建文件
[root@c703b5b1911f home]# touch test.java
[root@c703b5b1911f home]# ls
test.java
[root@c703b5b1911f home]# exit
exit
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c703b5b1911f centos "/bin/sh -c 'while t…" 35 minutes ago Up 35 minutes pedantic_banach
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker cp c703b5b1911f:/home/test.java /home
[root@iZwz99sm8v95sckz8bd2c4Z ~]# ls /home
hai pan test.java
命令总结
Docker数据卷
一个Docker容器一旦删除,其中的数据也就随之删除了。因此需要一种技术将容器内的数据进行持久化。数据卷!
数据卷简单理解,就是把宿主机上的目录挂载到容器内的一个目录。挂载其实就是关联。这样这两个目录的数据会==即时双向同步==。
即使容器删除,宿主机上的保存的数据并不会删除。重新run一个容器并挂载同一个宿主机目录后,发现数据完整的同步到容器中!
数据卷概念
- 数据卷是宿主机中的一个目录或文件
- 当容器目录和数据卷目录绑定后,对方的修改会立即同步
- 一个数据卷可以被多个容器同时挂载
- 一个容器也可以被挂载多个数据卷
数据卷的作用
- 容器数据持久化
- 外部机器和容器间接通信
- 容器之间数据交换:多个容器挂载一个数据卷
配置数据卷
在创建容器时,通过-v参数指定。
[root@aliyunECS ~]# docker run -id --name=tomcat-01 -p 8080:8080 -v ~/webapps/:/usr/local/apache-tomcat-8.5.56/webapps -v ~/tomcatlogs/:/usr/local/apache-tomcat-8.5.56/logs my-tomcat:1.0
注意:
- ==所有目录必须是绝对路径==。
- 容器内目录不能使用简写符号,比如不可以使用“~”符号代替当前用户目录。
- 如果目录不存在,会自动创建
- 可以挂载多个数据卷
数据卷容器
# 想要创建一个容器A,挂载容器B挂载的所有数据卷。通过--volumes-from=容器id实现
[root@aliyunECS ~]# docker run -id --name=tomcat-02 -p 8081:8080 --volumes-from=tomcat-01 my-tomcat:1.0
常用命令
# 创建数据卷
$ docker volume create my-vol
# 查看所有数据卷
$ docker volume ls
# 查看指定数据卷信息
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
# 删除数据卷
$ docker volume rm my-vol
# 删除数据时删除宿主机上与之相关的数据卷
$ docker rm -v my-vol
无主的数据卷可能会占据很多空间,要清理请使用以下命令
$ docker volume prune
1
使用 --mount创建数据卷
挂载一个主机目录作为数据卷。使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去。
$ docker run -d -P \
--name web \
-v /src/webapp:/opt/webapp \
--mount type=bind,source=/src/webapp,target=/opt/webapp \
training/webapp
python app.py
上面的命令挂载主机的/src/webapp目录到容器的/opt/webapp目录。用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。
Docker 挂载主机目录的默认权限是读写 ,用户也可以通过添加readonly 参数指定为只读 。
$ docker run -d -P \
--name web \
# -v /src/webapp:/opt/webapp:ro \
--mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \
training/webapp \
python app.py
加了readonly之后,就挂载为只读了。如果你在容器内/src/webapp目录新建文件,会显示如下错误
/src/webapp # touch new.txt
touch: new.txt: Read-only file system
具名挂载和匿名挂载
挂载方式一共有三种:按路径挂载、具名挂载和匿名挂载。其中按路径挂载就是之前看到的那种挂载方式:==-v 宿主机目录:容器内目录==。注意这里的两个目录都必须是绝对路径。
-
匿名挂载:-v参数后只给出容器内目录,而不指定宿主机目录或名称。 -
具名挂载:通过"==-v 名称:容器内目录=="实现的挂载方式。
具名挂载和匿名挂载最终的挂载目录都保存在/var/lib/docker/volumes目录下。具名挂载的目录为其声明的名称。匿名挂载的目录为一个随机生成的哈希码。
测试:具名挂载
# 具名挂载
[root@aliyunECS volumes]# docker run -id --name=tomcat-02 -p 8081:8080 -v webapps:/usr/local/apache-tomcat-8.5.56/webapps -v tomcatlogs:/usr/local/apache-tomcat-8.5.56/logs my-tomcat:1.0
20e62033301c3159080e9f43694e39096a3c56630d5f42aa9c686aee9a758f0e
[root@aliyunECS volumes]# docker volume ls
DRIVER VOLUME NAME
local tomcatlogs
local webapps
[root@aliyunECS volumes]# pwd
/var/lib/docker/volumes
[root@aliyunECS volumes]# ls
metadata.db tomcatlogs webapps
可以看到,启动容器时声明的两个具名挂载名:webapps和tomcatlogs,都放在了/var/lib/docker/volumes目录下。
测试:匿名挂载
[root@aliyunECS volumes]# docker run -id --name=tomcat-03 -p 8082:8080 -v /usr/local/apache-tomcat-8.5.56/webapps -v /usr/local/apache-tomcat-8.5.56/logs my-tomcat:1.0
d273e5f55eacf7c05bf82678cf81420d7fa8c3ed1c191501f95dbb02e3b7e7d2
[root@aliyunECS volumes]# docker volume ls
DRIVER VOLUME NAME
local 1fa9fb08e6ba3cba2dec337b8ffd6a9c677071417b7da3e9085f09124cfe3e89
local 2fc2c0ee95aa8b2261ea4415e60843edbfe13db8f91f4421fe402cdff1ccff34
local tomcatlogs
local webapps
[root@aliyunECS volumes]# ls
1fa9fb08e6ba3cba2dec337b8ffd6a9c677071417b7da3e9085f09124cfe3e89 metadata.db webapps
2fc2c0ee95aa8b2261ea4415e60843edbfe13db8f91f4421fe402cdff1ccff34 tomcatlogs
可以发现,volumes里多了两个名字很长的目录,这就是docker自动为挂载目录生成的一个随机名字。
指定数据卷的可读/可写参数
ro —— readonly 只读。设置了只读则只能操作宿主机的路径,不能操作容器中的对应路径。
rw ----- readwrite 可读可写
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
Dockerfile中设置数据卷
通过VOLUME指令给镜像添加一个或多个==匿名挂载数据卷==。
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
VOLUME声明的数据卷,如果启动容器时没有通过-v进行具名或指定路径挂载,则会自动进行匿名挂载。
数据卷数据覆盖问题
参考博客:www.cnblogs.com/sparkdev/p/…
数据覆盖的两条规则:
- 如果挂载一个==空的数据卷==到容器中的==一个非空目录==中,那么这个目录下的文件会被==复制到数据卷==中。
- 如果挂载一个==非空的数据卷==到容器中的一个目录中,那么容器中的目录中会显示数据卷中的数据。如果原来容器中的目录中有数据,那么这些原始数据会被隐藏掉。【==覆盖==】
我的测试结论:
- 规则1:
按路径挂载:如果容器中的非空目录是其Dockerfile中使用VOLUME命令声明过的,则容器内文件会被复制到宿主机。否则,容器内的目录会被清空。具名或匿名挂载:复制规则始终成立
- 规则2:只要宿主机的目录不为空,则一定会覆盖掉容器内的目录。
测试
重点在于规则1。
测试:使用Docker安装rabbitmq。
Rabbitmq的Dockerfile文件中声明了一个匿名数据卷:/var/lib/rabbitmq。
Rabbitmq的相关目录:
- 保存数据:/var/lib/rabbitmq
- 保存配置:/etc/rabbitmq
- /etc/rabbitmq中有一个conf.d文件夹,里面包含一个10-default-guest-user.conf的配置文件
测试一:按路径挂载数据和配置目录
[root@aliyunECS rabbitmq]# docker run -id --name=my-mq -p 5672:5672 -p 15672:15672 -p 25672:25672 -p 15692:15692 \
> -v ~/rabbitmq/data:/var/lib/rabbitmq \
> -v ~/rabbitmq/conf.d:/etc/rabbitmq/conf.d \
> --hostname=myrabbit rabbitmq:3.9.13-management
507b30bc5b8381a8c32eb060a9a2aaa091dc019b81c72c359a59bd63c3a671c5
[root@aliyunECS rabbitmq]# ls
conf.d data
[root@aliyunECS rabbitmq]# ls data
mnesia
[root@aliyunECS rabbitmq]# ls data/mnesia/
rabbit@myrabbit rabbit@myrabbit-feature_flags rabbit@myrabbit.pid rabbit@myrabbit-plugins-expand
[root@aliyunECS rabbitmq]# ls
conf.d data
[root@aliyunECS rabbitmq]# ls conf.d/
现象:从12行和16行可以发现,宿主机上的data目录同步到了容器内的数据,但conf.d目录没有同步到。
测试二:按具名挂载的方式挂载数据和配置目录
[root@aliyunECS rabbitmq]# docker run -id --name=mymq -p 5672:5672 -p 15672:15672 -p 25672:25672 -p 15692:15692 \
> -v rabbit_data:/var/lib/rabbitmq \
> -v rabbit_conf.d:/etc/rabbitmq/conf.d
> --hostname=myrabbit rabbitmq:3.9.13-management
[root@aliyunECS rabbitmq]# docker volume inspect rabbit_conf.d
[
{
"CreatedAt": "2022-02-22T15:55:15+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/rabbit_conf.d/_data",
"Name": "rabbit_conf.d",
"Options": null,
"Scope": "local"
}
]
[root@aliyunECS rabbitmq]# ls /var/lib/docker/volumes/rabbit_conf.d/_data
10-default-guest-user.conf
现象:观察第20行可以发现,使用具名挂载后,conf.d目录也被同步下来了。
Docker应用部署
准备工作:
-
如果使用的是阿里云服务器,务必在安全组设置里开放后续准备使用的端口。
-
防火墙配置
# 查看防火墙状态。可以写firewalld也可以写firewalld.service systemctl status firewalld # 关闭防火墙(虚拟机可以这么玩,阿里云服务器不建议关闭!) systemctl stop firewalld # 禁止防火墙开机自启动(虚拟机可以这么玩,阿里云服务器不建议关闭!) systemctl disabled firewalld # 添加端口 firewall-cmd --zone=public --add-port=8000-9000/tcp --permanent # 重启防火墙 systemctl restart firewalld.service
Nginx部署
# 1. 搜索nginx镜像
docker search nginx
# 2. 下载nginx镜像
docker pull nginx
# 3. 创建容器,设置数据卷,端口映射
# 在/root目录下创建nginx目录用于存储nginx数据信息
mkdir ~/nginx
cd ~/nginx
mkdir conf
cd conf
# 在~/nginx/conf/下创建nginx.conf文件,粘贴下面内容
vim nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
docker run -id --name=c_nginx \
-p 80:80 \
-v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf \
-v $PWD/logs:/var/log/nginx \
-v $PWD/html:/usr/share/nginx/html \
nginx
参数说明:
- -p 80:80:将容器的 80端口映射到宿主机的 80 端口。
- -v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf:将主机当前目录下的 /conf/nginx.conf 挂载到容器的 :/etc/nginx/nginx.conf。配置目录
- -v $PWD/logs:/var/log/nginx:将主机当前目录下的 logs 目录挂载到容器的/var/log/nginx。日志目录
Mysql部署
# 1. 拉取Mysql镜像
docker pull mysql:5.6
# 2. 在/root目录下创建mysql目录用于存储mysql数据信息
mkdir ~/mysql
cd ~/mysql
# 3. 启动容器
docker run -id \
-p 3307:3306 \
--name=c_mysql \
-v $PWD/conf:/etc/mysql/conf.d \
-v $PWD/logs:/logs \
-v $PWD/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.6
参数说明:
- -e:配置环境变量。Mysql部署时必须配置MYSQL_ROOT_PASSWORD这个环境变量,否则启动不起来!
目前有一个比较坑的点还未解决:
如果启动两个mysql容器,即使我们把端口映射都配置好(一个映射到宿主机3306,一个映射到宿主机3307),他们也无法同时访问,报错10061。
tomcat部署
# 在/root目录下创建tomcat目录用于存储tomcat数据信息
mkdir ~/tomcat
cd ~/tomcat
# 创建容器
docker run -id --name=c_tomcat \
-p 8080:8080 \
-v $PWD:/usr/local/tomcat/webapps \
tomcat
Dockerfile详解
Dockerfile是什么?
Dockerfile是一个构建镜像的脚本工具。我们在Dockerfile中撰写一个镜像生成过程,就可以通过docker build来构建一个自己的镜像了。
回忆一下,镜像的原理本质上是一个分层的文件系统。所以要搭建镜像,就是要像搭积木一样去搭建每一层的文件系统。
docker镜像的发布步骤
- 编写一个Dockerfile文件
docker build构建成为一个镜像docker run 镜像创建一个可读写的容器,进行容器的相关操作docker commit 容器id 镜像名:tag将容器打包成镜像docker tag 新镜像名:新tag 旧镜像id给镜像添加一个新的标签docker push 镜像(发布镜像到DockerHub、阿里云镜像仓库)
容器转镜像步骤
docker commit 容器id 镜像名称:版本号
docker save -o 压缩文件名称 镜像名称:版本号
docker load –i 压缩文件名称
容器转镜像后,容器内的数据会保留,但挂载的数据卷不会保留。
Dockerfile指令
| 指令 | 说明 |
|---|---|
| FROM | 基于哪个镜像进行构建(指定父镜像) |
| MAINTAINER | 维护者 |
| RUN | 执行一个命令 |
| ADD | 添加文件到镜像,相较于COPY命令,能够添加互联网上的文件以及能够实现自动解压。 |
| WORKDIR | 设置工作目录。该目录就是进入容器后的目录 |
| VOLUME | 声明匿名数据卷 |
| EXPOSE | 声明暴露的端口 |
| CMD | 创建容器时执行的命令,只有最后一个CMD会生效 |
| ENTRYPOINT | 与CMD类似,CMD不能追加命令,但ENTRYPOINT可以 |
| ONBUILD | 当构建一个被继承DockerFile,这个时候就会运行ONBUILD的指令,触发指令 |
| COPY | 复制文件到镜像里 |
| ENV | 设置环境变量,与-e参数的效果相同。 |
指令详解
MAINTAINER
# MAINTAINER:声明维护者
MAINTAINER handing <dinghan93@gmail.com>
ADD和COPY
两者都可以把宿主机上的文件复制到镜像里。ADD的功能更加强大,能够将==互联网上的文件添加进来==,并且可以==自动解压缩文件==。因此,除非有这两项功能需求,其他基本的复制都建议使用COPY指令。
ADD 源文件 镜像内文件
CMD和ENTRYPOINT
两者都是在启动容器的时候执行的命令。区别在于:
- CMD指令在
docker run ... 镜像 指令A的时候,指令A会==覆盖==CMD声明的指令,不能够在原来CMD指令的基础上追加 - ENTRYPOINT能够实现追加
# CMD命令测试
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# cat dockerfile-cmd-test
FROM centos
CMD ["ls","-a"] # 此处使用了CMD命令,在启动容器时无法追加参数(例如-l)
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest:1.0 .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : CMD ["ls","-a"]
---> Running in 6d4d0112322f
Removing intermediate container 6d4d0112322f
---> b6ec5224d2ac
Successfully built b6ec5224d2ac
Successfully tagged cmdtest:1.0
# 正常启动容器
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# docker run cmdtest:1.0
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
#由于使用的是 CMD指令,命令无追加,-l取代了原本的ls -a,而-l命令不存在所以报错。
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# docker run cmdtest:1.0 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
# ENTRYPOINT测试
#1.修改dockerfile文件
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# cat dockerfile-cmd-test
FROM centos
ENTRYPOINT ["ls","-a"]
#2.构建镜像
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest:2.0 .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : ENTRYPOINT ["ls","-a"]
---> Running in 61389c0c1967
Removing intermediate container 61389c0c1967
---> ac7b7e83ff88
Successfully built ac7b7e83ff88
Successfully tagged cmdtest:2.0
#3.运行镜像
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# docker run cmdtest:2.0
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
#4.追加镜像再次运行
[root@iZwz99sm8v95sckz8bd2c4Z dockerfile]# docker run cmdtest:2.0 -l
total 56
drwxr-xr-x 1 root root 4096 Jan 1 03:55 .
drwxr-xr-x 1 root root 4096 Jan 1 03:55 ..
-rwxr-xr-x 1 root root 0 Jan 1 03:55 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Jan 1 03:55 dev
drwxr-xr-x 1 root root 4096 Jan 1 03:55 etc
drwxr-xr-x 2 root root 4096 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 17:37 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 15:22 media
drwxr-xr-x 2 root root 4096 Nov 3 15:22 mnt
drwxr-xr-x 2 root root 4096 Nov 3 15:22 opt
dr-xr-xr-x 106 root root 0 Jan 1 03:55 proc
dr-xr-x--- 2 root root 4096 Dec 4 17:37 root
drwxr-xr-x 11 root root 4096 Dec 4 17:37 run
lrwxrwxrwx 1 root root 8 Nov 3 15:22 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 15:22 srv
dr-xr-xr-x 13 root root 0 Dec 29 15:41 sys
drwxrwxrwt 7 root root 4096 Dec 4 17:37 tmp
drwxr-xr-x 12 root root 4096 Dec 4 17:37 usr
drwxr-xr-x 20 root root 4096 Dec 4 17:37 var
WORKDIR
工作目录。启动并进入容器时自动进入的目录
EXPOSE
声明容器创建后暴露给宿主机的端口。注意这里仅仅是声明,并没有真正将容器内端口和宿主机端口绑定。当==使用-P创建容器==时,自动将EXPOSE声明的端口与宿主机同样的端口绑定。
VOLUME
声明要挂载数据卷的目录。当创建容器没有使用-v挂载该目录时,会自动在宿主机的/var/lib/docker/volumes目录里生成一个文件夹挂载到VOLUME声明的目录。
ENV
设置环境变量。与创建容器时的-e参数类似。-e声明的环境变量可以覆盖ENV声明的环境变量。
关于DockerFile文件的脚本注意点
1、每个保留关键字(指令)都必须是大写字母
2、文件中的指令从上到下顺序执行,第一个指令必须是FROM
3、# 号表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!
实战-制作tomcat镜像并发布
制作镜像
准备工作:上传文件
[root@aliyunECS build]# pwd
/root/build
[root@aliyunECS build]# ls
apache-tomcat-8.5.56.tar.gz Dockerfile jdk-8u11-linux-x64.tar.gz README.txt
注意:Dockerfile的标准化命名就是==Dockerfile==。这样命名之后在build时可以不指定-f参数。
编写Dockerfile
# 指定父镜像为centos:7
FROM centos:7
MAINTAINER handing <dinghan93@gmail.com>
# 因为官方的centos镜像里没有vim和ip命令,因此我们可以自行安装
RUN yum -y install vim
RUN yum -y install iproute
# 设置环境变量
ENV MYPATH=/usr/local
# 设置工作目录
WORKDIR $MYPATH
# 向镜像中复制文件,复制到工作目录
ADD jdk-8u11-linux-x64.tar.gz $MYPATH
ADD apache-tomcat-8.5.56.tar.gz $MYPATH
# 设置环境变量,包括Java环境变量和tomcat环境变量
# Linux上是用冒号:做分隔符的。在Windows上是分号;
# Linux上通过$符号引用其他环境变量。在Windows上是%%
ENV JAVA_HOME=$MYPATH/jdk1.8.0_11
ENV CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME=$MYPATH/apache-tomcat-8.5.56
ENV CATALINA_BASE=$MYPATH/apache-tomcat-8.5.56
# 把所有目录添加到PATH。注意一定要把原来的PATh目录也追加进来。
ENV PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 暴露端口
EXPOSE 8080
# 声明容器创建时的命令
# && 符号连接两个命令,等价于两个CMD指令。因为每一个指令都会创建一层中间镜像,用&&符号的好处是避免创建两个中间镜像,可节省空间和时间
CMD $CATALINA_HOME/bin/startup.sh && tail -F $CATALINA_HOME/logs/catalina.out
build镜像
格式:docker build -f dockerfile文件 -t 镜像名:tag .。最后一个点表示在当前目录下查找Dockerfile。
[root@aliyunECS build]# docker build -t my-tomcat:1.0 .
Sending build context to Docker daemon 169.4MB
Step 1/15 : FROM centos:7
---> eeb6ee3f44bd
Step 2/15 : MAINTAINER handing <dinghan93@gmail.com>
---> Running in aa363267018f
Removing intermediate container aa363267018f
---> d88e92dcf921
Step 3/15 : RUN yum -y install vim
---> Running in 6d1f345d68b3
...
Complete!
Removing intermediate container 6d1f345d68b3
---> 6ac929da1b64
Step 4/15 : RUN yum -y install iproute
---> Running in b9febb7d4299
...
Complete!
Removing intermediate container b9febb7d4299
---> 48591870e53e
Step 5/15 : ENV MYPATH=/usr/local
---> Running in 87abfd3f4d21
Removing intermediate container 87abfd3f4d21
---> 37c5e9c9b602
Step 6/15 : WORKDIR $MYPATH
---> Running in b6b8a22645de
Removing intermediate container b6b8a22645de
---> 94d4402e21b8
Step 7/15 : ADD jdk-8u11-linux-x64.tar.gz $MYPATH
---> 4b0fb3567597
Step 8/15 : ADD apache-tomcat-8.5.56.tar.gz $MYPATH
---> 559435105ee7
Step 9/15 : ENV JAVA_HOME=$MYPATH/jdk1.8.0_11
---> Running in 878246a5f023
Removing intermediate container 878246a5f023
---> 3b0690f76684
Step 10/15 : ENV CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
---> Running in c879c7fdec29
Removing intermediate container c879c7fdec29
---> 1314c555388e
Step 11/15 : ENV CATALINA_HOME=$MYPATH/apache-tomcat-8.5.56
---> Running in fa80ab47de46
Removing intermediate container fa80ab47de46
---> d335ab4d806b
Step 12/15 : ENV CATALINA_BASE=$MYPATH/apache-tomcat-8.5.56
---> Running in fd23583f0940
Removing intermediate container fd23583f0940
---> 6fb488adc2cc
Step 13/15 : ENV PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
---> Running in 7f8538a9fc05
Removing intermediate container 7f8538a9fc05
---> 1f9d74044f86
Step 14/15 : EXPOSE 8080
---> Running in 1cf5b2c57010
Removing intermediate container 1cf5b2c57010
---> 0dbbad1fb7c5
Step 15/15 : CMD $CATALINA_HOME/bin/startup.sh && tail -F $CATALINA_HOME/logs/catalina.out
---> Running in 5b854897ff7b
Removing intermediate container 5b854897ff7b
---> 23ad601db998
Successfully built 23ad601db998
Successfully tagged my-tomcat:1.0
观察上述的build过程可以发现:
-
Dockerfile里每一条指令对应一个step。每一个step都会构造一个中间容器。中间容器自动提交为一个镜像。step结束后会删除中间容器。使用docker images -aq可以看到生成的所有的中间镜像。
启动容器测试镜像
[root@aliyunECS build]# docker run -it -P \
> -v ~/webapps/:/usr/local/apache-tomcat-8.5.56/webapps \
> -v ~/tomcatlogs/:/usr/local/apache-tomcat-8.5.56/logs \
> my-tomcat:1.0 /bin/bash
[root@6054c35c35fd local]# pwd
/usr/local
可以看到,进入容器后的目录就是WORKDIR里设置的目录。
通过inspect查看容器信息
[root@aliyunECS local]# docker inspect 6054c3
[
...
# 对应启动容器时的-v设置
"Mounts": [
{
"Type": "bind",
"Source": "/root/webapps",
"Destination": "/usr/local/apache-tomcat-8.5.56/webapps",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Source": "/root/tomcatlogs",
"Destination": "/usr/local/apache-tomcat-8.5.56/logs",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {
...
# 对应Dockerfile里的ENV指令
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/jdk1.8.0_11/bin:/usr/local/apache-tomcat-8.5.56/lib:/usr/local/apache-tomcat-8.5.56/bin",
"MYPATH=/usr/local",
"JAVA_HOME=/usr/local/jdk1.8.0_11",
"CLASSPATH=/usr/local/jdk1.8.0_11/lib/dt.jar:/usr/local/jdk1.8.0_11/lib/tools.jar",
"CATALINA_HOME=/usr/local/apache-tomcat-8.5.56",
"CATALINA_BASE=/usr/local/apache-tomcat-8.5.56"
],
"Cmd": [
"/bin/bash"
],
"Image": "my-tomcat:1.0",
"Volumes": null,
"WorkingDir": "/usr/local",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201113",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS",
"org.opencontainers.image.created": "2020-11-13 00:00:00+00:00",
"org.opencontainers.image.licenses": "GPL-2.0-only",
"org.opencontainers.image.title": "CentOS Base Image",
"org.opencontainers.image.vendor": "CentOS"
}
},
# 对应Dockerfile里的EXPOSE指令
"NetworkSettings": {
"Ports": {
"8080/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "49160"
},
{
"HostIp": "::",
"HostPort": "49160"
}
]
},
...
镜像发布
发布到DockerHub
-
首先需要先注册DockerHub账号(在hub.docker.com上)
-
其次在ssh里登录
$ docker login -u 用户名 -p 密码 -
把自己制作的镜像推送到DockerHub
$ docker push 镜像名:tag
发布到自己的阿里云镜像仓库
先创建个人实例
创建命名空间
创建仓库
注意:==这里的仓库(repository)名称就是你想要的镜像名==。其实当你执行docker images时,标题栏显示的也是repository。
点进去这个仓库,里面会指导你如何把镜像push过来
因为我用的是阿里云服务器,这里就使用专有网络地址提高镜像拉取和推送速度。
使用专有网络推送
使用专有网络需要:
- 登录地址必须是专有网络地址
- 给镜像打tag时前缀地址需要是vpc地址
- 登录阿里云Docker Registry(使用VPC专有网络地址)
$ docker login --username=darren93 registry-vpc.cn-shenzhen.aliyuncs.com
- 将镜像推送到Registry
$ docker tag [ImageId] registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:[镜像版本号]
$ docker push registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:[镜像版本号]
- 拉取镜像
$ docker pull registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:[镜像版本号]
测试:
[root@aliyunECS local]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-tomcat 1.0 23ad601db998 3 hours ago 910MB
redis 5.0 c5da061a611a 4 weeks ago 110MB
centos 7 eeb6ee3f44bd 4 months ago 204MB
[root@aliyunECS local]# docker tag 23ad601db998 registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:1.0
[root@aliyunECS local]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-tomcat 1.0 23ad601db998 3 hours ago 910MB
registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1 1.0 23ad601db998 3 hours ago 910MB
redis 5.0 c5da061a611a 4 weeks ago 110MB
centos 7 eeb6ee3f44bd 4 months ago 204MB
[root@aliyunECS local]# docker push registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:1.0
The push refers to repository [registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1]
377d586d44e0: Pushed
fa0435aa33e3: Pushed
651cfecd43a1: Pushed
01ccdd7a0393: Pushed
174f56854903: Layer already exists
1.0: digest: sha256:7caecf6386d8c8e09aa09ac3e7d3302a73b27bd7c633c12dd63b659673b22aee size: 1378
Docker网络连接
网络模式
# 查看所有网络
[root@aliyunECS local]# docker network ls
NETWORK ID NAME DRIVER SCOPE
d6b04a1c8898 bridge bridge local
6559504b4cd5 host host local
4aa7eef81294 mynet bridge local
9c0017c31172 none null local
8a5a6f47ce7d redis bridge local
各种网络模式介绍
Docker默认提供了四个网络模式(也叫driver)
- bridge:容器默认的网络是桥接模式(自己搭建的网络默认也是使用桥接模式,启动容器默认也是使用桥接模式)。此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
- none:不配置网络,容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。
- host:容器和宿主机共享Network namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
- container:创建的容器不会创建自己的网卡,配置自己的IP容器网络连通。容器和另外一个容器共享Network namespace(共享IP、端口范围)。
每种模式可以构建多个网络,其实就是==相当于划分了不同的子网==。
容器默认使用bridge网络(名称为bridge的网络,其driver也是bridge),我们使用docker run --network=网络名指定容器使用的网络。
测试观察
[root@aliyunECS local]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6054c35c35fd my-tomcat:1.0 "/bin/bash" 3 hours ago Up 3 hours 0.0.0.0:49160->8080/tcp, :::49160->8080/tcp quizzical_villani
[root@aliyunECS local]# docker inspect 6054c35c35fd
...
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "d6b04a1c8898d9ad92c9f6ac5444fffb77b4902ea64c6795508e1c838ad060e0",
"EndpointID": "50fac3d0fd452e3b445684b153509f813b72ae70638fce4664bde85cb46efe01",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
可以发现,默认没有指定--network的时候,其自动连接到bridge网络,docker为其自动分配了一个ip地址:172.17.0.2。
Bridge模式原理
当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。Docker0使用到的技术是evth-pair技术。在默认bridge网络模式下,我们每启动一个Docker容器,Docker就会给Docker容器配置一个ip。
Docker容器完成bridge网络配置的过程如下:
- 在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
- Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以veth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中。
- 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。
使用ip addr命令观察宿主机的网络配置
[root@aliyunECS local]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3e:18:31:96 brd ff:ff:ff:ff:ff:ff
inet 172.18.77.41/20 brd 172.18.79.255 scope global dynamic eth0
valid_lft 314692020sec preferred_lft 314692020sec
inet6 fe80::216:3eff:fe18:3196/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:a3:74:99:1a brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:a3ff:fe74:991a/64 scope link
valid_lft forever preferred_lft forever
171: veth554d498@if170: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 1a:70:ce:12:c5:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::1870:ceff:fe12:c506/64 scope link
valid_lft forever preferred_lft forever
网络3就是docker0。171那个就是docker为之前启动的容器创建的一个veth-pair。
进入容器内执行ip addr观察容器内的网络配置。
[root@aliyunECS local]# docker exec -it 6054 /bin/bash
[root@6054c35c35fd local]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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
170: eth0@if171: <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
对比发现,170-171就是一个veth-pair。
查看bridge网络的信息。
[root@aliyunECS local]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "d6b04a1c8898d9ad92c9f6ac5444fffb77b4902ea64c6795508e1c838ad060e0",
"Created": "2022-01-16T19:03:15.26682876+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"6054c35c35fd29472f3fcda56ffc80f11cfcf3a39a7dd41c5c7ddf050d9c1b46": {
"Name": "quizzical_villani",
"EndpointID": "50fac3d0fd452e3b445684b153509f813b72ae70638fce4664bde85cb46efe01",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
该bridge网络的子网是172.17.0.0/16,从Containers里可以看到,当前有一个容器连接到该网络,容器分配的地址是172.17.0.2。
所有连接到==bridge网络==的容器,因为他们在一个子网下,因此他们之间==可以通过ip彼此访问!==但==不能通过名字访问==
- 创建两个容器tomcat-01和tomcat-02,查看两者的ip地址
[root@aliyunECS local]# docker network inspect bridge
"Containers": {
"0b3bbafb2491f716b0a19e2a217dc1c665c0d65f6375ca012ca2c6c54ac3eefe": {
"Name": "tomcat-01",
"EndpointID": "6e0f2b16b55cad62b58bb5cd64c5c9f4167b2fd8922e863e656996750b875fe2",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"a43edaed2b04357ff15a253bf86c1c499487090eaa3ae62db5ac49d2b337b6c9": {
"Name": "tomcat-02",
"EndpointID": "65b7b8a03cb989b2eaf127dd9e6539548e859734e336490aa421b6008cafb129",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
}
},
- 进入tomcat-01去ping tomcat-02的IP地址:成功
[root@aliyunECS local]# docker exec -it tomcat-01 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.137 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.107 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.105 ms
^C
--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.105/0.116/0.137/0.017 ms
- 进入tomcat-02去ping tomcat-01的IP地址:成功
[root@aliyunECS local]# docker exec -it tomcat-02 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.108 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.105 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.098 ms
^C
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.098/0.103/0.108/0.012 ms
- 使用名字去ping:失败
[root@aliyunECS local]# docker exec -it tomcat-02 ping tomcat-01
ping: tomcat-01: Name or service not known
自定义网络
因为docker0,默认情况下不能通过容器名进行访问。需要通过--link进行设置连接。这样的操作比较麻烦,更推荐的方式是自定义网络,容器都使用该自定义网络,就可以实现通过容器名来互相访问了。
创建自定义网络mynet
[root@aliyunECS local]# docker network create --subnet 172.38.0.0/16 --gateway 172.38.0.1 mynet
184ec09cb580545cd95b01c1b179290d5588172f3c3592ae38d0610e2f416561
创建容器,连接到mynet
[root@aliyunECS local]# docker run -id --name=tomcat-01-mynet -p 8083:8080 --network mynet my-tomcat:1.0
444385ffc91009aaa06d80fcb196987e7daede43986f4768fc242ec762af73dd
[root@aliyunECS local]# docker run -id --name=tomcat-02-mynet -p 8084:8080 --network mynet my-tomcat:1.0
da2bcf581b1be30f3b6d46a6467029d5eb2b83a7a53166897d3d7117275922c6
[root@aliyunECS local]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da2bcf581b1b my-tomcat:1.0 "/bin/sh -c '$CATALI…" 2 seconds ago Up 2 seconds 0.0.0.0:8084->8080/tcp, :::8084->8080/tcp tomcat-02-mynet
444385ffc910 my-tomcat:1.0 "/bin/sh -c '$CATALI…" 10 seconds ago Up 10 seconds 0.0.0.0:8083->8080/tcp, :::8083->8080/tcp tomcat-01-mynet
a43edaed2b04 my-tomcat:1.0 "/bin/sh -c '$CATALI…" 38 minutes ago Up 38 minutes 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp tomcat-02
0b3bbafb2491 my-tomcat:1.0 "/bin/sh -c '$CATALI…" 38 minutes ago Up 38 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp tomcat-01
查看mynet当前信息
[root@aliyunECS local]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "184ec09cb580545cd95b01c1b179290d5588172f3c3592ae38d0610e2f416561",
"Created": "2022-01-23T16:41:18.578443942+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.38.0.0/16",
"Gateway": "172.38.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"444385ffc91009aaa06d80fcb196987e7daede43986f4768fc242ec762af73dd": {
"Name": "tomcat-01-mynet",
"EndpointID": "8ca87310bcba93796d8eae6a6710c7947f9a533c1ccfd8496c9ddacc0cd036c6",
"MacAddress": "02:42:ac:26:00:02",
"IPv4Address": "172.38.0.2/16",
"IPv6Address": ""
},
"da2bcf581b1be30f3b6d46a6467029d5eb2b83a7a53166897d3d7117275922c6": {
"Name": "tomcat-02-mynet",
"EndpointID": "88859015a14d548c0d980c7b58998ba424f6073558071d2934c1ed40401341b6",
"MacAddress": "02:42:ac:26:00:03",
"IPv4Address": "172.38.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
tomcat-01-mynet和tomcat-02-mynet都成功连到mynet网络了!
测试连通性
[root@aliyunECS local]# docker exec -it tomcat-01-mynet ping tomcat-02-mynet
PING tomcat-02-mynet (172.38.0.3) 56(84) bytes of data.
64 bytes from tomcat-02-mynet.mynet (172.38.0.3): icmp_seq=1 ttl=64 time=0.147 ms
64 bytes from tomcat-02-mynet.mynet (172.38.0.3): icmp_seq=2 ttl=64 time=0.099 ms
64 bytes from tomcat-02-mynet.mynet (172.38.0.3): icmp_seq=3 ttl=64 time=0.109 ms
^C
--- tomcat-02-mynet ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.099/0.118/0.147/0.022 ms
[root@aliyunECS local]# docker exec -it tomcat-02-mynet ping tomcat-01-mynet
PING tomcat-01-mynet (172.38.0.2) 56(84) bytes of data.
64 bytes from tomcat-01-mynet.mynet (172.38.0.2): icmp_seq=1 ttl=64 time=0.101 ms
64 bytes from tomcat-01-mynet.mynet (172.38.0.2): icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from tomcat-01-mynet.mynet (172.38.0.2): icmp_seq=3 ttl=64 time=0.099 ms
^C
--- tomcat-01-mynet ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.099/0.105/0.116/0.011 ms
==结论:当容器连接到自定义网络后,容器之间彼此都可以通过容器名进行访问!==
Docker网络之间的互联
没有设置的情况下,不同网络间的容器是无法进行网络连接的。如图,两个不同的网络docker0和自定义网络mynet的网络模型图:
不配置的时候,跨网络连接会失败!
[root@aliyunECS local]# docker exec -it tomcat-01 ping tomcat-01-mynet
ping: tomcat-01-mynet: Name or service not known
要想跨网络连接,使用connect命令!docker network connect [OPTIONS] NETWORK CONTAINER
[root@aliyunECS local]# docker network connect mynet tomcat-01
[root@aliyunECS local]# docker inspect tomcat-01
...
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "d6b04a1c8898d9ad92c9f6ac5444fffb77b4902ea64c6795508e1c838ad060e0",
"EndpointID": "6e0f2b16b55cad62b58bb5cd64c5c9f4167b2fd8922e863e656996750b875fe2",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
},
"mynet": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"0b3bbafb2491"
],
"NetworkID": "184ec09cb580545cd95b01c1b179290d5588172f3c3592ae38d0610e2f416561",
"EndpointID": "21f34a47f6667e079bb4867ad1ba5e5e4c673a58241e9cf47e98d342fd76f80e",
"Gateway": "172.38.0.1",
"IPAddress": "172.38.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:26:00:04",
"DriverOpts": {}
}
将tomcat-01连接到mynet之后,它就拥有了两个ip地址,分别在bridge网络和mynet网络下各有一个ip地址。
这样,tomcat-01就可以连接mynet网络下的所有容器了!
[root@aliyunECS local]# docker exec -it tomcat-01 ping tomcat-01-mynet
PING tomcat-01-mynet (172.38.0.2) 56(84) bytes of data.
64 bytes from tomcat-01-mynet.mynet (172.38.0.2): icmp_seq=1 ttl=64 time=0.113 ms
64 bytes from tomcat-01-mynet.mynet (172.38.0.2): icmp_seq=2 ttl=64 time=0.104 ms
64 bytes from tomcat-01-mynet.mynet (172.38.0.2): icmp_seq=3 ttl=64 time=0.106 ms
^C
--- tomcat-01-mynet ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.104/0.107/0.113/0.012 ms
总结
- 启动容器时,如果不配置网络,默认连接到bridge网络
- 在bridge网络下的容器可以互相通过ip访问,但不能通过容器名访问
- 创建自定义网络后,连接到同一自定义网络的容器可以互相通过容器名访问
- 跨网络的容器互相访问:使用
docker network connect命令配置即可
Docker网络实战
Docker搭建redis集群
1、创建redis集群连接的网络
[root@aliyunECS local]# docker network create --subnet=172.38.0.0/16 redis
551a86d7f6c2078584c8adeca9ab2428159179464aeffeb449cd6a7054bf5898
[root@aliyunECS local]# docker network ls
NETWORK ID NAME DRIVER SCOPE
d6b04a1c8898 bridge bridge local
6559504b4cd5 host host local
9c0017c31172 none null local
551a86d7f6c2 redis bridge local
2、通过脚本构建集群中的各个节点的目录(三主三从)
for port in $(seq 1 6); \
do \
mkdir -p /home/handing/mydata/redis/node-${port}/conf
touch /home/handing/mydata/redis/node-${port}/conf/redis.conf
cat << EOF > /home/handing/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、通过脚本启动六个节点
for port in $(seq 1 6); \
do \
docker run -id --name=redis-${port} \
-p 637${port}:6379 \
-p 1637${port}:6379 \
-v /home/handing/mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-v /home/handing/mydata/redis/node-${port}/data:/data \
--network redis \
--ip 172.38.0.1${port} \
redis:5.0 redis-server /etc/redis/redis.conf
done
4、进入其中一个redis节点,启动集群服务
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
启动效果:
>>> 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.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 8c19bc51bf623af8033ab00fee8ea39b55e22f08 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: ad3cddcdcc18dccdf9134c20a3abd91aae808ef0 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 6253179953b9a0c154d1e4a1c60173c36adb1253 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: b29f1c2ed41fe66a14428148a3809abad7e880e6 172.38.0.14:6379
replicates 6253179953b9a0c154d1e4a1c60173c36adb1253
S: 181782eaec8d157011f2a4fea37c15b265d9f43a 172.38.0.15:6379
replicates 8c19bc51bf623af8033ab00fee8ea39b55e22f08
S: 08b973ea8208bea278783d07a11d8f410893dc95 172.38.0.16:6379
replicates ad3cddcdcc18dccdf9134c20a3abd91aae808ef0
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.38.0.11:6379)
M: 8c19bc51bf623af8033ab00fee8ea39b55e22f08 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 181782eaec8d157011f2a4fea37c15b265d9f43a 172.38.0.15:6379
slots: (0 slots) slave
replicates 8c19bc51bf623af8033ab00fee8ea39b55e22f08
S: 08b973ea8208bea278783d07a11d8f410893dc95 172.38.0.16:6379
slots: (0 slots) slave
replicates ad3cddcdcc18dccdf9134c20a3abd91aae808ef0
M: 6253179953b9a0c154d1e4a1c60173c36adb1253 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: ad3cddcdcc18dccdf9134c20a3abd91aae808ef0 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: b29f1c2ed41fe66a14428148a3809abad7e880e6 172.38.0.14:6379
slots: (0 slots) slave
replicates 6253179953b9a0c154d1e4a1c60173c36adb1253
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
5、测试
# 查看集群信息
172.38.0.12:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:2
cluster_stats_messages_ping_sent:511
cluster_stats_messages_pong_sent:499
cluster_stats_messages_meet_sent:1
cluster_stats_messages_sent:1011
cluster_stats_messages_ping_received:499
cluster_stats_messages_pong_received:512
cluster_stats_messages_received:1011
# 查看所有节点信息
172.38.0.12:6379> cluster nodes
181782eaec8d157011f2a4fea37c15b265d9f43a 172.38.0.15:6379@16379 slave 8c19bc51bf623af8033ab00fee8ea39b55e22f08 0 1642942935590 1 connected
08b973ea8208bea278783d07a11d8f410893dc95 172.38.0.16:6379@16379 slave ad3cddcdcc18dccdf9134c20a3abd91aae808ef0 0 1642942936699 6 connected
ad3cddcdcc18dccdf9134c20a3abd91aae808ef0 172.38.0.12:6379@16379 myself,master - 0 1642942934000 2 connected 5461-10922
6253179953b9a0c154d1e4a1c60173c36adb1253 172.38.0.13:6379@16379 master - 0 1642942936000 3 connected 10923-16383
8c19bc51bf623af8033ab00fee8ea39b55e22f08 172.38.0.11:6379@16379 master - 0 1642942936600 1 connected 0-5460
b29f1c2ed41fe66a14428148a3809abad7e880e6 172.38.0.14:6379@16379 slave 6253179953b9a0c154d1e4a1c60173c36adb1253 0 1642942935689 4 connected
# set一组键值对
127.0.0.1:6379> set name darren
-> Redirected to slot [5798] located at 172.38.0.12:6379
OK
172.38.0.12:6379> get name
"darren"
set的键值对放在了172.38.0.12上,即redis-2节点。redis-6节点是redis-2的从机。这里挂掉redis-2之后看看效果。
# 挂掉redis-2后再取出name值,自动转到从节点上
127.0.0.1:6379> get name
-> Redirected to slot [5798] located at 172.38.0.16:6379
"darren"
172.38.0.16:6379>
部署简单的springboot项目
1、编写项目
2、打jar包
3、编写Dockerfile
FROM java:8
COPY hello-springboot-1.0.jar /hello.jar
EXPOSE 8080
CMD ["java", "-jar", "hello.jar"]
4、将Dockerfile和kar包上传到服务器,build镜像
[root@aliyunECS hello-springboot-project]# docker build -t hello:1.0 .
5、部署,启动容器
[root@aliyunECS hello-springboot-project]# docker run -id -p 80:8080
外部访问结果: