Docker学习笔记

127 阅读16分钟

Docker初步

为什么要有Docker?

传统运维模式:一堆帮助文档,安装程序

Docker:打包镜像发布测试,一键运行

  • 更便捷的升级和扩容
  • 使用了docker之后,我们部署应用和搭积木一样
  • 更高效的计算资源利用

Docker是内核级别的虚拟化,可以在一个物理机上运行很多的容器实例,服务器性能可以压榨到极致

Docker架构

img

镜像

docker镜像好比一个模板,可以通过模板创建容器服务,tomcat镜像 ====> run ==> tomcat01 容器

tag

即标签,可以理解为当前镜像的版本。一个镜像的标准定义是==镜像名:tag==。如果不加tag,则默认tag是latest。通过给镜像打tag,后续能够实现将镜像推送到指定的仓库中。

容器

docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建。

启动,停止,删除,基本命令!

目前就可以把这个容器理解为一个简易的linux系统

仓库(repository):

仓库就是存放镜像的地方

仓库分为共有仓库和私有仓库

Docker Hub(默认是国外的)

阿里云 都有容器服务器(配置镜像加速)

注意:每个镜像有不同的版本(tag)。因此一个仓库(repository)即保存的是**一个镜像的全部版本**。换言之,一个镜像≈一个仓库。理解这一点在搭建阿里云私有仓库的时候非常有帮助。

Docker基本组成

Docker Architecture Diagram

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镜像源加速。

64285899043

参考页面下方配置即可。

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会在最顶层加载一个读写文件系统作为容器。

img

我们搭建一个镜像,本质上就是将==个人项目+运行环境打包到一起==!

一个tomcat镜像,可以理解为一个安装了tomcat的Linux系统!

问题

  1. Docker 中一个centos镜像为什么只有200MB,而一个centos操作系统的iso文件要几个个G?

    答:Centos的iso镜像文件包含bootfs和rootfs,而docker的centos镜像复用操作系统的bootfs,只有rootfs和其他镜像层。

  2. 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为例:

64286183122

64286191187

查看和删除镜像

# 查看所有镜像: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

命令总结

img

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

注意

  1. ==所有目录必须是绝对路径==。
  2. 容器内目录不能使用简写符号,比如不可以使用“~”符号代替当前用户目录。
  3. 如果目录不存在,会自动创建
  4. 可以挂载多个数据卷

数据卷容器

# 想要创建一个容器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来构建一个自己的镜像了。

回忆一下,镜像的原理本质上是一个分层的文件系统。所以要搭建镜像,就是要像搭积木一样去搭建每一层的文件系统。

img

docker镜像的发布步骤

  1. 编写一个Dockerfile文件
  2. docker build 构建成为一个镜像
  3. docker run 镜像 创建一个可读写的容器,进行容器的相关操作
  4. docker commit 容器id 镜像名:tag 将容器打包成镜像
  5. docker tag 新镜像名:新tag 旧镜像id 给镜像添加一个新的标签
  6. 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可以看到生成的所有的中间镜像。

    64291244725

启动容器测试镜像

[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
    

发布到自己的阿里云镜像仓库

先创建个人实例

64291952562

创建命名空间

64291960401

创建仓库

注意:==这里的仓库(repository)名称就是你想要的镜像名==。其实当你执行docker images时,标题栏显示的也是repository。

64291985910

64291989960

点进去这个仓库,里面会指导你如何把镜像push过来

64292036551

因为我用的是阿里云服务器,这里就使用专有网络地址提高镜像拉取和推送速度。

使用专有网络推送

使用专有网络需要:

  • 登录地址必须是专有网络地址
  • 给镜像打tag时前缀地址需要是vpc地址
  1. 登录阿里云Docker Registry(使用VPC专有网络地址)
$ docker login --username=darren93 registry-vpc.cn-shenzhen.aliyuncs.com
  1. 将镜像推送到Registry
$ docker tag [ImageId] registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:[镜像版本号]
$ docker push registry-vpc.cn-shenzhen.aliyuncs.com/darren-test/test1:[镜像版本号]
  1. 拉取镜像
$ 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

总结

  1. 启动容器时,如果不配置网络,默认连接到bridge网络
  2. 在bridge网络下的容器可以互相通过ip访问,但不能通过容器名访问
  3. 创建自定义网络后,连接到同一自定义网络的容器可以互相通过容器名访问
  4. 跨网络的容器互相访问:使用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之后看看效果。

64294346058

# 挂掉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 

外部访问结果:

64299965094