docker容器添加對外映射端口


一般在運行容器時,我們都會通過參數 -p(使用大寫的-P參數則會隨機選擇宿主機的一個端口進行映射)來指定宿主機和容器端口的映射,例如

docker run -it -d --name [container-name] -p 8088:80 [image-name]

這里是將容器內的80端口映射到宿主機的8088端口

參數說明

  • -d 表示后台運行容器
  • -t 為docker分配一個偽終端並綁定到容器的標准輸入上
  • -i 是讓容器的標准輸入保持打開狀態
  • -p 指定映射端口

在運行容器時指定映射端口運行后,如果想要添加新的端口映射,可以使用以下兩種方式:

方式一:將現有的容器打包成鏡像,然后在使用新的鏡像運行容器時重新指定要映射的端口

大概過程如下:

先停止現有容器

docker stop container-name

將容器commit成為一個鏡像

docker commit container-name  new-image-name

用新鏡像運行容器

docker run -it -d --name container-name -p p1:p1 -p p2:p2 new-image-name

方式二:修改要端口映射的容器的配置文件

查看容器信息

docker ps -a

 查看容器的端口映射情況,在容器外執行:

docker port 容器ID 或者 docker port 容器名稱

查找要修改容器的容器Id

docker inspect f244 |grep Id

進到/var/lib/docker/containers 目錄下找到與 Id 相同的目錄,修改 hostconfig.json 和 config.v2.json文件

若該容器還在運行,先停掉

docker stop 容器ID

停掉docker服務

systemctl stop docker

修改hostconfig.json如下,添加端口綁定"9003/tcp": [{"HostIp": "","HostPort": "9003"}],表示綁定端口9003

修改config.v2.json在ExposedPorts中加上要暴露的端口,即9003

改完之后保存啟動docker

systemctl start docker

之后可以再次查看添加的端口是否已映射綁定上

附注:

1、將容器打包成鏡像命令:

docker commit -a "king西陽" -m "a new image" [容器名稱或id] [打包的鏡像名稱]:[標簽]

常用OPTIONS說明:

  • -a :提交的鏡像作者
  • -c :使用Dockerfile指令來創建鏡像
  • -m :提交時的說明文字
  • -p :在commit時,將容器暫停

2、查看宿主機端口是否和容器內端口映射成功,在容器外執行

netstat -an |grep 宿主機的映射端口

如果有進程存在則表示有映射

方法三 

原文地址:https://www.jb51.net/article/142462.htm

創建兩個容器並進行了端口映射,結果如圖所示:

假如,我start一個容器,其內部IP為172.17.0.5,並在容器內部啟動了80端口。

FORWARD規則鏈我們不用管它,docker已經幫我們寫好了,我們只需要關心NAT中的幾條鏈即可。

查看NAT表中的PREROUTING鏈

從上面可以看出,iptables將滿足條件的數據都轉發到了DOCKER鏈上去了。

查看NAT表中的DOCKER鏈

仿照上圖,我們添加一條自己的映射規則,將宿主的8082端口映射到172.17.0.5的80端口上去,規則如下:

1
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8082 -j DNAT --to-destination 172.17.0.5:80

查看NAT表中的POSTROUTING鏈

仿照上圖中的規則,書寫的規則如下:

1
iptables -t nat -A POSTROUTING -s 172.17.0.5/32 -d 172.17.0.5/32 -p tcp -m tcp --dport 80 -j MASQUERADE

查看FILTER表中的DOCKER鏈

仿照上圖書寫規則如下:

1
iptables -t filter -A DOCKER -d 172.17.0.5/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT

結果

雖然IP為172.17.0.5的容器沒有開啟端口映射,如下圖所示:

但我們依然能夠通過訪問宿主機(192.168.78.238)的8082端口來訪問172.17.0.5的80端口,效果如下:

使用此方法有一個缺點,不能訪問localhost:8082,也就是說如果想對localhost也進行轉發,需要進行額外的配置。

Mac 動態端口

動態添加端口:https://www.jianshu.com/p/6aefed2be1c7

HOW TO LOGIN THE VM OF DOCKER DESKTOP FOR MAC

原文地址:https://www.dbform.com/2019/07/08/how-to-login-the-vm-of-docker-desktop-for-mac/

DOCKER FOR MACOS的宿主機在哪里?

我們之前在MOVING MYSQL GROUP REPLICATION INSTANCES TO DOCKER CONTAINER ON MACOS這篇文章中提過在Docker for macOS中,容器的宿主機並不是macOS本身,而是在macOS中運行的一個虛擬機。虛擬機的路徑可以通過查看Docker Desktop的配置界面獲知。

如果我們想登錄這台虛擬機應該怎么做?

方法一

使用screen命令。實際上在上面那篇文章中我們提到過這個方法。
比如在上圖中我們看到虛擬機的文件路徑是:

/Users/Kamus/Library/Containers/com.docker.docker/Data/vms/0/Docker.raw

進入到這個文件的所在目錄。可以看到tty這個軟鏈接文件。

$ cd /Users/Kamus/Library/Containers/com.docker.docker/Data/vms/0
$ ls -l
total 31067864
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.000005f4
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.00001000
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.00001001
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.0000f3a5
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000003.000005f5
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000003.00000948
-rw-r--r--@ 1 Kamus  staff  63999836160  7  7 12:51 Docker.raw
-rw-r--r--  1 Kamus  staff       215040  7  4 12:22 config.iso
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 connect
lrwxr-xr-x  1 Kamus  staff           17  7  4 12:22 guest.000005f5 -> 00000003.000005f5
lrwxr-xr-x  1 Kamus  staff           17  7  4 12:22 guest.00000948 -> 00000003.00000948
-rw-r--r--  1 Kamus  staff         2303  7  4 12:22 hyperkit.json
-rw-r--r--  1 Kamus  staff            4  7  4 12:22 hyperkit.pid
drwxr-xr-x  2 Kamus  staff           64 11 21  2018 log
-rw-r--r--  1 Kamus  staff           36 11 21  2018 nic1.uuid
lrwxr-xr-x  1 Kamus  staff           12  7  4 12:22 tty -> /dev/ttys000

screen該文件即可連接到虛擬機的輸出窗口中。

$ screen tty

screen之后可能終端界面會懸停,按一下Ctrl+c,即可顯示出已經登錄到了虛擬機中。

linuxkit-025000000001:~# uname -a
Linux linuxkit-025000000001 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux

登出screen界面可以使用Ctrl+a d(同時按住Ctrl和a,然后放開再按下d),重新登入,可以使用screen -r,如果要徹底結束screen,可以使用Ctrl+a k。

方法二

還可以使用更優雅的方式,臨時建一個最小化的debian容器,指定容器運行在pid=host命名空間下,然后該容器運行nsenter命令。如果之前沒有安裝過依賴的debian鏡像,那么會首先自動下載這個鏡像,鏡像很小,只有101MB。

$ docker run -it --rm --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
6f2f362378c5: Pull complete
Digest: sha256:118cf8f3557e1ea766c02f36f05f6ac3e63628427ea8965fb861be904ec35a6f
Status: Downloaded newer image for debian:latest

/ # uname -a
Linux linuxkit-025000000001 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux

如果說覺得101MB的debian鏡像還是太大了,那么可以選擇下載Alpine Linux鏡像,這個鏡像只有5.56MB。

$ docker run -it --rm --privileged --pid=host alpine:edge nsenter -t 1 -m -u -n -i sh

詳細解釋一下這條命令為什么就會登錄進macOS中作為宿主機的VM里面。
–rm表示在退出的時候就自動刪除該容器;
–privileged表示允許該容器訪問宿主機(也就是我們想要登錄的VM)中的各種設備;
–pid=host表示允許容器共享宿主機的進程命名空間(namespace),或者通俗點兒解釋就是允許容器看到宿主機中的各種進程;
這些是docker在啟動容器時候的參數設置,但是僅僅依靠這些參數還無法讓我們直接登錄到宿主機VM中,接下來解釋最主要的nsenter命令。

nsenter是一個小工具允許我們進入一個指定的namespace然后運行指定的命令,ns=namespace,enter=進入。
namespace是容器技術的根基,基本上可以認為namespace就是一組隔離的資源,不同的進程可以看到不同的系統資源這里這里有比較詳細的關於namespace的介紹。
可以從操作系統的/proc/[pid]/ns目錄下一窺全貌。比如我們進入pid=1的ns目錄下。可以看到有一共8種namespace。

# pwd
/proc/1/ns
# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jul  8 12:51 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 net -> net:[4026531889]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 uts -> uts:[4026531838]

接下來我們通過一個例子來直觀的感受一下namespace和nsenter的功能,由於沒有現成的操作系統命令可以修改一個namespace用於演示,所以我們需要先在nbrownuk下載一段c函數源碼,我們演示UTS namespace,這個相對直觀,所以只需要下載invoke_ns3.c即可。
UTS namespace中包含了hostname,我們的演示計划是給一個進程設置一個新的hostname,然后用nsenter進入該進程的namespace查看。

下載完invoke_ns3.c之后,需要編譯。

# gcc -o invoke_ns3 ./invoke_ns3.c
# ls -l
total 28
-rwxr-xr-x 1 root root 71928 Jul  8 13:41 invoke_ns3
-rw-r--r-- 1 root root  4603 Jul  8 13:38 invoke_ns3.c

使用新的hostname啟動一個bash進程,15842是執行invoke_ns3命令的進程,而15843則是bash進程,接下來我們只需要用nsenter進入15843進程驗證一下即可。

# ./invoke_ns3 -vu newhostname bash
Parent: PID of parent is 15842
Parent: PID of child is 15843
 Child: PID of child is 15843
 Child: executing command bash ...
[root@newhostname root]

啟動一個新的終端。可以看到在終端自己的hostname沒有變化的情況下,我們用nsenter進入不同的進程,看到的hostname是不同的,其中15843進程中顯示的就是上面修改過的主機名。

# hostname
ecs-arm-4xlarge
# nsenter -t 1 -u hostname
ecs-arm-4xlarge
# nsenter -t 15843 -u hostname
newhostname

最后解釋一下nsenter命令的選項。回顧一下命令是:nsenter -t 1 -m -u -n -i sh
-t 1: 表示要進入哪個pid,1表示整個操作系統的主進程id
-m: 進入mount namespace,掛載點
-u: 進入UTS namespace,也就是上面我們演示的那個namespace
-n: 進入network namespace,網絡
-i: 進入IPC namespace,進程間通信
sh: 表示運行/bin/sh

到此為止:docker加上–pid=host加上nsenter,就讓我們登錄到了在macOS中作為docker容器宿主機的VM里。

方法三

實際上跟方法二一樣,但是在方法二中,需要下載至少是alpine鏡像這樣的最簡化Linux操作系統,雖然這個鏡像只有5MB多,已經很小了,但是我們還是可以直接下載網絡上其它人提供的單獨的nsenter鏡像,這樣的鏡像更小,大約只有幾百KB。

walkerlee/nsenter鏡像有583KB。

docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n sh

justincormack/nsenter1鏡像更小,只有101KB。

docker run -it --rm --privileged --pid=host justincormack/nsenter1

方法四:會出現亂碼,不推薦

從這里找到:https://i.cnblogs.com/articles?cateId=1271815&page=6

nc -U ~/Library/Containers/com.docker.docker/Data/debug-shell.sock

容器目錄也發生了改變

/var/lib/docker/containers

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM