docker之container

运行一个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服务了
 
 
posted on 2017-10-31 09:58  wadeson  阅读(6086)  评论(1编辑  收藏  举报