Docker运行容器端口映射

Posted 是渣渣呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker运行容器端口映射相关的知识,希望对你有一定的参考价值。

大致描述

我发现docker启动容器时(以redis为例),在已经启动了一个-p 6379:6379的redis1容器后,当我们开启第二个redis2容器时,
右边的端口映射既可以写别的我们想要映射的端口(-p 6380:6380 redis2),也可以继续写6379(-p 6380:6379 redis2)!!!

因为众所周知,一个服务只能占用一个端口,但是这里却能映射相同的docker容器的端口号!(所以我很好奇)

详细展示

(注:先测试映射6380的redis2,再换成映射6379的redis2,并且redis1一直是开启的状态)

1* 启动两个redis容器的(redis1配置文件端口为6379,redis2是6380)
首先是映射不同的端口创建两个容器,分别映射6379 和 6380 端口。

[root@zch config]# docker run -d --name redis1 -v /usr/local/docker/redis/config/redis1/redis.conf:/etc/redis.conf -v /usr/local/docker/redis/data:/data -p 6379:6379 redis:6.0.12 redis-server /etc/redis.conf
ffeac01946f1d34115734fb1405a68f5a020e6bb1b0f6100c6dbd257630ffe7a
[root@zch config]# docker run -d --name redis2 -v /usr/local/docker/redis/config/redis2/redis.conf:/etc/redis.conf -v /usr/local/docker/redis/data:/data -p 6380:6380 redis:6.0.12 redis-server /etc/redis.conf
ca58fb27e6f92d12afacebafaa854692f99fab9db4ce8fe66af8304cf8e9fffc
[root@zch config]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ca58fb27e6f9 redis:6.0.12 “docker-entrypoint.s…” 13 seconds ago Up 12 seconds 6379/tcp, 0.0.0.0:6380->6380/tcp redis2
ffeac01946f1 redis:6.0.12 “docker-entrypoint.s…” 52 seconds ago Up 51 seconds 0.0.0.0:6379->6379/tcp redis1

然后进入redis1和redis2的客户端,可以看到都是能成功连接上的
(注:在进入redis2的时候一定要以==-p 6380==进入)

[root@zch config]# docker exec -it redis1 redis-cli 
127.0.0.1:6379> exit
[root@zch config]# docker exec -it redis2 redis-cli -p 6380
127.0.0.1:6380>

2* 接着我将原来的redis2容器删除后,再重新创建redis2,并把右边的映射端口,也改成和redis1一样的6379

docker run -d  --name redis2 -v /usr/local/docker/redis/config/redis2/redis.conf:/etc/redis.conf -v /usr/local/docker/redis/data:/data -p 6380:6379 redis:6.0.12 redis-server /etc/redis.conf

然后再次进入redis2容器,会发现虽然是映射的还是6379,但依然是能够进入到客户端的

[root@zch ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
203a0d3dad1a redis:6.0.12 “docker-entrypoint.s…” 5 hours ago Up 5 minutes 0.0.0.0:6380->6379/tcp redis2
ffeac01946f1 redis:6.0.12 “docker-entrypoint.s…” 15 hours ago Up 3 seconds 0.0.0.0:6379->6379/tcp redis1
[root@zch ~]# docker exec -it redis2 redis-cli -p 6380
127.0.0.1:6380>

但是,注意到docker ps 的时候redis2的PORTS属性只剩下0.0.0.0:6380->6379/tcp

再回看之前映射6380的redis2的PORTS属性:6379/tcp, 0.0.0.0:6380->6380/tcp

可以看到映射内部6380端口的redis2容器PORTS有两个值,并且没有与内部端口6379映射的本机ip

情况分析

我们可以看下pull下来的redis镜像的具体信息

[root@zch config]# docker images
REPOSITORY               TAG                 IMAGE ID       CREATED         SIZE
redis                    6.0.12              090314e0c44c   4 weeks ago     104MB

[root@zch config]# docker inspect 090314e0c44c
[
    
        "Id": "sha256:090314e0c44c58e5faaa379904242657dcb4203e1a6a61413e534e0f40e8bdd5",
        "RepoTags": [
            "redis:6.0.12"
        ],
        "RepoDigests": [
            "redis@sha256:cc4231ed1a6ae4d0a3e0c85c205ba68d0cbcd60c837caca1334b01661eb8b3bb"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-03-13T04:04:30.678552814Z",
        "Container": "c62962de94021537ddd3d2a2cf36c1ee26eec6f374b65c9624fc54675b65beb3",
        "ContainerConfig": 
            "Hostname": "c62962de9402",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": 
                "6379/tcp": 
            ,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.12",
                "REDIS_VERSION=6.0.12",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.0.12.tar.gz",
                "REDIS_DOWNLOAD_SHA=f16ad973d19f80f121e53794d5eb48a997e2c6a85b5be41bb3b66750cc17bf6b"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\\"redis-server\\"]"
            ],
            "Image": "sha256:09a494871c16ded394e132a87f16e105522b63e88c92018a1dddcf21d8b401f3",
            "Volumes": 
                "/data": 
            ,
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": 
        ,
        "DockerVersion": "19.03.12",
        "Author": "",
        "Config": 
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": 
                "6379/tcp": 
            ,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.12",
                "REDIS_VERSION=6.0.12",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.0.12.tar.gz",
                "REDIS_DOWNLOAD_SHA=f16ad973d19f80f121e53794d5eb48a997e2c6a85b5be41bb3b66750cc17bf6b"
            ],
            "Cmd": [
                "redis-server"
            ],
            "Image": "sha256:09a494871c16ded394e132a87f16e105522b63e88c92018a1dddcf21d8b401f3",
            "Volumes": 
                "/data": 
            ,
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null
        ,
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 104291820,
        "VirtualSize": 104291820,
        "GraphDriver": 
            "Data": 
                "LowerDir": "/var/lib/docker/overlay2/6f0cd9ab5a300e71ce8475861a4bc2b76a2826ec0020e787a43d38a5ff2db2ef/diff:/var/lib/docker/overlay2/d70138999bd376d810f4b4f6d1ada4560923317c74609ac467381fd0fc67d50a/diff:/var/lib/docker/overlay2/12991f82bf1068b3191de47ebf9d581f34bcc3a8a8cbdef0f90f052bf65b53e8/diff:/var/lib/docker/overlay2/85b82010fca6b6fa29cc66a3e3df59c1c934a5340e0dcfd023650c23439b2439/diff:/var/lib/docker/overlay2/0ae0ed3fdcd6cbe7a7c6aa491d837653a84e1a55f774a6604df1035c29012c65/diff",
                "MergedDir": "/var/lib/docker/overlay2/83b39cef71e2dc3cd1ff367a3496afcbf68c248afe6cb427a348907fb94cefce/merged",
                "UpperDir": "/var/lib/docker/overlay2/83b39cef71e2dc3cd1ff367a3496afcbf68c248afe6cb427a348907fb94cefce/diff",
                "WorkDir": "/var/lib/docker/overlay2/83b39cef71e2dc3cd1ff367a3496afcbf68c248afe6cb427a348907fb94cefce/work"
            ,
            "Name": "overlay2"
        ,
        "RootFS": 
            "Type": "layers",
            "Layers": [
                "sha256:14a1ca976738392ffa2ae4e54934ba28ab9cb756e924ad9297a4795a4adbfdf6",
                "sha256:a6b7270e6c20bae1d8c5d009171ce7db2e268c3d32e447a2ec4f33b02b256955",
                "sha256:cf2aefb51919d2cf15e3311fec4e187f968e06f168ee610d500e81757b53a3f7",
                "sha256:6e0e8a8a5ad7776289d5929ba624ce58e64600af5995f0208502fc265773a192",
                "sha256:e3059a3a1a65e206c34ae3e24ae6098ede134e7ad4cbd8a5eae4b5feeeb38589",
                "sha256:65508d7d88a08e37d76fad31e959cd15facecee0f1b3513ef4592d1186be077e"
            ]
        ,
        "Metadata": 
            "LastTagTime": "0001-01-01T00:00:00Z"
        
    
]
[root@zch config]# 

注意到这个地方

“ExposedPorts”:
“6379/tcp”:
,

也就是说,当我们pull下来镜像的时候,就已经在docker内部有一个默认的端口号了(一般就是平常各种服务默认的端口号),所以当我们通过镜像创建容器的时候,对于同一个镜像,它所创建的不同容器在docker内部的端口都有一个默认的和镜像一致的端口!

===查看与6380内部端口映射(-p 6380:6380)的redis2的元数据时(docker inspect redis2)发现

“Ports”:
“6379/tcp”: null, //这里的就是docker容器内部默认的端口,只不过我们没有本机地址与它映射,所以为null,也是为何docker ps时有两个值的原因
“6380/tcp”: [

“HostIp”: “0.0.0.0”,
“HostPort”: “6380”

]

===再看与6379内部端口映射(-p 6380:6379)的redis2的元数据时(docker inspect redis2)发现

“Ports”:
“6379/tcp”: [

“HostIp”: “0.0.0.0”,
“HostPort”: “6380”

]

这里就只有容器默认的内部端口6379和本机的映射了

原因分析

所以,为何同一个docker内部端口6379能够与不同的本机端口相映射呢

我猜测是跟docker网络有关。。
所以我们查看一下开启前后的ip
(注:此时两个容器都是与内部端口6379映射的)

[root@zch ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS          PORTS                    NAMES
203a0d3dad1a   redis:6.0.12   "docker-entrypoint.s…"   6 hours ago    Up 49 minutes   0.0.0.0:6380->6379/tcp   redis2
ffeac01946f1   redis:6.0.12   "docker-entrypoint.s…"   16 hours ago   Up 43 minutes   0.0.0.0:6379->6379/tcp   redis1

启动容器前

[root@zch ~]# 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:16:3e:30:ac:de brd ff:ff:ff:ff:ff:ff
    inet 172.24.11.75/18 brd 172.24.63.255 scope global dynamic eth0
       valid_lft 307823829sec preferred_lft 307823829sec
3: br-2ebc59f84c42: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:51:6f:6a:ad brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-2ebc59f84c42
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:42:98:e1:75 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

启动两个映射6379的redis容器后

[root@zch ~]# 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:16:3e:30:ac:de brd ff:ff:ff:ff:ff:ff
    inet 172.24.11.75/18 brd 172.24.63.255 scope global dynamic eth0
       valid_lft 307824120sec preferred_lft 307824120sec
3: br-2ebc59f84c42: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:51:6f:6a:ad brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-2ebc59f84c42
       valid_lft forever preferred_lft forever
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:42:98:e1:75 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
12178: vethb34c46b@if12177: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 5a:35:bb:a2:4e:c1 brd ff:ff:ff:ff:ff:ff link-netnsid 0
12180: vetha7fde8c@if12179: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 72:24:61:31:6a:41 brd ff:ff:ff:ff:ff:ff link-netnsid 1

很明显,最后多了两个ip,也就是说docker为不同的容器分配了不同的ip,所以即便内部端口都是6379,但是由于前面的ip不同,所以自然也就可以共存(我猜的**)

以上是关于Docker运行容器端口映射的主要内容,如果未能解决你的问题,请参考以下文章

教你如何修改运行中的docker容器的端口映射

[转帖]教你如何修改运行中的docker容器的端口映射

如何修改Docker已运行实例的端口映射

docker 容器修改端口

教你如何修改运行中的docker容器的端口映射

如何修改运行中的docker容器的端口映射和挂载目录