docker之container

wadeson發表於2017-10-31
執行一個container的本身就是開啟一個具有獨立namespace的程式
  程式有自己的網路,檔案系統等
docker通過run命令來啟動一個container
執行一個container必須要指定一個image作為初始化的檔案系統
 
對於不存在的image,docker會自動去registry裡面下載對應的image,然後再執行container
 
command標誌的是在container中實際執行的首程式
  作業系統的0號程式
  在centos7系統上是0號程式systemd

  在容器中是/bin/bash程式,也就是本機host上面的一個普通程式
如果image裡面包含了CMD的命令,那麼在啟動container的時候,不需要指定command,否則會使用指定的command來覆蓋image中的CMD
  也就是這裡顯示的COMMAND
  容器的狀態會隨著command的命令執行而改變
 
前臺執行和後臺執行:
  預設的container是在前臺執行的,會繫結command程式的STDIN、STDOUT、STDERR到console上(在console上展現標準輸入、輸出和標準錯誤輸出)
    可以通過-d的選項讓container執行在後臺
  如果是在前臺執行,也可以通過-a {STDIN,STDOUT,STDERR}選擇需要繫結的IO
    只選擇某一個標準展示在console上面
[root@docker ~]# docker run -t -a stdin centos sh -c "while true;do echo hello world;sleep 2;done"                   
b7930a6c5c4cdf2b73e24e26f2a8fd801e9eb11a1e28b0a376d180d3fd2e4d4a
-a stdin:表示只執行了stdin(雖然在前臺執行,但是沒有指定stdout和stderr所以並沒有顯示輸出)可以通過logs來檢視該容器的stdout
[root@docker ~]# docker logs b7930a6c5c4c
hello world
hello world
通過attach命令可以重新attach一個後臺執行的container
  attach可以將後臺執行的切換到前臺

 

在後臺執行的情況下,RUN命令會返回一個容器的uuid,唯一標識container
可以通過docker ps來檢視container的uuid和執行資訊
可以通過指定--name的方式來指定container的名字,name必須唯一
 
inspect:可以檢視container的更多資訊
  通過docker inspect {container_id}來獲取container的更多的資訊,包括網路,volume,實際在host上的程式id等資訊
 
log:
  通過logs命令可以看到container中command所指向程式的STDOUT,STDERR資料
  可以程式排錯(-d後臺執行沒有輸出到console時,檢視)
# docker run -dt --name mycentos centos sh -c "while true;do echo hello world;sleep 2;done" 

環境變數:
  通過-e引數,可以在執行container的時候新增系統環境變數
 
網路設定:
  docker使用bridge橋接的方式來實現container之間以及和外部的通訊
檢視本機host的網路資訊:
[root@docker ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:efff:fe2d:d653  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ef:2d:d6:53  txqueuelen 0  (Ethernet)
        RX packets 1  bytes 76 (76.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 258 (258.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.101.14  netmask 255.255.255.0  broadcast 192.168.101.255
        inet6 fe80::9b70:a5ba:c2d6:d665  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:07:65:c0  txqueuelen 1000  (Ethernet)
        RX packets 375314  bytes 497786475 (474.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 134729  bytes 10091671 (9.6 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)
        RX packets 280  bytes 22624 (22.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 280  bytes 22624 (22.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth9bd4211: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::5045:f6ff:fef6:da10  prefixlen 64  scopeid 0x20<link>
        ether 52:45:f6:f6:da:10  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

vethe1ab8ab: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::e0e5:e5ff:fe58:ddec  prefixlen 64  scopeid 0x20<link>
        ether e2:e5:e5:58:dd:ec  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
上述中veth對應幾個container網路
[root@docker ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
b7930a6c5c4c        centos              "sh -c 'while true..."   5 minutes ago       Up 5 minutes                            stoic_shirley
8179b8e95e31        centos              "sh -c 'while true..."   15 minutes ago      Up 15 minutes                           mycentos
兩張veth網路卡對應兩個container容器(正在執行的)
veth網路都橋接在docker0上(被分配)
 
network架構:
  在host主機上的一個veth{id}的虛擬網路卡和一個container裡面的eth0網路卡一一對映
  host上的bridge負責把資料流在不同的veth間轉發,實現網路的IO
  bridge(docker0)使用RFC1918私有網路,給每一個container分配ip
 
網路設定
  通過--net引數來修改container的網路設定,預設是bridge的方式
  none表示關閉container的網路連線
  host表示使用主機的網路棧,這個時候host主機不會建立veth虛擬網路卡對映到container
    container的網路和主機host的網路在同一網段
# docker run -t --net host saltstack/ubuntu-14.04 sh -c "while true;do ifconfig;sleep 2;done"
container:{name|id},使用另外一個container的網路棧
建立一個容器內的服務,採用本機host的網路ip:
[root@docker ~]# docker run -d --net host saltstack/ubuntu-14.04 python -m SimpleHTTPServer
cd07720586501b298c90067e33fb3c099e6e14d91b9de4327026cc2f06321e08
  -d:建立在後臺執行
  --net host:建立在本機host網路上
  python -m SimpleHTTPServer:在容器內執行的命令(命令程式不終止,容器狀態也不會停止)

可以看出python的程式已經監聽在8000埠上了
  如果不將容器的網路掛在本機host上,那麼如何進行訪問容器的服務呢?
  將本機host的埠同容器內的埠進行對映,詳情看下面埠對映
 
DNS:
  預設使用host的dns設定
  可以通過--dns的引數來指定container自己的dns配置
 
埠對映:
  docker通過採用埠對映的方式,允許把內部container的服務埠暴露到外包
  使用-p引數可以指定需要暴露的container的內部埠,在不指定特定的host的對應埠的情況下,docker會自動分配(49000-49900)在一個host上的埠與其對映
  使用-P引數,表示暴露所有在image中通過EXPOSE指定的埠
[root@docker ~]# docker run -dt -p 8000 saltstack/ubuntu-14.04 python -m SimpleHTTPServer            
f7d04a31f5a2d6220a70c8dd7d78a5819bd722b3baab9e743c6c098533bd96ec
-p 8000:表示將容器內的8000埠暴露了出來,由於這裡沒有明確指定用本機host的哪個埠與之對映,所以這裡採用了隨機埠
-p 8000:80 -p 443:443:對映容器中的多個埠(前面本機host埠,後面container埠)
通過檢視container可以看見隨機埠與之做了對映,然後訪問主機host的這個埠

下面直接啟動一個指定了本機host埠與容器服務埠進行對映:
[root@docker ~]# docker run -dt -p 80:8000 saltstack/ubuntu-14.04 python -m SimpleHTTPServer       
a9c3d1c7b6f4319ee34fe726eb5989b7f20bdf4e75e26ef4d5e734665c7efa75

  python -m SimpleHTTPServer:這個服務開啟的預設埠為8000

使用inspect檢視整個container資訊:

 如果想對映多個埠時:

  -p 8000:80 -p 443:443:對映容器中的多個埠,只需要在後面連線對映本機host埠對應container埠就行
或者直接-P暴露掉container中的所有埠對應host本機的隨機埠
 
volume繫結:
  通過-v引數,可以把host上的一個目錄繫結到container中,允許container對其進行讀寫
[root@docker ~]# mkdir test/wadeson -p
[root@docker ~]# docker run -t -v /root/test:/wadeson saltstack/ubuntu-14.04 sh -c "ls -al /wadeson"
total 0
drwxr-xr-x.  3 root root  21 Oct 27 22:09 .
drwxr-xr-x. 22 root root 257 Oct 27 22:10 ..
drwxr-xr-x.  2 root root   6 Oct 27 22:09 wadeson
  -v /root/test:/wadeson:將本機host下面的test目錄對映到container中下面的wadeson目錄
  由於命令執行完成後,container也就消亡了停止了
docker 資料卷
  -v, --volume list Bind mount a volume
    為container繫結一個資料卷
[root@docker ~]# docker run -it -v /data -h wadeson saltstack/ubuntu-14.04
root@wadeson:/# ls
bin  boot  data  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
  -i:互動模式,直接進入到container容器中
  -t:tty,偽終端
  -h wadeson:指定為container設定hostname
  -v /data:container內的/data為掛載點
檢視data目錄:
root@wadeson:/# ls /data/
root@wadeson:/# 
容器中的data目錄實際也對應這本機host的某一處目錄,使用inspect檢視:
  "Mounts": [
            {
                "Type": "volume",
                "Name": "71025e4f8325fce175e21861a1fe0d089b9a08760778a8c9c517d6391c0dbceb",
                "Source": "/var/lib/docker/volumes/71025e4f8325fce175e21861a1fe0d089b9a08760778a8c9c517d6391c0dbceb/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }

[root@docker _data]# pwd
/var/lib/docker/volumes/71025e4f8325fce175e21861a1fe0d089b9a08760778a8c9c517d6391c0dbceb/_data
[root@docker _data]# ll
total 0
這裡就是本機host的目錄對映到container中的/data目錄
現在在本機host上建立檔案,看看容器中的data目錄是否存在建立的檔案?
[root@docker _data]# touch wadeson.sh
[root@docker _data]# ll
total 0
-rw-r--r--. 1 root root 0 Oct 26 21:46 wadeson.sh
返回容器檢視:
root@wadeson:/# ls /data/
wadeson.sh
於是驗證成功,本機host將某個目錄對映到容器中,當不指定host的源目錄,那麼預設在這裡
 
現在建立一個指定host上一個目錄掛載到容器中:
[root@docker ~]# docker run -it -v /root:/root -h wadeson saltstack/ubuntu-14.04
  將本機host的/root目錄掛載到容器中的/root目錄
root@wadeson:/# ls /root/
anaconda-ks.cfg  docker-ce-17.09.0.ce-1.el7.centos.x86_64.rpm
  在容器中已經成功有了本機host下/root目錄的資料
而預設的掛載點並沒有:
[root@docker volumes]# ll
total 24
drwxr-xr-x. 3 root root    19 Oct 26 21:46 71025e4f8325fce175e21861a1fe0d089b9a08760778a8c9c517d6391c0dbceb
-rw-------. 1 root root 32768 Oct 26 21:39 metadata.db
如果需要將目錄掛載在container中只讀:
docker run -it -v /root:/root:ro -h wadeson saltstack/ubuntu-14.04

 

--volumes-from list Mount volumes from the specified container(s)
  從一個指定的容器選擇掛載點
現在有兩個容器,都是exited狀態,現在啟動一個容器,將啟動的容器的掛載點選擇上面圖中的任何一個:
[root@docker ~]# docker run -it --volumes-from b8c05a805280 -h wadeson saltstack/ubuntu-14.04             
root@wadeson:/# ls /data/
root@wadeson:/#
  --volumes-from b8c05a805280:後面接容器名稱或者容器id
  相當於兩個container共同使用本機host的掛載點
[root@docker volumes]# ll
total 24
drwxr-xr-x. 3 root root    19 Oct 26 21:46 71025e4f8325fce175e21861a1fe0d089b9a08760778a8c9c517d6391c0dbceb
drwxr-xr-x. 3 root root    19 Oct 26 22:11 f808fc539538ba743c08a852b4b8c4e52c61a33df4c8e52032596385a39b963b
-rw-------. 1 root root 32768 Oct 26 22:11 metadata.db
[root@docker volumes]# cd f808fc539538ba743c08a852b4b8c4e52c61a33df4c8e52032596385a39b963b/_data/
[root@docker _data]# ll
total 0
  上面就是剛剛新建的(兩個container共同使用的掛載點)
 
容器間通訊:
  通過link引數,把container的埠資訊暴露到另一個container中,實現container之間的通訊
[root@docker ~]# docker run --name redis -dt redis
7014723aea605fa4baedb83be8e5f6d528b2fc009aa4379a1694f3131b72b041
  啟動一個名為redis的例項,後臺執行
  因為有預設的CMD命令,所以建立之後容器在處於執行狀態
[root@docker ~]# docker run --link redis:db -t saltstack/ubuntu-14.04 sh -c "export"
export DB_ENV_GOSU_VERSION='1.10'
export DB_ENV_REDIS_DOWNLOAD_SHA='b1a0915dbc91b979d06df1977fe594c3fa9b189f1f3d38743a2948c9f7634813'
export DB_ENV_REDIS_DOWNLOAD_URL='http://download.redis.io/releases/redis-4.0.2.tar.gz'
export DB_ENV_REDIS_VERSION='4.0.2'
export DB_NAME='/wizardly_keller/db'
export DB_PORT='tcp://172.17.0.2:6379'
export DB_PORT_6379_TCP='tcp://172.17.0.2:6379'
export DB_PORT_6379_TCP_ADDR='172.17.0.2'
export DB_PORT_6379_TCP_PORT='6379'
export DB_PORT_6379_TCP_PROTO='tcp'
export HOME='/root'
export HOSTNAME='192208a0c626'
export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
export PWD='/'
export TERM='xterm'
  該命令建立了將redis的容器的redis服務暴露在另一個container中,利用db這個別名將redis的服務資訊暴露給後面這個container的環境變數中,這樣後面的container就可以利用變數來連線redis容器的redis服務了
 
 

相關文章