运行一个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服务了