docker的学习

1,847 阅读19分钟

是什么?

白话点, 是个提供了必要环境的虚拟机(类似于java的导入部分包一样和c++的头文件差不多), 所以它比普通的VMWare或者VirtualBox安装的虚拟机要

总体来说类似于jvm那样的存在, 只不过jvm运行的是java编译的字节码, docker运行的是各种组件, 比如mysql, redis, zookeeper或者我们的项目

有哪些关键的概念

  1. 镜像

docker镜像类似于系统安装包ISO, 或者我们对某个程序的备份, 将这个备份压缩成rar压缩包, 备份了很多程序的数据和配置, 我们只要把这个压缩包丢给别人, 别人解压并使用这个程序

  1. 容器

容器类似于我们的程序(前面的镜像是压缩包), 可以直接运行

总结
镜像和容器的关系是 一个镜像对应可以多个容器(只要你创建的多)

怎么用?

Docker安装与启动

安装Docker

由于我们学习的环境都使用的是CentOS,因此这里我们将Docker安装到CentOS上。注意:这里建议安装在CentOS7.x以上的版本,在CentOS6.x的版本中,安装前需要安装其他很多的环境而且Docker很多补丁不支持更新。

请直接挂载课程配套的Centos7.x镜像

(1)yum 包更新到最新

sudo yum update

(2)安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

(3)设置yum源为阿里云

sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

(4)安装docker

sudo yum install docker-ce

(5)安装后查看docker版本

docker -v

设置镜像加速

创建或编辑该文件:

vi /etc/docker/daemon.json 在该文件中输入如下内容:

{
    "registry-mirrors": [
        "https://docker.mirrors.ustc.edu.cn",
        "https://hub-mirror.c.163.com",
        "https://mirror.ccs.tencentyun.com",
        "https://registry.docker-cn.com"
    ]
}

docker基本指令

service docker start # 开启docker
service docker stop # 关闭docker
service docker restart # 重启docker

当然也可以使用systemctl

systemctl start docker # 同上

镜像管理

导入导出镜像

docker save java > /home/java.tar.gz
docker load < /home/java.tar.gz

镜像的下载其实是分层的, 具体可以使用docker inspect 镜像名, 可以看到

image.png

当我们有些层级在其他镜像中也存在则不需要重新下载, 直接复用了事

image.png

这里涉及到docker底层镜像的原理, 联合文件系统unionFS, 简单点说就是对于一个文件的修改是一层一层的叠加的, 类似于 github 提交修改的文件一样, 使用该系统后, docker 的镜像文件可以被继承, 复用

使用这套系统将会特别精简, 只需要加载必要继续环境和层级来完成我们的环境搭建, 不会想VMware虚拟机一样(一下子几G), 直接一个加载一个系统, 而使用docker我们只需要环境需要的

相关的 bootfs 和 rootfs 自行百度

镜像查找

docker search java

我们还可以添加--filter stars=3000, 表示镜像的stars大于3000

镜像下载

docker pull java

镜像上传

镜像上传到 dockerhub 远程仓库

  1. 登入 docker login --username 用户名 回车后需要输入密码

  2. docker push

image.png

注意: 最好加上 tag

不过最终我还是失败了, 为什么呢?

很简单

假设我 hub docker 上的账户名称是

image.png

docker tag my_centos:1.0.0 libai/centos:1.0.0

比如我 hub docker 的账号名称是 libai, 则镜像的名称必须是 libai 开头

image.png

将镜像上传到阿里云

  1. 打开阿里云控制台

image.png

  1. 搜索容器镜像

image.png

  1. 点击个人实例

image.png

  1. 点击命名空间, 并创建命名空间

image.png

命名空间的功能有点像 C++ 的namespace

  1. 创建镜像仓库

image.png

下一步, 发现有很多仓库, 这里根据需要选择就行

我选择了本地仓库

接下来就能看到非常详细的步骤

image.png

根据步骤就能够上传我们的镜像

image.png

查看镜像列表

docker images

查看镜像信息

docker inspect java
[
    {
        "Id": "sha256:d23bdf5b1b1b1afce5f1d0fd33e7ed8afbc084b594b9ccf742a5b27080d8a4a8",
        "RepoTags": [
            "java:latest"
        ],
        "RepoDigests": [
            "java@sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2017-01-17T00:52:54.890877145Z",
        "Container": "4b4ab1e131616e04a88f26f9811e5847dd0c3ec5f8178b634b388d3c510ee606",
        "ContainerConfig": {
            "Hostname": "33842653d6db",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=C.UTF-8",
                "JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64",
                "JAVA_VERSION=8u111",
                "JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1",
                "CA_CERTIFICATES_JAVA_VERSION=20140324"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "/var/lib/dpkg/info/ca-certificates-java.postinst configure"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:7cfe1ce37b990ea20d6377b8901f5ffccd463ed2f965e9730d834e693b53baec",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": [],
            "Labels": {}
        },
        "DockerVersion": "1.12.3",
        "Author": "",
        "Config": {
            "Hostname": "33842653d6db",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=C.UTF-8",
                "JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64",
                "JAVA_VERSION=8u111",
                "JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1",
                "CA_CERTIFICATES_JAVA_VERSION=20140324"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:7cfe1ce37b990ea20d6377b8901f5ffccd463ed2f965e9730d834e693b53baec",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": [],
            "Labels": {}
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 643195347,
        "VirtualSize": 643195347,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/fcdfe412499e0b1afe9cb8d6800eb56af9c578b1c49fbf0fc9f38fead4f32b2d/diff:/var/lib/docker/overlay2/5d79e6646df2342376ba59d8d21b70142d0e3fd0c9a0de2229c1cfa4c2d98e93/diff:/var/lib/docker/overlay2/47b9afdc585a2c847d112283d7d884f00140dab44c33203eeeccc4a592a23378/diff:/var/lib/docker/overlay2/9565b7df775e50948f7713b8a1b1ba6610eb055c958bbd23a7646b4414ccefab/diff:/var/lib/docker/overlay2/dd8233c055d2241a6e52a0f0acd48220f87a75e50fbe2a7355445bcc75bbfbb9/diff:/var/lib/docker/overlay2/64bb2d108355eb53a495cdb6804e602baa651888a27c10c19dfb0fa2351648b6/diff:/var/lib/docker/overlay2/3fb4d1d79e7b1966b16dfb4d7dcde2ac6ac602f932395acf2c5d3bd0573a9c67/diff",
                "MergedDir": "/var/lib/docker/overlay2/09e28e456caf00dd0ab82af1f594f248f05e0e64a4b931f69251ab2f1c9c4df3/merged",
                "UpperDir": "/var/lib/docker/overlay2/09e28e456caf00dd0ab82af1f594f248f05e0e64a4b931f69251ab2f1c9c4df3/diff",
                "WorkDir": "/var/lib/docker/overlay2/09e28e456caf00dd0ab82af1f594f248f05e0e64a4b931f69251ab2f1c9c4df3/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:a2ae92ffcd29f7ededa0320f4a4fd709a723beae9a4e681696874932db7aee2c",
                "sha256:0eb22bfb707db44a8e5ba46a21b2ac59c83dfa946228f04be511aba313bdc090",
                "sha256:30339f20ced009fc394410ac3360f387351641ed40d6b2a44b0d39098e2e2c40",
                "sha256:ce6c8756685b2bff514e0b28f78eedb671380084555af2b3833e54bb191b262a",
                "sha256:a3483ce177ce1278dd26f992b7c0cfe8b8175dd45bc28fee2628ff2cf063604c",
                "sha256:6ed1a81ba5b6811a62563b80ea12a405ed442a297574de7440beeafe8512a00a",
                "sha256:c3fe59dd955634c3fa1808b8053353f03f4399d9d071be015fdfb98b3e105709",
                "sha256:35c20f26d18852b74cc90afc4fb1995f1af45537a857eef042a227bd8d0822a3"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

镜像删除

docker rmi java

删除所有镜像

docker rmi $(docker images -q)

查看一个镜像如何创建的

docker history 镜像id

image.png

可以通过 Portainer 查看

image.png

容器管理

启动镜像(镜像初次产生容器)

启动镜像会默认创建出一个容器

  • docker run -it --name myjava java bash 使用bash运行保持控制台方式运行
  • docker run -it --name myjava -p 9000:8080 -p 9050:8050 java bash 以控制台方式运行java并且映射了java的端口8080到主机的9000, 映射到java的8050到主机的9050端口
  • docker run -it -name myjava -v /home/project:/soft --privileged java bash 映射java应用的路径/soft 到主机的/home/project路径并使用--privileged给了修改权限
mkdir /home/project
docker run -it --name myjava -p 9000:8080 -p 9050:8050 -v /home/project:/soft --privileged java bash

添加[option] -d创建和以后台方式启动容器

给容器内的应用添加环境参数

docker run -it 容器id -e 容器应用的参数 -e xxx -e yyy image.png

进入正在运行的容器

方式一:

docker exec -it 容器id 容器对应的命令 docker exec -it centos /bin/bash

方式二: docker attcah 容器id

这两种方式不同之处在于:
docker exec 是启动一个新的终端
docker attcah 进入容器正在执行的终端, 而不启动新的进程

暂停、停止和开启容器

docker pause 容器id # 可以在另一个控制台暂停
docker unpause 容器id # 可以在另一个控制台执行
docker stop 容器id # 可以停止掉容器
docker start 容器id # 启动容器
docker kill 容器id # 强制停止容器
docker restart 容器id # 重启容器

退出容器

exit # 直接推出容器, 并停止
ctrl + P + Q # 容器不停止, 退出

查看容器和查看运行中的容器

docker ps -a # 查看所有容器, 包括未运行的容器
docker ps -aq # 查看所有容器的id, 包括未运行的容器
docker ps # 查看正在运行的容器

删除容器

docker rm myjava 删除容器

docker rm -f $(docker ps -aq) 删除所有容器

查看容器日志

docker logs

docker logs -f -t --tail 容器id

查看容器内进程信息

docker top 容器id

从容器中拷贝

docker cp 容器id:容器内目录 本地目录

2.png

提交容器

  1. 首先下载

docker pull tomcat

  1. 运行

docker run -d tomcat

  1. 进入容器内部

docker exec -it 3e369e0c31d4 /bin/bash

  1. 修改webapp
whereis tomcat
cd /usr/local/tomcat
ls

image.png

cp -r webapps.dist/ROOT/ webapps

  1. 打包(完毕)
[root@localhost mysql]# docker commit --help

Usage:  docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Create a new image from a container's changes

Options:
  -a, --author string    Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
  -c, --change list      Apply Dockerfile instruction to the created image
  -m, --message string   Commit message
  -p, --pause            Pause container during commit (default true)

docker commit -a '你的名字' -m '消息, 你对容器的修改' 容器id 镜像名称:版本

docker commit -a 'zhazha' -m 'change webapp' 3e369e0c31d4 my_tomcat:0.0.1

命令总结

3.png

字典

4.png

创建docker卷

为什么需要数据卷?

这得从 docker 容器的文件系统说起。出于效率等一系列原因,docker 容器的文件系统在宿主机上存在的方式很复杂,这会带来下面几个问题:

  • 不能在宿主机上很方便地访问容器中的文件。
  • 无法在多个容器之间共享数据。
  • 当容器删除时,容器中产生的数据将丢失。

为了解决这些问题,docker 引入了数据卷(volume) 机制。数据卷是存在于一个或多个容器中的特定文件或文件夹,这个文件或文件夹以独立于 docker 文件系统的形式存在于宿主机中。数据卷的最大特定是:其生存周期独立于容器的生存周期。

使用数据卷的最佳场景

  • 在多个容器之间共享数据,多个容器可以同时以只读或者读写的方式挂载同一个数据卷,从而共享数据卷中的数据。
  • 当宿主机不能保证一定存在某个目录或一些固定路径的文件时,使用数据卷可以规避这种限制带来的问题。
  • 当你想把容器中的数据存储在宿主机之外的地方时,比如远程主机上或云存储上。
  • 当你需要把容器数据在不同的宿主机之间备份、恢复或迁移时,数据卷是很好的选择。

使用方法

docker volume create --name v1

例如:

root@ubuntu:/# docker volume create --name node1
node1
root@ubuntu:/# docker volume inspect node1
[
    {
        "CreatedAt": "2020-07-08T14:03:16+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/node1/_data",
        "Name": "node1",
        "Options": {},
        "Scope": "local"
    }
]

它把卷创建到了宿主机的/var/lib/docker/volumes/node1/_data目录下

匿名和具名卷

匿名卷

docker run -v /etc/nginx --name nginx01 -d nginx 这种方式创建的容器是匿名卷

具名卷

docker volume create nginx_volume

docker volume ls

DRIVER    VOLUME NAME
local     nginx_volume
local     portainer_data

docker run -v nginx_volume:/etc/nginx --name nginx02 -d nginx

这样就创建了一个具名卷的nginx

image.png

image.png

总结下

docker 卷有三种方式

  1. 匿名卷
  2. 具名卷
  3. 主机目录和docker虚拟机目录映射

安装mysql, 并映射卷的例子

这里我们选择使用 -v的方式实现主机和docker虚拟机的映射(docker卷)

docker run -p 23306:3306 -v /root/mysql/my.cnf:/etc/mysql/my.cnf -v /root/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --privileged=true --name mysql01 -d mysql

这段代码是通过官方命令修改而成的, 至于为什么知道需要映射那些目录, 主要还是查资料, 查linux系统安装完毕 mysql 之后, 主要涉及的目录是些什么, 我们就在docker上添加什么

-e 的mysql密码, 需要我们主动添加, 否则会报错

--privileged=true , 默认给容器内部的系统提升权限到 root

-p 23306:3306 将docker虚拟机的 3306 映射到主机的 23306 端口中

-d mysql 默认后台运行, 我发现这项放在前面经常会报错, 所以最高好还是放到最后

如果运行 mysql 会报错ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement, 可能需要在映射到主机的/root/mysql/my.cnf文件中添加 secure_file_priv=/var/lib/mysql

image.png

注意, 里面的参数 port=3306 端口不能修改, 因为我们的端口映射虚拟机就是 3306

image.png

成功连接上去

image.png

数据卷

主要用于同步文件使用

image.png

简单的Dockerfile入门

  1. 简单的写个dockerfile
FROM centos
VOLUME ["volume01", "volume02"]
CMD 'echo "=======end======="'
CMD /bin/bash
  1. build
docker build -f Dockerfile -t zhazha/centos:0.0.1 .

image.png

. 号,其实是在指定镜像构建过程中的上下文环境的目录。

docker build 其实是在 docker 引擎中构建的, 所以需要传递我们的上下文环境给docker

使用Portainer 查看我们创建的镜像, 就会发现 , 我们的指令在下面这个地方

image.png

Image layers

又遇到熟悉的 layer

我们写的 Dockerfile每一行代码都算一个层, docker限制我们的层不能超过 127

image.png

现在我们启动我们的镜像文件

docker run -it f2fbcaac50da /bin/bash

image.png

可以看到两个 volume

查看docker的inspect就可以发现

image.png

这两个映射

现在我们正式开始学习数据卷

多个系统都有一个卷是共享的

  1. 写简单的Dockerfile
FROM centos
VOLUME ["volume"]
CMD echo "====end====="
CMD /bin/bash

使用

docker build -f Dockerfile -t zhazha/centos:0.0.1 .

创建出一个镜像文件

image.png

现在我们在三个控制台上创建

docker run --name=centos01 -it 3cc90e8bc91c /bin/bash
docker run --volumes-from centos01 --name=centos02 -it 3cc90e8bc91c /bin/bash
docker run --volumes-from centos01 --name=centos03 -it 3cc90e8bc91c /bin/bash

现在我们在 volume 中创建一个新的文件

touch zhazha.txt

image.png

在其他控制台中看看

image.png

我们写入hello centos2

然后到 centos3 上看看

image.png

这个文件的volume在三个系统中以复制的方式存在, 所以即便删除掉其中一个系统, 另外两个系统都不会收到任何影响

image.png

CMD 、 RUN 和 ENTRYPOINT 的区别

  1. RUN
  • 构建镜像时运行的指令

说白了, 就是 docker build时运行的RUN

  1. CMD
  • 运行容器时执行的shell环境, 但它可以被代替

说白了, 就是docker run时运行的, 比如 CMD echo "容器执行了", 它被放在dockerfile的最后一行

FROM centos:7
MAINTAINER zhazha<22222@qq.com>
RUN echo "容器构建了"
CMD echo "容器执行了"

image.png

image.png

CMD用于指定容器启动时执行的命令,每个Dockerfile只能有一个CMD命令,多个CMD命令只执行最后一个。 若容器启动时指定了运行的命令,则会覆盖掉CMD中指定的命令。

  1. ENTRYPOINT

ENTRYPOINTCMD 一样, Dockerfile中,只能有 一个ENTRYPOINT 指令,如果有多个 ENTRYPOINT 指令则以最后 一个 为准

  • 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

什么叫不被命令参数执行的指令覆盖?

现在我们把 dockerfile 修改下

FROM centos:7
MAINTAINER zhazha<22222@qq.com>
RUN echo "容器构建了"
CMD ls -a

docker run -it 0ff248d85404 -l

image.png

报错了

CMD 替换成 ENTRYPOINT

docker build -f centos_dockerfile -t mm_centos02 .

docker run -it b6b9a3fe10cb -l

image.png

现在知道什么覆盖了吧?

使用CMD 的方式, 如果在 docker run 的最后又有新的指令, 则会立即代替掉我们 dockerfile 里面最终一行, 所写的 CMD 指令, 如果使用的是 ENTRYPOINT 则, docker run 最后命令将会添加到dockerfile

需要注意的是, RUN 这些命令是一层包装的意思, docker里面的镜像最多包装127层, 所以前一个 RUN cd /home 后一个RUN touch 1.txt所处的目录不同, 前一个RUN的目录可能是在home下面, 而第二个RUN目录其实还在根目录下, 所以下面的代码最多会在根目录下创建一个1.txt文件

FROM centos:7
MAINTAINER zhazha<22222@qq.com>
RUN ["cd", "/home"]
RUN ["touch", "1.txt"]

需要这样:

FROM centos:7
MAINTAINER zhazha<22222@qq.com>
RUN ["touch", "/home/1.txt"]

DockerFile文件编写

1.png

  1. 编写dockerfile
FROM centos:7
MAINTAINER zhazha<2222222222@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "=====end====="
CMD /bin/bash
  1. 执行命令

docker build -f Dockerfile -t zhazha/centos:1.0.0 .

image.png

  1. 成功创建, 现在可以看到镜像了

image.png

image.png

现在我们的这个镜像创建的容器可以使用 vimnet 相关的指令

使用dockerfile定制自己的tomcat虚拟机

如果我们编写的Dockerfile文件名是Dockerfile, 则不需要添加docker build -f 不需要添加-f, 他会自动找到Dockerfile的文件

  1. 准备资源文件

image.png

  1. 编写Dockerfile

vi Dockerfile

FROM centos:7
MAINTAINER zhazha<2222222222@qq.com>
ENV MYPATH /usr/local
COPY readMe.txt $MYPATH/readMe.txt
WORKDIR $MYPATH
ADD openJdk11.tar.gz $MYPATH
ADD apache-tomcat-10.tar.gz $MYPATH
RUN yum -y install vim
ENV JAVA_HOME /usr/local/jdk-11.0.14.1+1
ENV CLASS_PATH $JAVA_HOME/lib
CMD ["export", "PATH JAVA_HOME CLASSPATH"]
CMD source /etc/profile.d/java.sh
ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.17
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-10.0.17/bin/startup.sh && tail -F /usr/local/apache-tomcat-10.0.17/logs/catalina.out

创建镜像:

docker build -t my_tomcat .

image.png

创建成功:

image.png

image.png

创建容器:

docker run -it b49f9241556e /bin/bash

image.png

环境变量添加成功:

image.png

image.png

docker 网络

要了解 docker 的网络, 需要了解 veth-pair 技术

Virtual Ethernet Pair 简称 veth pair ,是一个成对的端口,所有从这对端口一端进入的数据包都将从另一端出来,反之也是一样

探索过程

我们编写 Dockerfile

FROM tomcat:latest
MAINTAINER zhazha<222@qq.com>
RUN apt update
RUN apt -y install iputils-ping # 让你可以使用 ping
RUN apt -y install iproute2 # 让你可以使用 ip addr
RUN apt -y install net-tools # 让你可以使用 ifconfig

然后启动起来

docker run -P -it 镜像ID

现在我们在容器内输入ip a查看 ip 180: eth0@if181

image.png

然后在主机上输入 ip a 看看 181: veth005201b@if180

image.png

然后就能得到下面这张图片:

image.png

PS: 需要更多的 docker 图片可以查百度

image.png

上图的紫色 NAT 表示直连

如果我们再次启动另一个 tomcat 照上面的方式还是能看到

虚拟机:

image.png

主机:

image.png

总体来说, 就类似于 docker 在虚拟机与虚拟机间搭建了一座桥梁, 虚拟机借助这座桥梁与另外的虚拟机通讯

也可以当作管道, 虚拟机在管道间通讯

我们需要注意的是现在 不仅仅是主机能与虚拟机ping通, 而且虚拟机和虚拟机之间也是可以ping通的

image.png

link(不推荐)

link的方式已经不被推荐使用

为什么需要?

问: 前面我们知道虚拟机已经可以和虚拟机相互 ping 通, 那为什么还需要 link 呢?

ip 到 域名 的改变

答: 其实很简单, 就因为一段代码: ping 172.17.0.3

① ip 不好记忆, 是硬编码

② 虚拟机的 ip 是 docker 随机分配的, 假设虚拟机 tomcat01 现在的地址是 172.17.0.3 下次可不一定还是它, 所以我们需要已经类似域名的东西作为 ip 的代替品, 类似DNS的方式

③ 容器的端口也可以自定义

所以 link 诞生了

是什么?

简洁版: 通过dockerlink机制可以通过一个name来和另一个容器通信,link机制方便了容器去发现其它的容器并且可以安全的传递一些连接信息给其它的容器

image.png

需要注意的是 link 的方式存在发送端和接收端, 他是单向的

怎么用?

docker run --name=tomcat01 -it 5372cc765456 /bin/bash
docker run --link=tomcat01 --name=tomcat02 -it 5372cc765456 /bin/bash

进入容器 tomcat01 去 ping 容器 tomcat02 无法 ping 通

image.png

反之可以:

docker run --link=tomcat01 --name=tomcat02 -it 5372cc765456 ping tomcat01

image.png

怎么实现的?

link底层的实际上使用的是 修改 hosts 的方式

image.png

现在我们知道为什么在 tomcat02 内部使用 pingtomcat01

那如果 tomcat01ip 变了呢? 没关系, docker 会主动修改 tomcat02 内的 hoststomcat01ip , 全自动的, 不需要用户自己修改

缺点

虽然link 打通了一个单向的管道, 但无法反向访问, 所以这是他的缺点

所以 自定义 docker 网络 的方式出现了

自定义 docker 内部网络

前置知识

在创建内网前, 我们需要知道一些网络方面的知识

我们经常能看到这样:

image.png

172.17.0.1/16 这后面的 16 是什么?

它表示了 161 , 而这里的 161 用于下面的 ip

11111111.11111111.0.0 子网掩码: 255.255.0.0

而他的作用是限定了我们主机的 ip 的数量可以是 172.17.0.0 ~ 172.17.255.255 去除掉 网络号(全0) 172.17.0.0 和 广播地址 172.17.0.255(全1), 剩下的都是主机号

不过据说出现了 CIDR 已经不需要减 2 , 不过这不是本文重点

现在可以学习docker网络方面的知识了

docker的网络模式

image.png

docker 的网络模式:

  1. bridge : 桥接模式, 就是我们说的 docker0 , 一般默认创建的虚拟机就使用的 docker0 进行桥接
  2. host: 主机直连
  3. none: 不配置网络

怎么用? (创建docker网络)

[root@localhost ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     将容器连接到网络
  create      创建 docker 的网络
  disconnect  断开容器与网络的链接
  inspect     显示一个或多个网络的详细信息
  ls          列出网络
  prune       删除所有未使用的网络
  rm          移除一个或多个网络

image.png

  1. 创建网络
docker network create -d bridge --subnet 192.167.0.0/16 --gateway 192.167.0.1 mynet

image.png

看注解, 我们可以把上面的代码精简下

docker network create --subnet 192.167.0.0/16 --gateway 192.167.0.1 mynet

指定 子网 ip网关 ip

image.png

  1. 创建容器并连接

docker run -P --network mynet --name tomcat01 -it 5372cc765456 /bin/bash

image.png

image.png

借助Portainer我们也可以看见:

image.png

主机和tomcat01也互通

docker run -P --network mynet --name tomcat02 -it 5372cc765456 /bin/bash

image.png

现在 tomcat01tomcat02 也是互通的

ping tomcat01
ping tomcat02

外部容器连接到一个网络集群

有一两个外部的虚拟机需要连接到一个网络集群中这种场景, docker 提供了这种场景的支持

QQ截图20220303004011.png

docker network connect mynet 8fcf9d6f2624

image.png