Docker 操作指南之常见使用篇
容器的使用
docker run -i -t /bin/bash
使用 image 创建 container 并进入交互模式, login shell 是/bin/bash
实例:
$ docker run -it ubuntu /bin/bash
root@946be96acd5f:/#
root@946be96acd5f:/# exit
exit
exit 后容器将不在运行
docker start -i
启动一个 container 并进入交互模式
实例:
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
648944eeef8a ubuntu "/bin/bash" 8 seconds ago Exited (0) 6 seconds ago suspicious_feynman
root@ubun:~# docker start -i 648944eeef8a
root@648944eeef8a:/#
docker exec
通过宿主机在正在运行的容器上执行命令
通过宿主机在容器上创建文件
docker exec 87cb69be18bb touch /root/abc.txt
可通过 exec 命令从正在运行的容器上申请一个终端,执行 shell
docker exec -it 87cb69be18bb /bin/bash
docker ps
默认显示正在运行中的 container
docker ps –a
显示所有的 container,包括未运行的实例:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
946be96acd5f ubuntu "/bin/bash" About a minute ago Exited (0) About a minute ago thirsty_mclean
docker ps –l
显示最后一次创建的 container,包括未运行的
docker start/stop/restart
开启/停止/重启 container
docker 容器和镜像迁移
docker 的备份方式有 export 和 save 两种:
-
docker export 当前状态的容器,通过 docker import 进行恢复;
-
docker save针 对的是镜像,通过 docker load 进行恢复。
save
- 找出要保存的镜像名称
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
memcached v0.1 291272444a64 7 weeks ago 212 MB
- 备份镜像
docker save memcached:v0.1 >memcached_bak.tar
- 恢复镜像
将镜像 scp 到目标服务器,恢复镜像
$ docker load < memcached_bak.tar
- 查看镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
memcached v0.1 291272444a64 7 weeks ago 212 MB
export
- 找出要保存的容器ID或名称
docker ps|grep memcached
- 备份容器
docker export memcached > memcached_bak.tar
- 恢复成镜像
docker import memcached_bak.tar memcached
- 查看镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
memcached latest 51af4462e58b About a minute ago 250.5 MB
2两者区别
导出后再导入(export-import) 的镜像会丢失所有的历史和层信息,而保存后再加载(save-load)的镜像没有丢失历史和层 (layer)。
这意味着使用导出后再导入的方式,你将无法回滚到之前的层(layer),同时,使用保存后再加载的方式持久化整个镜像,就可以做到层回滚.
使用 Supervisor 来管理进程
docker 容器在启动的时候开启单个进程,比如,一个 ssh 或者 apache 的 daemon 服务。但我们经常需要在一个机器上开启多个服务,这可以有很多方法,最简单的就是把多个启动命令方到一个启动脚本里面,启动的时候直接启动这个脚本,另外就是安装进程管理工具。下面将使用进程管理工具 supervisor 来管理容器中的多个进程。使用 Supervisor 可以更好的控制、管理、重启我们希望运行的进程。
下面这里我们演示一下如何同时使用 ssh 和 haproxy 服务。
创建 dockerfile
mkdir webserver
cd webserver
vi Dockerfile
FROM ubuntu:14.04
MAINTAINER 7d
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y openssh-server haproxy supervisor
#↑安装软件
RUN mkdir -p /var/run/sshd
RUN mkdir -p /var/log/supervisor
#↑创建了2个用来允许ssh和supervisor的目录
RUN sed -i 's/root/#root/g' /etc/shadow
RUN sed -i '1i\root:$1$R8Pn1TN5$4lKkDscZH4rbMa4P9H3Zx1:16501:0:99999:7:::' /etc/shadow
#↑修改root密码为root。root默认无密码,不能登录ssh
Run sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
#↑允许root登录
COPY ssh.conf /etc/supervisor/conf.d/ssh.conf
#↑将本地的supervisor's的配置文件ssh.conf添加到容器中
EXPOSE 22 80
#↑对外发布22、80端口
CMD ["/usr/bin/supervisord"]
#↑使用cmd来启动supervisord,使用supervisord的可执行路径启动服务。
注:/etc/shadow 文件的密码为加密过的,通过以下命令生成加密密码
openssl passwd -1 -salt $(< /dev/urandom tr -dc '[:alnum:]' | head -c 32)
提示输入要加密的密码,即可生成加密密码。
创建 supervisor 配置文件 ssh.conf
cd webserver
vi ssh.conf
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:haproxy]
command=haproxy -f /etc/haproxy/haproxy.cfg
process_name=haproxy
autostart=true
autorestart=true
配置文件包含目录和进程,第一段 supervsord 配置软件本身,使用 nodaemon 参数来运行。
下面 2 段包含要控制的 2 个服务。每一段包含一个服务的目录和启动这个服务的命令。
使用方法
- 创建image
docker build -t webserver:v1 .
- 创建并启动我们的 supervisor 容器
docker run –d \
--name webserver \
-p 10022:22 \
-p 10080:80 \
-it webserver:v1
使用 docker run 来启动我们创建的容器。-d 让容器以后台方式运行。使用多个 -p 来映射多个端口,将容器的 22 端口映射为本地的 10022,80 映射为 10080。这样我们就能同时访问 ssh 和 haproxy 服务了。
- 查看容器状态:
docker ps
启动后会发现本地启动 10022 和 10080 端口
tcp6 0 0 :::10080 :::* LISTEN
tcp6 0 0 :::10022 :::* LISTEN
通过如下 ssh 即可访问容器
ssh 127.0.0.1 –p 10022
- 容器的停止与启动
docker stop webserver
容器停止后,本地的 10022 和 10022 端口也随之消失。
docker start webserver
再次启动容器。
容器间的链接
运行一个容器,给它一个名称,例如:
启动容器 1:web
docker run --name web -d -p 22 -p 80 -it webserver:v1
启动容器2:ap1,连接到 web
docker run --name ap1 --link=web:apache -d -p 22 -p 80 -it webserver:v1
启动容器 3:ap2,连接到 web
docker run --name ap2 --link=web:apache -d -p 22 -p 80 -it webserver:v1
说明:
启动两个容器 ap1,ap2 连接到 web,并将其命名为 apache
在宿主机上使用i ptables 命令来查看,例如:
iptables –L –n
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 172.17.0.147 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.147 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 172.17.0.148 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.148 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 172.17.0.149 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.149 tcp dpt:22
从这里看到两个容器间端口可以互相的访问了,ssh 到 172.17.0.147,并可以通过该机器 ssh 到148,149
容器下数据卷的使用
- 一个数据卷就是经过特殊设计的,在一个或多个容器中通过UFS文件系统提供的一些特性
- 实现数据持久化或共享.
- 数据卷可以在容器之间共享和重复利用
- 可以对数据卷里的内容直接进行修改
- 对镜像的更新不会改变数据卷的内容
- 卷会一直持续到没有容器使用他们
添加一个数据卷
可以使用带有 -v 参数的 docker run 命令给容器添加一个数据卷.
docker run -d -p 22 -p 9100:80 --name haserver -v /data1 ubuntuha:v2 /usr/sbin/sshd –D
这个在容器里就会有一个 /data1 的卷
#df -h
/dev/disk/by-uuid/8398833e-fdbb-423f-ac92-661e095b4afe 19G 12G 6.5G 64% /data1
在 Dockefile 中使用 VOLUME 指令来创建添加一个或多个数据卷
挂载宿主文件夹到数据卷
使用 -v 参数也可以挂载宿主的文件夹到容器里
docker run -d -p 22 -p 9000:80 --name datatest -v /data:/opt/data ubuntuha:v2 /usr/sbin/sshd -D
这样会把本地的 /data 文件夹挂在容器 /opt/data 目录下。
宿主机上的文件夹必须是绝对路径,而且当文件夹不存在时会自动创建,此功能在 Dockerfile 文件中无法使用。
默认情况下 Docker 以读写权限挂载数据卷,但是我们也可以以只读方式进行挂载。
docker run -d -p 22 -p 9000:80 --name datatest -v /data:/opt/data:ro ubuntuha:v2 /usr/sbin/sshd -D
还是上面的那个命令,只是我们添加了一个 ro 选项来制定挂载时文件权限应该是只读的。
创建和挂载一个数据卷容器
如果一些数据需要在容器间共享最好的方式来创建一个数据卷容器,然后从数据卷容器中挂载数据
创建一个带有命名容器来共享数据
docker run -d -p 22 -v /data --name dbdata ubuntuha:v2 /usr/sbin/sshd -D
在另一个容器中使用 --volumes-from 标记挂在 /dbdata 卷
docker run -d -p 22 -p 9100:80 --volumes-from dbdata --name webserver1 ubuntuha:v2 /usr/sbin/sshd -D
在另一个容器中同时也挂载 /dbdata 卷
docker run -d -p 22 -p 9200:80 --volumes-from dbdata --name webserver2 ubuntuha:v2 /usr/sbin/sshd -D
可以使用多个 --volumes-from 参数来把多个容器中的多个数据卷放到一起
备份,恢复,迁移数据
使用它们来进行备份,恢复或迁移数据.如下所示,我们使用
–volumes-from 标记来创建一个挂载了要备份数据卷的容器.
docker run -d -p 22 --volumes-from dbdata -v /bkserver:/backup ubuntuha:v2 tar zcvf /backup/backup.tar.gz /data
这里我们创建并登录了一个新容器,挂载了 dbdata 容器中的数据卷,并把本地的一个目录(/bkserver)挂载了 /backup下,最后再传一条 tar 命令来备份 dbdata 卷到 /backup 下,当命令执行完成后容器就会停止运行,并保留 dbdata 的备份,在本地目录( /bkserver )下会一个备份的文件。
注:新创建的容器中要有 tar 命令,得到备份数据就可以恢复或迁移数据了
容器间的链接
运行一个容器,给它一个名称,例如:
启动容器1:web
docker run --name web -d -p 22 -p 80 -it webserver:v1
启动容器2:ap1 连接到 web
docker run --name ap1 --link=web:apache -d -p 22 -p 80 -it webserver:v1
启动容器3:ap2 连接到 web
docker run --name ap2 --link=web:apache -d -p 22 -p 80 -it webserver:v1
说明:
启动两个容器 ap1,ap2 连接到 web,并将其命名为 apache
在宿主机上使用 iptables 命令来查看,例如:
#iptables –L –n
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 172.17.0.147 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.147 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 172.17.0.148 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.148 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 172.17.0.149 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.149 tcp dpt:22
从这里看到两个容器间端口可以互相的访问了,ssh 到 172.17.0.147,并可以通过该机器 ssh 到148,149
桥接和容器静态IP
-
宿主机(系统采用
ubuntu-14.04.1-server-amd64
)的网络采用桥接模式(默认是 DHCP 模式,还有一种模式就是静态 IP),网桥的网段与物理网段相同。目前的物理网段为192.168.5.1/24
,网关是192.168.1.1
,物理网卡设备为 eth0 -
编辑配置文件
/etc/network/interfaces
,自定义网桥 br0
auto lo
iface lo inet loopback
auto br0
iface br0 inet static
address 192.168.1.251
netmask 255.255.255.0
broadcast 192.168.10.255
gateway 192.168.1.1
bridge_ports eth0
bridge_stp off
dns-nameservers 114.114.114.114
- 配置保存退出后,重启网络
ifdown -a && ifup –a
- 网桥配置好后,剩下的就是 docker 相关的网络配置了。
- 容器启动的网络模式必须为 none,用
-net=none
指定,比如
docker run -it --rm --net=none jim/custom1 /bin/bash
- 自动添加 IP 脚本
#/bin/bash
if [ -z $1 ] || [ -z $2 ] || [ -z $3 ] || [ -z $4 ] || [ -z $5 ];
then
echo "*****Input the necessary parameters: CONTAINERID IP MASK GATEWAY ETHNAME"
echo "*****Call the script like: sh manual_con_static_ip.sh b0e18b6a4432 192.168.5.123 24 192.168.5.1 deth0"
exit
fi
CONTAINERID=$1
SETIP=$2
SETMASK=$3
GATEWAY=$4
ETHNAME=$5
#判断宿主机网卡是否存在
ifconfig $ETHNAME > /dev/null 2>&1
if [ $? -eq 0 ]; then
read -p "$ETHNAME exist,do you want delelte it? y/n " del
if [[ $del == 'y' ]]; then
ip link del $ETHNAME
else
exit
fi
fi
#
pid=`docker inspect -f '{{.State.Pid}}' $CONTAINERID`
mkdir -p /var/run/netns
find -L /var/run/netns -type l -delete
if [ -f /var/run/netns/$pid ]; then
rm -f /var/run/netns/$pid
fi
ln -s /proc/$pid/ns/net /var/run/netns/$pid
#
ip link add $ETHNAME type veth peer name B
brctl addif br0 $ETHNAME
ip link set $ETHNAME up
ip link set B netns $pid
#先删除容器内已存在的eth0
ip netns exec $pid ip link del eth0 > /dev/null 2>&1
#设置容器新的网卡eth0
ip netns exec $pid ip link set dev B name eth0
ip netns exec $pid ip link set eth0 up
ip netns exec $pid ip addr add $SETIP/$SETMASK dev eth0
ip netns exec $pid ip route add default via $GATEWAY
- 使用方法
./setip 457f72c7d4cf 192.168.1.253 24 192.168.1.1 deth0
- 脚本说明
pid=`docker inspect -f '{{.State.Pid}}' $CONTAINERID`
为了操作容器需要获取容器的进程号 PID,docker inspect 可以查看容器的底层信息,查看容器 dfe83012cda2 所有的底层相关信息,用 docker inspect dfe83012cda2
就可以查看。
-f 参数可以格式化输出给定的信息,比如查看容器的状态
# docker inspect -f '{{.State.Running}}' dfe83012cda2
true
root@ubuntu-docker:~#
为容器创建 net 命名空间,建立点对点连接(容器命名空间网卡和宿主上生成的网卡点对点),确保存放 net 命名空间的目录 /var/run/netns 存在,然后删除该目录失效的链接,再将容器的 net 命名空间文件软链接到 /var/run/netns,以便执行 ip netns 能够读取。
mkdir -p /var/run/netns
find -L /var/run/netns -type l -delete
ln -s /proc/$pid/ns/net /var/run/netns/$pid
在宿主上创建 2 张直连网卡(A 与 B 直连),将 B 作为容器里的网卡,A 作为宿主机的网卡。
ip link add A type veth peer name B
将网卡 A 桥接到 br0 上,并启动网卡 A
brctl addif br0 A
ip link set A up
将网卡 B 加入到相应的容器 net 命名空间,当网卡 B 加入到容器的 net 命名空间后,宿主机将无法查看到该网卡信息(执行i p netns 时默认读取的目录是 /var/run/netns
)
ip link set B netns $pid
ip netns exec 能进入容器的 net 命名空间,可以用来配置容器 net 命名空间的网络参数,配置容器内的网卡 B
ip netns exec $pid ip link set dev B name eth0
ip netns exec $pid ip link set eth0 up
ip netns exec $pid ip addr add $SETIP/$SETMASK dev eth0
ip netns exec $pid ip route add default via $GATEWAY
接下来先了解下 docker 为容器创建网络的过程《http://dockerpool.com/static/books/docker_practice/underly/network.html》,就会明白为什么要这么配置了。
- 创建一对虚拟接口,分别放到本地主机和新容器中;
- 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;
- 容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的名字空间可见;
- 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。
当我们使用–net=none 参数启动容器后,docker 不对容器进行网络配置。如果需要容器网络可用需要我们按照相同的步骤配置容器的网络
相关系列:
- 点赞
- 收藏
- 关注作者
评论(0)