Docker 操作指南之常见使用篇

Posted zuozewei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker 操作指南之常见使用篇相关的知识,希望对你有一定的参考价值。

一、容器的使用

1、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 后容器将不在运行

2、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:/#

3、docker exec

通过宿主机在正在运行的容器上执行命令

通过宿主机在容器上创建文件

docker exec 87cb69be18bb touch /root/abc.txt     

可通过 exec 命令从正在运行的容器上申请一个终端,执行 shell

docker exec -it 87cb69be18bb /bin/bash     

4、docker ps

默认显示正在运行中的 container

5、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   

6、docker ps –l

显示最后一次创建的 container,包括未运行的

docker start/stop/restart

开启/停止/重启 container

二、docker 容器和镜像迁移

docker 的备份方式有 export 和 save 两种:

  • docker export 当前状态的容器,通过 docker import 进行恢复;

  • docker save针 对的是镜像,通过 docker load 进行恢复。

1、save

  1. 找出要保存的镜像名称
$ docker images     
REPOSITORY        TAG               IMAGE ID          CREATED           VIRTUAL SIZE     
memcached         v0.1              291272444a64      7 weeks ago         212 MB
  1. 备份镜像
docker save memcached:v0.1 >memcached_bak.tar
  1. 恢复镜像
    将镜像 scp 到目标服务器,恢复镜像
$ docker load < memcached_bak.tar
  1. 查看镜像
$ docker images     
REPOSITORY        TAG               IMAGE ID          CREATED           VIRTUAL SIZE     
memcached         v0.1              291272444a64      7 weeks ago         212 MB

2、export

  1. 找出要保存的容器ID或名称
docker ps|grep memcached
  1. 备份容器
docker export memcached > memcached_bak.tar
  1. 恢复成镜像
docker import memcached_bak.tar memcached
  1. 查看镜像
$ docker images     
REPOSITORY      TAG             IMAGE ID            CREATED              VIRTUAL SIZE     
memcached      latest           51af4462e58b        About a minute ago      250.5 MB

2.1、两者区别

导出后再导入(export-import) 的镜像会丢失所有的历史和层信息,而保存后再加载(save-load)的镜像没有丢失历史和层 (layer)。

这意味着使用导出后再导入的方式,你将无法回滚到之前的层(layer),同时,使用保存后再加载的方式持久化整个镜像,就可以做到层回滚.

三、使用 Supervisor 来管理进程

docker 容器在启动的时候开启单个进程,比如,一个 ssh 或者 apache 的 daemon 服务。但我们经常需要在一个机器上开启多个服务,这可以有很多方法,最简单的就是把多个启动命令方到一个启动脚本里面,启动的时候直接启动这个脚本,另外就是安装进程管理工具。下面将使用进程管理工具 supervisor 来管理容器中的多个进程。使用 Supervisor 可以更好的控制、管理、重启我们希望运行的进程。

下面这里我们演示一下如何同时使用 ssh 和 haproxy 服务。

1、创建 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)

提示输入要加密的密码,即可生成加密密码。

2、创建 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 个服务。每一段包含一个服务的目录和启动这个服务的命令。

3、使用方法

  1. 创建image
docker build -t webserver:v1 .
  1. 创建并启动我们的 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 服务了。

  1. 查看容器状态:
docker ps   

启动后会发现本地启动 10022 和 10080 端口

tcp6       0      0 :::10080                :::*                    LISTEN          
tcp6       0      0 :::10022                :::*                    LISTEN

通过如下 ssh 即可访问容器

ssh 127.0.0.1 –p 10022     
  1. 容器的停止与启动
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文件系统提供的一些特性
  • 实现数据持久化或共享.
  • 数据卷可以在容器之间共享和重复利用
  • 可以对数据卷里的内容直接进行修改
  • 对镜像的更新不会改变数据卷的内容
  • 卷会一直持续到没有容器使用他们

1、添加一个数据卷

可以使用带有 -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 指令来创建添加一个或多个数据卷

2、挂载宿主文件夹到数据卷

使用 -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 选项来制定挂载时文件权限应该是只读的。

3、创建和挂载一个数据卷容器

如果一些数据需要在容器间共享最好的方式来创建一个数据卷容器,然后从数据卷容器中挂载数据

创建一个带有命名容器来共享数据

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 参数来把多个容器中的多个数据卷放到一起

4、备份,恢复,迁移数据

使用它们来进行备份,恢复或迁移数据.如下所示,我们使用
–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

  1. 宿主机(系统采用 ubuntu-14.04.1-server-amd64)的网络采用桥接模式(默认是 DHCP 模式,还有一种模式就是静态 IP),网桥的网段与物理网段相同。目前的物理网段为 192.168.5.1/24,网关是192.168.1.1,物理网卡设备为 eth0

  2. 编辑配置文件 /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
  1. 配置保存退出后,重启网络
ifdown -a && ifup –a
  1. 网桥配置好后,剩下的就是 docker 相关的网络配置了。
  2. 容器启动的网络模式必须为 none,用 -net=none 指定,比如
docker run -it --rm --net=none jim/custom1 /bin/bash
  1. 自动添加 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
  1. 使用方法
./setip 457f72c7d4cf 192.168.1.253 24 192.168.1.1 deth0
  1. 脚本说明
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 不对容器进行网络配置。如果需要容器网络可用需要我们按照相同的步骤配置容器的网络

相关系列:

以上是关于Docker 操作指南之常见使用篇的主要内容,如果未能解决你的问题,请参考以下文章

测试开发之系统篇-Docker常用操作

测试开发之系统篇-Docker常用操作

Docker 操作指南之常用操作篇

Docker开篇之基础概念篇

测试开发之系统篇-Docker 常用操作

DevOps利器之Docker入门篇