1. 程式人生 > >Docker容器學習梳理--容器登陸方法梳理(attach、exec、nsenter)

Docker容器學習梳理--容器登陸方法梳理(attach、exec、nsenter)

config .org app ron 簡單 dha entos ava dir

對於運行在後臺的Docker容器,我們運維人員時常是有登陸進去的需求。登陸Docker容器的方式:

1)使用ssh登陸容器。這種方法需要在容器中啟動sshd,存在開銷和攻擊面增大的問題。同時也違反了Docker所倡導的一個容器一個進程的原則。 參考Docker容器學習梳理--SSH方式登陸容器

2)使用自帶命令docker attach登陸容器。命令格式:docker attach container_id。不過docker attach存在的問題是:當多個窗口同時attach到同一個容器時,所有的窗口都會同步的顯示,假如其中的一個窗口發生阻塞時,其它的窗口也會阻塞,docker attach命令可以說是最不方便的進入後臺docker容器的方法。

3)使用自帶命令docker exec登陸容器。命令格式:docker exec -ti container_id /bin/bash。docker exec和docker attach是Docker的原生方法,大多數情況下就使用這兩種命令登陸容器。docker exec命令是在docker1.3之後出現的,比docker attach命令更加方便!兩者之間的區別:

1.Docker attach必須是登陸到一個已經運行的容器裏。需要註意的是如果從這個容器中exit退出的話,就會導致容器停止!!這是極其不方便的!
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"              4 days ago          Up About an hour    0.0.0.0:8888->8080/tcp          tomcat
[root@localhost ~]# docker attach tomcat
[root@2faf24118766 /]# exit          //按住ctrl+d退出當前窗口
[root@localhost ~]# docker ps        //發現該容器也停止了!!
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                           NAMES
 
2.docker exec登陸容器,註意有兩個參數:-t和-i,這兩個參數很重要!
 
1)如果只用-i時,由於沒有分配偽終端,看起來像pipe執行一樣。但是執行結果、命令返回值都可以正確獲取。
這種方式可以理解為:在運行的容器上執行新進程!即在宿主機上執行容器裏的命令並查看到命令結果!這很方便的~但是僅僅使用-i參數無法直接登陸到容器內!
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"              4 days ago          Up About a minute   0.0.0.0:8888->8080/tcp          tomcat
 
[root@localhost ~]# docker exec -i tomcat date
Sat Apr  1 06:53:46 UTC 2017
[root@localhost ~]# docker exec -i tomcat uptime
 06:54:44 up 163 days, 23:28,  0 users,  load average: 0.00, 0.01, 0.05
[root@localhost ~]# docker exec -i tomcat /usr/local/tomcat7/bin/startup.sh
Tomcat started.
 
2)如果只使用-t參數,則可以看到一個console窗口,可以在宿主機上執行容器裏的命令並查看到命令結果,但是這種方式登陸到容器內執行的命令是沒有結果信息輸出的!
[root@localhost ~]# docker exec -t tomcat uptime
 07:02:38 up 163 days, 23:36,  0 users,  load average: 0.00, 0.02, 0.05
[root@localhost ~]# docker exec -t tomcat pwd
/
[root@localhost ~]# docker exec -t tomcat /bin/bash   //註意,使用-t參數登陸容器,退出當前窗口用的是ctrl+c而不是ctrl+d;而下面使用-ti參數,退出當前窗口使用ctrl+d
[root@2faf24118766 /]# uptime      //僅僅使用-t參數登陸容器內,發現執行命令後,沒有結果輸出!
 
3)使用-it時,則和我們平常操作console界面類似,而且不會像attach方式因為退出而導致 整個容器退出。 這種方式可以替代ssh或者nsenter方式,在容器內進行操作。
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"              4 days ago          Up About a minute   0.0.0.0:8888->8080/tcp          tomcat
 
[root@localhost ~]# docker exec -t tomcat /bin/bash
[root@2faf24118766 /]# exit          //按住ctrl+d退出當前窗口
[root@localhost ~]# docker ps       //發現容器還在,並沒有因為上面的窗口退出而停止容器!
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"              4 days ago          Up About a minute   0.0.0.0:8888->8080/tcp          tomcat
 
在使用docker exec登陸容器或執行容器中的命令時,最好都帶上-t和-i參數
[root@localhost ~]# docker exec -ti  tomcat yum install -y net-tools
[root@localhost ~]# docker exec -t -i  tomcat ifconfig
 
----------------------------------------------
除此之外,docker exec還可以使用-d參數,表示在後臺執行一個進程。如果一個命令需要長時間進程,使用-d參數會很快返回,程序在後臺運行。
這一般用於容器中的命令長時間執行的情況下。
[root@localhost ~]# docker exec -d tomcat yum install -y mysql

4)對於一個已關閉的容器的登陸,可以使用"docker start -ai container"登陸。這種其實就是先啟動容器,然後再進入容器內。

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"              4 days ago          Up 9 minutes        0.0.0.0:8888->8080/tcp          tomcat
 
[root@localhost ~]# docker stop tomcat
tomcat
[root@localhost ~]# docker start -i tomcat        //參數用-i或-a -i兩個參數都可以
[root@2faf24118766 /]# exit       //不過這種方式,在退出當前窗口後,也會導致容器停止!
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                           NAMES

5)使用外部工具nsenter登陸容器,該工具和docker exec命令的效果差不多。使用nsenter或docker exec,都可以在容器的上下文(嚴格地說,是命名空間)中運行任意命令!

1.安裝nsenter
nsenter 工具在util-linux包2.23版本後包含。如果系統中 util-linux 包沒有該命令,可以按照下面的方法從源碼安裝。
[root@localhost ~]# cd /usr/local/src/
[root@localhost src]# curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
[root@localhost util-linux-2.24]# ./configure  --without-ncurses
[root@localhost util-linux-2.24]# make nsenter && cp nsenter /usr/local/bin
   
2.nsenter使用
在使用nsenter命令之前需要獲取到docker容器的進程,然後再使用nsenter工具進去到docker容器中,具體的使用方法如下:
# docker inspect -f {{.State.Pid}} 容器名或者容器id   //每一個容器都有.State.Pid,所以這個命令除了容器的id需要我們根據docker ps -a去查找,其他的全部為固定的格式
# nsenter --target 上面查到的進程id --mount --uts --ipc --net --pid    // 輸入該命令便進入到容器中
   
解釋nsenter指令中進程id之後的參數的含義:
--mount參數是進去到mount namespace中
--uts參數是進入到uts namespace中
--ipc參數是進入到System V IPC namaspace中
--net參數是進入到network namespace中
--pid參數是進入到pid namespace中
--user參數是進入到user namespace中
   
在Linux中,最愛簡單的查看指定命令參數含義的辦法是在終端中輸入:
# nsenter --help  #會回顯所有與該命令有關的參數
# man nsenter  #能查到更加詳細的使用示例和參數說明
 
[root@localhost ~]# nsenter --help
 
Usage:
 nsenter [options] <program> [args...]
 
Options:
 -t, --target <pid>     target process to get namespaces from
 -m, --mount [=<file>]  enter mount namespace
 -u, --uts   [=<file>]  enter UTS namespace (hostname etc)
 -i, --ipc   [=<file>]  enter System V IPC namespace
 -n, --net   [=<file>]  enter network namespace
 -p, --pid   [=<file>]  enter pid namespace
 -U, --user  [=<file>]  enter user namespace
 -S, --setuid <uid>     set uid in user namespace
 -G, --setgid <gid>     set gid in user namespace
 -r, --root  [=<dir>]   set the root directory
 -w, --wd    [=<dir>]   set the working directory
 -F, --no-fork          do not fork before exec'ing <program>
 
 -h, --help     display this help and exit
 -V, --version  output version information and exit
   
實例如下:
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"         4 days ago          Up 23 minutes       0.0.0.0:8888->8080/tcp          tomcat
  
[root@localhost ~]# docker inspect -f {{.State.Pid}} tomcat
31356
[root@localhost ~]# nsenter --target 31356 --mount --uts --ipc --net --pid
[root@2faf24118766 /]# exit     //退出當前窗口,容器不會停止。
logout
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"         4 days ago          Up 27 minutes       0.0.0.0:8888->8080/tcp          tomcat
 
或者:
[root@localhost ~]# nsenter -m -u -n -i -p -t 31356 bash
[root@2faf24118766 /]#
 
[root@localhost ~]# nsenter -m -u -n -i -p -t 31356 uptime
 10:17:08 up 164 days,  2:50,  0 users,  load average: 0.00, 0.01, 0.05
[root@localhost ~]# nsenter -m -u -n -i -p -t 31356 free -m
              total        used        free      shared  buff/cache   available
Mem:       65759080      591904    58142584      419724     7024592    64301784
Swap:       2097148           0     2097148

6)更簡單的是,強烈推薦下載.bashrc_docker,並將內容放到.bashrc中。這個文件中定義了很多方便使用Docker的命令,比如docker-pid可以獲取某個容器的 PID;而 docker-enter 可以進入容器或直接在容器內執行命令!

[root@localhost ~]# wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker
[root@localhost ~]# echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc
  
舉例:
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"         4 days ago          Up 37 minutes       0.0.0.0:8888->8080/tcp          tomcat
  
1)直接使用docker-enter命令進入容器,非常方便!
[root@localhost ~]# docker-enter tomcat   
Last login: Sat Apr  1 10:07:21 UTC 2017
[root@2faf24118766 ~]# exit
logout
[root@localhost ~]# docker ps       //退出登陸窗口後,容器還在!
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                           NAMES
2faf24118766        192.168.1.23:5000/tomcat7   "/bin/bash"         4 days ago          Up 39 minutes       0.0.0.0:8888->8080/tcp          tomcat
  
以在容器的上下文中運行任意命令!即在宿主機上執行容器裏的命令
[root@localhost ~]# docker-enter tomcat uptime 
 10:11:05 up 164 days,  2:44,  0 users,  load average: 0.05, 0.03, 0.05
 
-----------------
註意:在宿主機上使用docker-enter命令執行容器中的命令時,最好後面加上--符號,這樣容器裏的所有存在的命令都可以正常執行。
[root@localhost ~]# docker-enter tomcat -- uptime
 10:49:08 up 164 days,  3:22,  0 users,  load average: 0.02, 0.02, 0.05
 
[root@localhost ~]# docker-enter tomcat -- df -h        //這條命令如果去掉--符號,就不會順利執行容器中的df -h命令了
Filesystem                                                                                           Size  Used Avail Use% Mounted on
/dev/mapper/docker-253:0-268868570-9ae66abb2dc10d8d1c4327a41bab376c3684f1c49af91cf6ca2b3a3d58a1d07f   10G  584M  9.5G   6% /
tmpfs                                                                                                 32G     0   32G   0% /dev
tmpfs                                                                                                 32G     0   32G   0% /sys/fs/cgroup
/dev/mapper/centos-root                                                                              150G  6.4G  144G   5% /etc/hosts
shm       
 
[root@localhost ~]# docker-enter tomcat -- cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
  
2)使用docker-pid獲取容器PID
[root@localhost ~]# echo $(docker-pid tomcat)
31356
[root@localhost ~]# nsenter --target 31356 --mount --uts --ipc --net --pid
[root@2faf24118766 /]#


Docker容器學習梳理--容器登陸方法梳理(attach、exec、nsenter)