侧边栏壁纸
  • 累计撰写 106 篇文章
  • 累计创建 19 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Docker入门到精通

zero
2021-01-08 / 0 评论 / 1 点赞 / 61 阅读 / 63197 字
温馨提示:
本文最后更新于 2024-07-04,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1、安装Docker

# 1、卸载旧的版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
# 2、需要的安装包
yum install -y yum-utils
# 3、设置镜像的仓库
yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 更新yum软件包索引
yum makecache fast
# 4、安装docker相关的类容 docker-ce 社区版 docker-ee 企业版
yum install docker-ce docker-ce-cli containerd.io
# 5、启动decker
systemctl start docker
# 6、查看是否启动成功
docker version
# 7、下载镜像如:hello-world
docker run hello-world
# 8、查看一下下载的这个hello-world 镜像

了解:卸载docker

# 1、 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2、删除资源
rm -rf /var/lib/docker
# /var/lib/docker docker的默认工作路径!

2、阿里云镜像加速

1、登录阿里云找到容器服务

登录之后在搜索栏输入容器镜像服务 ,第一次进入需要开启服务

2、找到镜像加速地址

# 下图是我的镜像服务
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://pqp40fmp.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker

3、Docker的常用命令

3.1、帮助命令

docker version # 显示docker的版本信息
docker indo    # 显示docker的系统信息,包括镜像和容器的数量
docker --help  # 帮助命令

3.2、镜像命令

docker images 查看所有本地的主机上的镜像

[root@localhost ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    bf756fb1ae65   12 months ago   13.3kB

# 解释
REPOSITORY  # 镜像的仓库源
TAG         # 镜像的标签
IMAGE ID    # 镜像的id
CREATED     # 镜像的创建时间
SIZE        # 镜像的大小

# 可选项
 -a, --all            # 显示所有镜像
 -q, --quiet          # 只显示镜像id

docker search 搜索镜像

[root@localhost ~]# docker search mysql
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   10326     [OK]       
mariadb                           MariaDB is a community-developed fork of MyS…   3825      [OK]       
mysql/mysql-server                Optimized MySQL Server Docker images. Create…   754                  [OK]
percona                           Percona Server is a fork of the MySQL relati…   518       [OK]       
centos/mysql-57-centos7           MySQL 5.7 SQL database server                   86                   
mysql/mysql-cluster               Experimental MySQL Cluster Docker images. Cr…   79                   
centurylink/mysql                 Image containing mysql. Optimized to be link…   60                   [OK]
bitnami/mysql                     Bitnami MySQL Docker Image                      47                   [OK]
deitch/mysql-backup               REPLACED! Please use http://hub.docker.com/r…   41                   [OK]
tutum/mysql                       Base docker image to run a MySQL database se…   35                   
...
# 可选项 , 通过搜藏来过滤
--filter=STARS=3000

docker pull 下载镜像

# 下载镜像 docker pull 镜像名[:tag]
[root@localhost ~]# docker pull mysql
Using default tag: latest           # 如果不写 tag, 默认就是latest
latest: Pulling from library/mysql
6ec7b7d162b2: Pull complete         # 分层下载,docker iamge的核心 联合文件系统
fedd960d3481: Pull complete 
7ab947313861: Pull complete 
64f92f19e638: Pull complete 
3e80b17bff96: Pull complete 
014e976799f9: Pull complete 
59ae84fee1b3: Pull complete 
ffe10de703ea: Pull complete 
657af6d90c83: Pull complete 
98bfb480322c: Pull complete 
6aa3859c4789: Pull complete 
1ed875d851ef: Pull complete 
Digest: sha256:78800e6d3f1b230e35275145e657b82c3fb02a27b2d8e76aac2f5e90c1c30873
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest      # 真实地址

# 等价于它
docker pull mysql
docker pull docker.io/library/mysql:latest

# 指定版本下载
[root@localhost ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
6ec7b7d162b2: Already exists 
fedd960d3481: Already exists 
7ab947313861: Already exists 
64f92f19e638: Already exists 
3e80b17bff96: Already exists 
014e976799f9: Already exists 
59ae84fee1b3: Already exists 
7d1da2a18e2e: Pull complete 
301a28b700b9: Pull complete 
529dc8dbeaf3: Pull complete 
bc9d021dc13f: Pull complete 
Digest: sha256:c3a567d3e3ad8b05dfce401ed08f0f6bf3f3b64cc17694979d5f2e5d78e10173
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

docker rmi 删除镜像

[root@localhost ~]# docker rmi -f 镜像id      # 删除指定的镜像
[root@localhost ~]# docker rmi -f 镜像id 镜像id 镜像id 镜像id 镜像id      # 删除多个容器
[root@localhost ~]# docker rmi -f $(docker images -aq)      # 删除全部的镜像

3.3、容器命令

说明:我们有了镜像才可以创建容器,linux,下载一个centos镜像来测试学习

docker pull centos

新建容器并启动

docker run [可选参数] image

# 参数说明
--name="Name"  # 容器名字  tomcat01   tomcat02, 用来区分容器
-d              # 后台方式运行
-it             # 使用交互方式运行,进入容器查看类容
-p              # 指定容器的端口 -p 8080:8080
    -p ip:主机端口:容器端口
    -p 主机端口:容器端口    (常用)
    -p 容器端口
    容器端口
-p              # 随机指定端口

# 测试,启动并进入容器
[root@localhost ~]# docker run -it centos /bin/bash
[root@cf725551c40c /]# ls   # 查看容器内的centos,基础版本,很多命令都是不完善的!
bin  etc   lib    lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
# 从容其中退回主机
[root@cf725551c40c /]# exit
exit
[root@localhost ~]# ls
anaconda-ks.cfg       logs       store  模板  图片  下载  桌面
initial-setup-ks.cfg  nohup.out  公共   视频  文档  音乐

列出所有运行的容器

# docker ps 命令
   # 列出当前正在运行的命令
-a # 列出当前正在运行的命令+带出历史运行过的容器
-n=? # 显示最近创建的容器
-q # 只显示容器的编号
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED         STATUS                            PORTS     NAMES
cf725551c40c   centos         "/bin/bash"   5 minutes ago   Exited (130) About a minute ago             zen_franklin
4588b275660d   bf756fb1ae65   "/hello"      2 hours ago     Exited (0) 2 hours ago                      hopeful_hermann

退出容器

exit    # 直接容器退出并退出
Ctrl + P + Q    # 容器不停止退出

删除容器

docker rm 容器id                   # 删除指定的容器,不能删除正在运行的容器
docker rm -f $(docker ps -aq)       # 删除所有的容器
docker ps -a -q|xargs docker rm     # 删除所有的容器

启动和停止容器的

docker start 容器id   # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id    # 停止当前正在运行的容器
docker kill 容器id    # 强制停止当前容器

3.4、常用其他命令

后台启动容器

# 命令 docker run -d 镜像名
[root@localhost ~]# docker run -d centos

# 问题docker ps, 发现 centos 停止了

# 常见的坑:docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立即停止,就是没有程序了

查看日志

docker logs -f -t --tail 容器,没有日志

# 自己编写一段shell脚本
[root@localhost /]# docker run -d centos /bin/sh -c "while true;do echo FlamingYouth; sleep 1;done"

# 显示id
[root@localhost /]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
b4b7dca27aec   centos    "/bin/sh -c 'while t…"   8 seconds ago   Up 7 seconds             hardcore_kalam
# 显示日志
-tf         # 显示日子
--tail      # 要显示日志
[root@localhost /]# docker logs -tf --tail 10 b4b7dca27aec

查看容器中进程信息

# top命令
[root@localhost ~]# docker top b4b7dca27aec
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                10809               10789               0                   07:50               ?                   00:00:01            /bin/sh -c while true;do echo FlamingYouth; sleep 1;done
root                16461               10809               0                   08:57               ?                   00:00:00            /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1

查看镜像的元数据

# 命令
docker inspect 容器id

# 测试
[root@localhost ~]# docker inspect b4b7dca27aec
[
    {
        "Id": "b4b7dca27aec2376338cbfd5656661fdf2cbc549635e2444eb6d6f1b3d630529",
        "Created": "2020-12-29T09:40:40.771199842Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true;do echo FlamingYouth; sleep 1;done"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 10809,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-12-29T09:40:41.156505681Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
        "ResolvConfPath": "/var/lib/docker/containers/b4b7dca27aec2376338cbfd5656661fdf2cbc549635e2444eb6d6f1b3d630529/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/b4b7dca27aec2376338cbfd5656661fdf2cbc549635e2444eb6d6f1b3d630529/hostname",
        "HostsPath": "/var/lib/docker/containers/b4b7dca27aec2376338cbfd5656661fdf2cbc549635e2444eb6d6f1b3d630529/hosts",
        "LogPath": "/var/lib/docker/containers/b4b7dca27aec2376338cbfd5656661fdf2cbc549635e2444eb6d6f1b3d630529/b4b7dca27aec2376338cbfd5656661fdf2cbc549635e2444eb6d6f1b3d630529-json.log",
        "Name": "/hardcore_kalam",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/6ac692e899a9a6433423beb2cda55efb6589a7e590d38d6eafebc4cc6cc77fd6-init/diff:/var/lib/docker/overlay2/602b32ecf8fdc2ac30f177eae6e59852d1fad4ba4af81893ac8760c7ee806d53/diff",
                "MergedDir": "/var/lib/docker/overlay2/6ac692e899a9a6433423beb2cda55efb6589a7e590d38d6eafebc4cc6cc77fd6/merged",
                "UpperDir": "/var/lib/docker/overlay2/6ac692e899a9a6433423beb2cda55efb6589a7e590d38d6eafebc4cc6cc77fd6/diff",
                "WorkDir": "/var/lib/docker/overlay2/6ac692e899a9a6433423beb2cda55efb6589a7e590d38d6eafebc4cc6cc77fd6/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "b4b7dca27aec",
            "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"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "while true;do echo FlamingYouth; sleep 1;done"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20201204",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "f68852780deafa92a15e40851bbf4b8136a46a824bc10a1f0d10e1a0de66cefb",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/f68852780dea",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "d7025b7caff9b7fcec1f0e2e9e4205159db66224bcb08dfc4fccf14dce3e6920",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "dfe4906e819a50a04f6bab4d013f712b90b0f1b1347794f978939fd20863605e",
                    "EndpointID": "d7025b7caff9b7fcec1f0e2e9e4205159db66224bcb08dfc4fccf14dce3e6920",
                    "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
                }
            }
        }
    }
]

进入当前正在运行的容器

# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置

# 命令
docker exec -it 容器id bashShell

# 测试
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS        PORTS     NAMES
b4b7dca27aec   centos    "/bin/sh -c 'while t…"   15 hours ago   Up 15 hours             hardcore_kalam
[root@localhost ~]# docker exec -it b4b7dca27aec /bin/bash
[root@b4b7dca27aec /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 Dec29 ?        00:00:01 /bin/sh -c while true;do echo FlamingYouth; s
root       4462      0  0 01:05 pts/0    00:00:00 /bin/bash
root       4486      1  0 01:05 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=s
root       4487   4462  0 01:05 pts/0    00:00:00 ps -ef

# 方式二
docker attach 容器id

#测试
[root@localhost ~]# docker attach b4b7dca27aec
正在执行当前的代码...

# docker exec       # 进入容器后开启一个新的终端,可以在里面操作(常用)
# docker attach     # 进入容器正在执行的终端,不会启动新的进程

从容器内拷贝文件到主机上

docker cp 容器id:容器内路径 目的的主机路径

# 查看当前主机目录下文件
[root@localhost home]# ls
flamingyouth  FlamingYouth.java
[root@localhost home]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED              STATUS              PORTS     NAMES
d8edc051860a   centos    "/bin/bash"   About a minute ago   Up About a minute             youthful_wu

# 进入docker 容器内部
[root@localhost home]# docker attach d8edc051860a
[root@d8edc051860a /]# ls 
bin  etc   lib    lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
[root@d8edc051860a /]# cd /home
[root@d8edc051860a home]# ls
# 在容器内新建一个文件
[root@d8edc051860a home]# touch test.java
[root@d8edc051860a home]# exit
exit
[root@localhost home]# docker ps -a
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS                     PORTS     NAMES
d8edc051860a   centos    "/bin/bash"   2 minutes ago   Exited (0) 8 seconds ago             youthful_wu

# 将这文件拷贝出来到主机上
[root@localhost home]# docker cp d8edc051860a:/home/test.java /home
[root@localhost home]# ls
flamingyouth  FlamingYouth.java  test.java

# 拷贝是一个手动过程,未来我们使用-v 卷的技术,可以实现,自动同步 / home /home

3.5、小结

attach          # 当前 shell 下 attach 连接指定运行镜像
build           # 通过 Dockerfile 定制镜像
commit          # 提交当前容器为新的镜像
cp              # 从容期中考被指定文件或目录到宿主机中
create          # 创建一个新的容器,同run,但不启动容器
difff           # 查看 docker 容器变化
events          # 从 docker 服务获取容器实时事件
exec            # 在已存在的容器上运行命令
export          # 导出容器的内容流作为一个 tar 归档文件[对应 import]
history         # 展示一个镜像形成的历史
images          # 列出系统当前镜像
import          # 从 tar 包中的内容创建一个新的文件系统映像[对应export]
info            # 显示系统相关信息
inspect         # 查看容器详细信息
kill            # kill 指定 docker 容器
load            # 从一个 tar 包中加载一个镜像[对应 save]
login           # 注册或登录一个 docker 源服务器
logout          # 从当前 Docker registry 退出
logs            # 输出当前容器日志信息
port            # 查看映射端口对应的容器内部源端口
pause           # 暂停容器
ps              # 列出容器列表
pull            # 从 docker 镜像源服务器拉取指定镜像或者库镜像
restart         # 重启运行的容器
rm              # 移除一个或者多个容器
rmi             # 移除一个或者多个镜像[无容器使用该镜像才可以删除,否则需删除相关容器才可继续或 -f 强制删除]
run             # 创建一个新的容器并运行一个命令
save            # 保存一个镜像为一个 tar 包[对应 load]
search          # 在 docker hub 中搜索镜像
start           # 启动容器
stop            # 停止容器
tag             # 给源中镜像打标签
top             # 查看容器中运行的进程信息
unpause         # 取消暂停容器
version         # 查看 docker 版本号
wait            # 截取容器停止时的退出状态值

3.6、作业练习

Docker 安装 Nginx

# 1、搜索镜像 search 建议大家去docker搜索,可以看到帮助文档
# 2、下载镜像 pull
# 3、运行测试
[root@localhost home]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    ae2feff98a0c   2 weeks ago   133MB
centos       latest    300e315adb2f   3 weeks ago   209MB

# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内部端口
[root@localhost home]# docker run -d --name nginx01 -p 3344:80 nginx
WARNING: IPv4 forwarding is disabled. Networking will not work.
b462b3118b7f981cd5f731bafd71e952723c3763239e13ab9294da2b0dbd0758
[root@localhost home]# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

#进入容器
[root@localhost ~]# docker exec -it nginx02 /bin/bash
root@44e75fe5b85b:/# ls
bin   dev          docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc           lib   media  opt  root  sbin  sys  usr
root@44e75fe5b85b:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@44e75fe5b85b:/# cd /etc/nginx
root@44e75fe5b85b:/etc/nginx# ls
conf.d  fastcgi_params  koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params  uwsgi_params  win-utf

Docker 安装 tomcat

# 官方的使用
docker run -it -- rm tomcat:9.0

# 我们之前的启动都是后台,停止了容器之后,容器还是可以查到 docker run -it --rm, 一般用来测试,用完就删除

# 下载在启动
docker pull tomcat

# 启动运行
docker run -d -p 3344:8080  --name tomcat01 tomcat

# 测试访问没有问题

# 进入容器
[root@localhost ~]# docker exec -it tomcat01 /bin/bash

# 发现问题:1、liunx命令少了, 2、没有webapps  阿里云镜像原因,默认是最小的镜像

4、Docker镜像讲解

如何提交一个自己的镜像

4.1、commit镜像

docker commit   提交容器成为一个新的副本

# 命令和git原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名: [TAG]

4.2、实战测试

# 1、启动一个默认的tomcat
docker run -d --name=tomcat -p 8099:8080 tomcat
# 2、发现这个默认的tomcat 是没有webapps应用,镜像的原因,官方的镜像默认 webapps 下面是没有文件的!

# 3、我自己拷贝进去了基本的文件
cp -f webapps.sart/* webapps
# 4、将我们操作的容器通过commit提交为一个镜像! 我们以后就使用我们修改过的镜像即可
docker commit -m="提交者姓名" -a="作者" 容器id 目标镜像名:[TAG]

5、容器数据卷

5、1 什么是容器数据卷

总结一句话:容器的持久化和同步操作!荣期间也是可以数据共享的!

5.2、使用数据卷

方式一:直接使用命令来挂载

docker run -it -v 主机目录:容器内目录

# 测试
[root@localhost ~]# docker run -it -v /home/Test:/home centos /bin/bash

# 启动起来时候我们可以通过 docker inspect 容器id
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/test",
                "Destination": "/home",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

好处:以后修改只需要在本地修改即可,容器内会自动同步!

5.3、实战:安装MySQL

思考:MySQL的数据持久化的问题

# 获取镜像
[root@localhost test]# docker pull mysql:5.7

# 运行容器,需要做数据挂载! 
# 安装启动mysql , 需要配置密码,这是要注意点!
# 官方测试: docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

#启动我们的
-d 后台运行
-p 端口运行
-v 卷挂载
-e 环境配置
--name 容器名字
[root@localhost ~]# docker run -d -p 3340:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysq -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

# 启动成功之后,我们在本地使用 sqlyog 来接测试一下
# sqlyog-连接到服务器端3340 --- 3340 和容器内的 3306映射 连接成功

发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能

具名和匿名挂载

# 匿名挂载
-v 容器内路径!
docker run -d -P --name nginx01 -v /ect/nginx nginx

# 查看所有的 volume 的情况
[root@localhost ~]# docker run -d -P --name nginx03 -v /ect/nginx nginx
ca140c2539fa4d04b1f1ddd72c496237d863f21cd3054b0e9d64a1b815009805
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     7a4e8691e5158cde8519a78809da1984d414149a198f2f387e277ae46e7062cb

# 这里发现,这种就是匿名挂载,我们在 -v 只写了容器内的路径,没有写容器外的路径!

# 具名挂载
[root@localhost ~]# docker run -d -P --name nginx04 -v juming-nginx:/ect/nginx nginx
8e1f5fe09c1655314d6fdf1a2117baa0ef012d35ed141d285756dbc33e026123
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     7a4e8691e5158cde8519a78809da1984d414149a198f2f387e277ae46e7062cb
local     juming-nginx

# 通过 -v 卷名:容器内路径
# 查看一下这个卷
[root@localhost ~]# docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2020-12-31T15:51:20+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxxx/_data

我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载

# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径            # 匿名挂载
-v 卷名:容器内路径         # 具名挂载
-v /宿主机路径::容器内路径    # 指定路径挂载

拓展:

# 通过 -v 容器内路径:ro rw 改变读写权限
ro  redonly     # 只读
rw  readwrite   # 可读可写

# 一旦设置了容器权限,容器对我们挂载出来的内容就有限定了
docker run -d -p --name nginx01 -v juming-nginx:/etc/nginx:ro   nginx
docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:rw   nginx

# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作的!

5.4、初始Dockerfile

Dockerfile 就是用来构建docker 镜像的构建文件!

通过如下脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,没一个命令都是一层

# 创建一个dockerfile文件 , 名字可以随机 建议 Dockerfile
# 文件中的内容 指令(大写) 参数
FORM centos

VOLUME ["volume01","volume02"]  // 匿名挂载

CMD echo "----end------"
CMD /bin/bash

# 这里的每一个命令,就是镜像的一层

[root@localhost docker-test-volume]# docker build -f dockerfile1 -t flamingyouth/centos .
# 启动自己写的容器

[root@localhost docker-test-volume]# docker run -it 349e0438a482 /bin/bash
[root@d8eb91613a84 /]# ls -l
total 0
lrwxrwxrwx.   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x.   5 root root 360 Dec 31 08:40 dev
drwxr-xr-x.   1 root root  66 Dec 31 08:40 etc
drwxr-xr-x.   2 root root   6 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   6 Dec  4 17:37 lost+found
drwxr-xr-x.   2 root root   6 Nov  3 15:22 media
drwxr-xr-x.   2 root root   6 Nov  3 15:22 mnt
drwxr-xr-x.   2 root root   6 Nov  3 15:22 opt
dr-xr-xr-x. 263 root root   0 Dec 31 08:40 proc
dr-xr-x---.   2 root root 162 Dec  4 17:37 root
drwxr-xr-x.  11 root root 163 Dec  4 17:37 run
lrwxrwxrwx.   1 root root   8 Nov  3 15:22 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3 15:22 srv
dr-xr-xr-x.  13 root root   0 Dec 31 01:03 sys
drwxrwxrwt.   7 root root 145 Dec  4 17:37 tmp
drwxr-xr-x.  12 root root 144 Dec  4 17:37 usr
drwxr-xr-x.  20 root root 262 Dec  4 17:37 var
# 这个目录就是我们生成镜像的时候自动挂载的,数据卷目录
drwxr-xr-x.   2 root root   6 Dec 31 08:40 volume01
drwxr-xr-x.   2 root root   6 Dec 31 08:40 volume02

这个卷和外部一定有同步目录

[root@localhost ~]# docker inspect d8eb91613a84
"Mounts": [
            {
                "Type": "volume",
                "Name": "87e428701abb15e7078e477e9347e3efd6972b5607b7dec32948999e29dd3e68",
                "Source": "/var/lib/docker/volumes/87e428701abb15e7078e477e9347e3efd6972b5607b7dec32948999e29dd3e68/_data",
                "Destination": "volume01",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "dab549523735a7b0a3c334d1985ed1f67684b99d2eaccea2ec9085f732934699",
                "Source": "/var/lib/docker/volumes/dab549523735a7b0a3c334d1985ed1f67684b99d2eaccea2ec9085f732934699/_data",
                "Destination": "volume02",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]

测试一下刚才的文件是否同步出去

这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像

假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径

5.5、数据卷容器

多个主机同步数据

# 测试 
# 启动docker01
docker run -it --name docker01 flamingyouth/centos
# 启动docker02,设置共享卷docker1
docker run -it --name docker02 --volumes-from docker01 flamingyouth/centos
# 启动docker03,设置共享卷docker1
docker run -it --name docker03 --volumes-from docker01 flamingyouth/centos

多个mysql实现数据共享

# 启动mysql01
docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
# 启动mysql02
docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7

结论:

容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。

但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!

6、DockerFile

dockerfile是用来构建docker镜像文件,命令参数脚本

6.1、DockerFile介绍

构建步骤:

  1. 编写一个dockerfile文件

  2. docker build 构建成为一个镜像

  3. docker run 运行镜像

  4. docker push 发布镜像(DockerHub、阿里云镜像仓库)

查看了很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像

官方既然可以制作镜像,那我们也可以

6.2、DockerFile构建过程

基础知识

  1. 每个保留关键字(指令)都是必须是大写字母

  2. 从上到下顺序执行

  3. 表示注释

  4. 每一个指令都会创建提交一个新的镜像层。并提交

dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单

Docker镜像逐渐成为企业交付的标准,必须要掌握

步骤:开发,部署,运维 ———— 缺一不可

DockerFile:构建文件,定义了一切的步骤,源代码

DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品

Docker容器:容器就是镜像运行起来提供服务器

DockerFile的指令

以前的话我们就是使用别人的,现在我们知道了这些命令后,我们来联系自己写一个镜像

FROM            # 基础镜像,一切这里开始构建
MAINTAINER      # 镜像是谁写的,姓名+邮箱
RUN             # 镜像构建的时候需要运行的命令
ADD             # 步骤:tomcat镜像。这个tomcat压缩包。添加内容
WORKDIR         # 镜像的工作目录
VOLUME          # 挂载的目录
EXPOSE          # 暴露端口配置
CMD             # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可以被替代
ENTRYPOINT      # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD         # 当构建一个被继承 DockerFile 这个时候就会运行 ONBUILD 的指令,触发指令
COPY            # 类似ADD,将我们文件拷贝到镜像中
ENV             # 构建的时候设置环境变量

实战测试

Docker Hub 中99%镜像都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行的构建

# 官方镜像
FROM scratch
ADD centos-7-x86_64-docker.tar.xz /

LABEL \
    org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20201113" \
    org.opencontainers.image.title="CentOS Base Image" \
    org.opencontainers.image.vendor="CentOS" \
    org.opencontainers.image.licenses="GPL-2.0-only" \
    org.opencontainers.image.created="2020-11-13 00:00:00+00:00"

CMD ["/bin/bash"]

创建一个自己的centos

# 1.编写Dockerfile的文件
FROM centos
MAINTAINER andy<935917439@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

# 2、通过这个文件构建镜像
[root@localhost dockerfile]# docker build -f FlamingYouth-centos -t mycentos:0.1 .

Successfully built cd544b1d0975
Successfully tagged mycentos:0.1

查看镜像的变更历史

[root@localhost ~]# docker history cd544b1d0975
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
cd544b1d0975   6 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
9b1f63f5b88c   6 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
56c158222b2f   6 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
4224dc236602   6 minutes ago    /bin/sh -c #(nop)  EXPOSE 80                    0B        
7241dc25315f   6 minutes ago    /bin/sh -c yum -y install net-tools             23.3MB    
8d3cae6b12e4   6 minutes ago    /bin/sh -c yum -y install vim                   58MB      
ad9c6232f124   10 minutes ago   /bin/sh -c #(nop) WORKDIR /usr/local            0B        
a4ab64bac79f   10 minutes ago   /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B        
cab126eb88eb   10 minutes ago   /bin/sh -c #(nop)  MAINTAINER andy<935917439…   0B        
300e315adb2f   4 weeks ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      4 weeks ago      /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      4 weeks ago      /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7…   209MB    

我们平时拿到一个镜像,可以研究一下她是怎么做的

CMD 和 ENTRYPOINT区别

CMD             # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可以被替代
ENTRYPOINT      # 指定这个容器启动的时候要运行的命令,可以追加命令

测试 CMD

# 构建镜像
[root@localhost dockerfile]# docker build -f centos-test -t centos-test:0.1 .

# run运行 , 发现我们的ls -a 命令生效
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM centos
 ---> 300e315adb2f
Step 2/2 : CMD ["ls","-a"]
 ---> Running in d851535e5308
Removing intermediate container d851535e5308
 ---> 989c713f99f7
Successfully built 989c713f99f7
Successfully tagged centos-test:0.1
[root@localhost dockerfile]# docker run centos-test:0.1
.
..
.dockerenv
bin
dev
....
var
# 项追加一个命令 -l    ls -al
[root@localhost dockerfile]# docker run centos-test:0.1 -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.

#cmd的清理下 -l 替换了CMD["ls","-a"]命令,-l 不是命令才报错

测试 ENTRYPOINT

[root@localhost dockerfile]# docker run centos-test:0.1 -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.
[root@localhost dockerfile]# vim centos-test 
[root@localhost dockerfile]# docker build -f centos-test -t centos-test:0.2 .
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM centos
 ---> 300e315adb2f
Step 2/2 : ENTRYPOINT ["ls","-a"]
 ---> Running in bf83c407087e
Removing intermediate container bf83c407087e
 ---> 8440c08af5bb
Successfully built 8440c08af5bb
Successfully tagged centos-test:0.2

# 我们的追加命令,是直接拼接在我们的 ENTRYPOINT 命令的后面
[root@localhost dockerfile]# docker run centos-test:0.2
.
..
.dockerenv
bin
dev
etc
...
var
[root@localhost dockerfile]# docker run centos-test:0.2 -l
total 0
drwxr-xr-x.   1 root root   6 Jan  6 07:06 .
drwxr-xr-x.   1 root root   6 Jan  6 07:06 ..
-rwxr-xr-x.   1 root root   0 Jan  6 07:06 .dockerenv
lrwxrwxrwx.   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x.   5 root root 340 Jan  6 07:06 dev
drwxr-xr-x.   1 root root  66 Jan  6 07:06 etc
...
drwxr-xr-x.  20 root root 262 Dec  4 17:37 var

Dockerfile中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果

实战:Tomcat镜像

1、准备镜像文件 tomcat压缩包,jdk的压缩包

2、编写Dockerfile文件,官方命名Dockerfile, build 会自动寻找这个文件,就不需要 -f 指定了

FROM centos
MAINTAINER andy<935917439@qq.com>

COPY readme.txt /usr/local/readme.txt

ADD jdk-8u144-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.61.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_144
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.61
ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.61
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-8.5.61/bin/startup.sh && tail -F /url/local/apache-tomcat-8.5.61/bin/logs/catalina.out

3、构建镜像

# docker build -t diytomcat .

4、启动镜像

docker run -d -p 9090:8080 --name yangfutomcat -v /home/flamingyouth/soft/tomcat/test:/usr/local/apache-tomcat-8.5.61/webapps/test -v /home/flamingyouth/soft/tomcat/tomcatlogs/:/usr/local/apache-tomcat-8.5.61/logs diytomcat     

5、访问测试

http://192.168.3.18:9998

6、发布项目(由于做了卷挂载,我们直接在本地编写项目就可以发布了)

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">

  <display-name>Tomcat Documentation</display-name>
  <description>
     Tomcat Documentation.
  </description>
</web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
Hello World!<br/>
<%
out.println("你的 IP 地址 " + request.getRemoteAddr());
%>
</body>
</html>

发现:项目部署成功,可以直接访问

我们以后开发的步骤:需要掌握Dockerfile的编写!我们之后的一切都是使用docker镜像来发布运行

发布自己的镜像

DockerHub

  1. 地址 https://hub.docker.com/ 注册自己的账号

  2. 确定这个账号可以登录

  3. 在我们服务器上提交自己的镜像

[root@rocketmq-nameserver2 WEB-INF]# docker login --help

Usage:  docker login [OPTIONS] [SERVER]

Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.

Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username

[root@rocketmq-nameserver2 WEB-INF]# docker login -u flamingyouth
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

4、登陆完毕后提交镜像,就是一步 docker push

# push自己的镜像到服务器上
[root@rocketmq-nameserver2 soft]# docker push diytomcat
Using default tag: latest
The push refers to repository [docker.io/library/diytomcat]
97b2c47cba0a: Preparing 
b5d7ec691879: Preparing 
424509e86482: Preparing 
c965c79abae3: Preparing 
2653d992f4ef: Preparing 
denied: requested access to the resource is denied # 拒绝

# push镜像的问题
[root@rocketmq-nameserver2 soft]# docker push flamingyouth/diytomcat:1.0
The push refers to repository [docker.io/flamingyouth/diytomcat]
An image does not exist locally with the tag: flamingyouth/diytomcat

# 解决,增加一个 tag
[root@rocketmq-nameserver2 soft]# docker tag 339a12b89473 flamingyouth/diytomcat:1.0

# docker 成功 push
[root@rocketmq-nameserver2 soft]# docker push flamingyouth/diytomcat:1.0
The push refers to repository [docker.io/flamingyouth/diytomcat]
97b2c47cba0a: Pushed 
b5d7ec691879: Pushed 
424509e86482: Pushed 
c965c79abae3: Pushed 
2653d992f4ef: Pushed 
1.0: digest: sha256:562e3024de1459efb78271842579d95d0bf28251b3e208af8e9f32bfe59c2700 size: 1373

提交的时候也是按照镜像的层级来进行提交的

阿里云镜像服务

  1. 登录阿里云

  2. 找到容器镜像服务

  3. 创建命名空间

  4. 创建镜像空间

  5. 浏览阿里云

小结

Docker网络

理解Docker0

测试

三个网络

# 问题:docker 是如何处理容器网络访问的?

# [root@rocketmq-nameserver2 ~]# docker run -d -p --name tomcat01 tomcat
[root@rocketmq-nameserver2 ~]# docker exec -it 91ed759e7732 /bin/bash

# 查看容器的内部网络地址 ip addr ,发现容器启动的时候会得到一个 eth0@if27 ip 地址,docker分配到
[root@91ed759e7732 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
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

# 思考 linux 能不能 ping 通容器内部
[root@rocketmq-nameserver2 ~]# 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.105 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.040 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.041 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.069 ms
64 bytes from 172.17.0.3: icmp_seq=5 ttl=64 time=0.040 ms

# linux 可以ping 通 docker 容器内部

原理

1、我们每启动一个docker容器,docker 就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术

2、测试ip addr(外面)

[root@rocketmq-nameserver2 ~]# 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
.....

27: veth4284a7f@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 2e:f1:01:0f:35:ba brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::2cf1:1ff:fe0f:35ba/64 scope link 
       valid_lft forever preferred_lft forever

再次测试ip addr(容器内)

[root@91ed759e7732 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
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# 我们发现这个容器带来网卡,都是一对对的
# evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用 evth-pair 技术

3、测试两个容器是否可以相互ping通

# 结论:容器和容器之间是可以相互ping通的

网络模型:

结论:tomcat01 和 tomcat02 是公用的一个路由器 , docker0

所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用IP

小结

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker0

Docker 中的所有的网络接口都是虚拟的,虚拟的转发效率高(内网传递文件)

只要容器删除,对应网桥一对就没了

思考一个场景,我们编写了一个微服务,database url = ip , 项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可用名字来进行访问容器?

[root@rocketmq-nameserver2 ~]# docker exec -it yangfutomcat ping hungry_perlman
ping: hungry_perlman: Name or service not known

# 如何可以解决呢?
# 通过--link 既可以解决了网络连通问题
[root@rocketmq-nameserver2 ~]# docker exec -it tomcat ping yangfutomcat
PING yangfutomcat (172.17.0.3) 56(84) bytes of data.
64 bytes from yangfutomcat (172.17.0.3): icmp_seq=1 ttl=64 time=0.297 ms
64 bytes from yangfutomcat (172.17.0.3): icmp_seq=2 ttl=64 time=0.105 ms
64 bytes from yangfutomcat (172.17.0.3): icmp_seq=3 ttl=64 time=0.086 ms
# 反向可以ping通吗?
[root@rocketmq-nameserver2 ~]# docker exec -it yangfutomcat ping tomcat
ping: tomcat: Name or service not known

探究:inspect

其实这个tomcat03就是在本地配置了tomcat02的配置?

查看 hosts 配置, 在这里原理发现
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3  tomcat02 91ed759e7732
172.17.0.4  e10ee272252e

本质探究:--link就是我们在hosts配置中增加了一个172.17.0.3 tomcat02 91ed759e7732

目前dokcer已经不建议使用 --likn 了!这种方法太笨了

自定义网络!不适合docker0

docker0问题:它不支持容器名连接访问

自定义网络

查看所有的docker 网络

网络模式

bridge : 桥接 docker(默认,自己搭建也使用桥接)

none : 不配置网络

host : 和宿主机共享网络

comtainer : 容器网络连通(用的少,局限性大)

测试

# 我们直接启动的命令 --net bridge, 而这个就是我们的docker0
docker run -d -P --name tomcat01 tamcat
docker run -d -P --name tomcat01 --net bridge tamcat

# docker0特点:默认,域名不能访问,--link可以打通

# 我们自定义一个网络
# --driver bridge   桥接模式
# --subnet 192.168.0.0/16  子网地址 192.168.0.2 ---- 192.168.255.255
# --gateway 192.168.0.1 网关地址
[root@rocketmq-nameserver2 ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
fc799d19ddbfcd721bf00a1cb47d4f20fb1cd2578d69cd371c7f18a169b25ae6
[root@rocketmq-nameserver2 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
6463312dfabb   bridge    bridge    local
de0b45f94c2c   host      host      local
fc799d19ddbf   mynet     bridge    local
e048e6b8ddef   none      null      local

查看网络

[root@rocketmq-nameserver2 ~]# docker run -d -P --name tomcat01 --net mynet tomcat
WARNING: IPv4 forwarding is disabled. Networking will not work.
1dac1d57d5283e318d5ecd28ab8de91d5a822ff2937f2da25f5484b7e8d094c4
[root@rocketmq-nameserver2 ~]# docker run -d -P --name tomcat02 --net mynet tomcat
WARNING: IPv4 forwarding is disabled. Networking will not work.
d3922d8e504a4f986a63af6e41824f655243116ff2686e7b5c23eb18a8d1b788
[root@rocketmq-nameserver2 ~]# docker network inspect mynet 
[
    {
        "Name": "mynet",
        "Id": "fc799d19ddbfcd721bf00a1cb47d4f20fb1cd2578d69cd371c7f18a169b25ae6",
        "Created": "2021-01-08T13:15:17.882808087+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1dac1d57d5283e318d5ecd28ab8de91d5a822ff2937f2da25f5484b7e8d094c4": {
                "Name": "tomcat01",
                "EndpointID": "80d9d6c30a88dc92418df4645f5f1207eb5424cb585f6b9e434c7b7944e47fcb",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "d3922d8e504a4f986a63af6e41824f655243116ff2686e7b5c23eb18a8d1b788": {
                "Name": "tomcat02",
                "EndpointID": "a6ae73a7e99a3dcac133408b9f37086de43378ed64a6823f230cb38c0280126e",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# 再次测试ping连接
[root@rocketmq-nameserver2 ~]# docker exec -it tomcat01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.151 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.081 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.083 ms
# 现在不使用 --link 也可以 ping 名字
[root@rocketmq-nameserver2 ~]# docker exec -it tomcat01 ping tomcat02
PING tomcat02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.068 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.105 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.095 ms

我们自定义的网络 docker 都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络

好处

redis - 不同的集群使用不同的网络,保证集群是安全和健康的

mysql - 不同的集群使用不同的网络,保证集群是安全和健康的

网络连通

# 核心
connect     Connect a container to a network
# 测试打通 tomcat03 - mynet
[root@rocketmq-nameserver2 ~]# docker network connect mynet tomcat03
# 连通之后就是将 tomcat03 放到了 mynet 网络下
[root@rocketmq-nameserver2 ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "fc799d19ddbfcd721bf00a1cb47d4f20fb1cd2578d69cd371c7f18a169b25ae6",
        "Created": "2021-01-08T13:15:17.882808087+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1dac1d57d5283e318d5ecd28ab8de91d5a822ff2937f2da25f5484b7e8d094c4": {
                "Name": "tomcat01",
                "EndpointID": "80d9d6c30a88dc92418df4645f5f1207eb5424cb585f6b9e434c7b7944e47fcb",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "c8d76c29c384a5c5063a970e470d9a681f16236b3823a034892811459ef6777b": {
                "Name": "tomcat03",
                "EndpointID": "da8567ad238353c5f8e3cdbeed0fd2776cc4f0a6ffa074ad8af354ca72b16700",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            },
            "d3922d8e504a4f986a63af6e41824f655243116ff2686e7b5c23eb18a8d1b788": {
                "Name": "tomcat02",
                "EndpointID": "a6ae73a7e99a3dcac133408b9f37086de43378ed64a6823f230cb38c0280126e",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
# 一个容器两个ip地址
# 例如:阿里云服务器,一个内网ip 一个外网ip

# 01 连通
[root@rocketmq-nameserver2 ~]# docker exec -it tomcat01 ping tomcat03
PING tomcat03 (192.168.0.4) 56(84) bytes of data.
64 bytes from tomcat03.mynet (192.168.0.4): icmp_seq=1 ttl=64 time=0.198 ms
64 bytes from tomcat03.mynet (192.168.0.4): icmp_seq=2 ttl=64 time=0.109 ms
64 bytes from tomcat03.mynet (192.168.0.4): icmp_seq=3 ttl=64 time=0.080 ms

# 02 是依旧打不通的
[root@rocketmq-nameserver2 ~]# docker exec -it tomcat01 ping tomcat04
ping: tomcat04: Temporary failure in name resolution

结论:假设要跨网络操作别人,就需要使用docker network connect 连通

实战:部署Redis集群

# 创建网卡
docker network create redis --subnet 172.38.0.0/2+

# 通过脚本创建六个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

for port in $(seq 1 6); \
do \
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \

#  创建集群配置
/data # redis-cli --cluster create 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 172.38.0.11: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.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.11:6379 to 172.38.0.13:6379
Adding replica 172.38.0.15:6379 to 172.38.0.14:6379
M: f3262337926635ae969ac26df93c5c9bcac96eeb 172.38.0.12:6379
   slots:[0-5460] (5461 slots) master
M: 97a7ff7d4c4e9df7ddc496770266835d0921eeaf 172.38.0.13:6379
   slots:[5461-10922] (5462 slots) master
M: 2e8d580e90f4d85f0aeff67444d4d85fa0587e90 172.38.0.14:6379
   slots:[10923-16383] (5461 slots) master
S: f2804bd2d07077648dbea87914177fd1766a7056 172.38.0.15:6379
   replicates 2e8d580e90f4d85f0aeff67444d4d85fa0587e90
S: 38228eb3addbc742c46ebe61ba81f299ba8ffdbe 172.38.0.16:6379
   replicates f3262337926635ae969ac26df93c5c9bcac96eeb
S: ee8db8e737a9e7d827b23fb07869fc72cbf18e7a 172.38.0.11:6379
   replicates 97a7ff7d4c4e9df7ddc496770266835d0921eeaf
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.12:6379)
M: f3262337926635ae969ac26df93c5c9bcac96eeb 172.38.0.12:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: ee8db8e737a9e7d827b23fb07869fc72cbf18e7a 172.38.0.11:6379
   slots: (0 slots) slave
   replicates 97a7ff7d4c4e9df7ddc496770266835d0921eeaf
M: 2e8d580e90f4d85f0aeff67444d4d85fa0587e90 172.38.0.14:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 38228eb3addbc742c46ebe61ba81f299ba8ffdbe 172.38.0.16:6379
   slots: (0 slots) slave
   replicates f3262337926635ae969ac26df93c5c9bcac96eeb
S: f2804bd2d07077648dbea87914177fd1766a7056 172.38.0.15:6379
   slots: (0 slots) slave
   replicates 2e8d580e90f4d85f0aeff67444d4d85fa0587e90
M: 97a7ff7d4c4e9df7ddc496770266835d0921eeaf 172.38.0.13:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

docker搭建redis集群完成

172.38.0.15:6379> cluster nodes
f2804bd2d07077648dbea87914177fd1766a7056 172.38.0.15:6379@16379 myself,master - 0 1610089016000 7 connected 10923-16383
97a7ff7d4c4e9df7ddc496770266835d0921eeaf 172.38.0.13:6379@16379 master - 0 1610089017034 2 connected 5461-10922
38228eb3addbc742c46ebe61ba81f299ba8ffdbe 172.38.0.16:6379@16379 slave f3262337926635ae969ac26df93c5c9bcac96eeb 0 1610089016530 5 connected
2e8d580e90f4d85f0aeff67444d4d85fa0587e90 172.38.0.14:6379@16379 master,fail - 1610088806354 1610088805141 3 connected
ee8db8e737a9e7d827b23fb07869fc72cbf18e7a 172.38.0.11:6379@16379 slave 97a7ff7d4c4e9df7ddc496770266835d0921eeaf 0 1610089016000 6 connected
f3262337926635ae969ac26df93c5c9bcac96eeb 172.38.0.12:6379@16379 master - 0 1610089016933 1 connected 0-5460

SpringBoot微服务打包Docker镜像

  1. 构架springboot项目

  2. 打包应用

  3. 编写dockerfile

    FROM java:8
    
    COPY *.jar /app.jar
    
    CMD ["--server.[port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java","-jar","/app.jar"]
  4. 构建镜像

    [root@rocketmq-nameserver2 idea]# ls
    demo-0.0.1-SNAPSHOT.jar  Dockerfile
    [root@rocketmq-nameserver2 idea]# docker build -t idea .
    Sending build context to Docker daemon     17MB
    Step 1/5 : FROM java:8
    ....
    Successfully built 78150404575e
    Successfully tagged idea:latest
  5. 发布运行

    [root@rocketmq-nameserver2 idea]# docker images
    REPOSITORY                                               TAG                IMAGE ID       CREATED         SIZE
    idea                                                     latest             78150404575e   4 seconds ago   660MB
    [root@rocketmq-nameserver2 idea]# docker run -d -P --name SpringBoot-web idea
    WARNING: IPv4 forwarding is disabled. Networking will not work.
    e05da3bb73e029168915f5197166468d4ebbc824eb9d9bf7c10aedebe5327f84
    [root@rocketmq-nameserver2 idea]# docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS          PORTS                     NAMES
    e05da3bb73e0   idea      "java -jar /app.jar …"   About a minute ago   Up 58 seconds   0.0.0.0:49159->8080/tcp   SpringBoot-web

以后我们使用了Docker之后,给别人交付的就是一个镜像即可

1

评论区