摘要
docker 主要有两个部分进行组成,一个是镜像(第二节),一个容器(第三节)。下面将介绍,镜像的常用操作与容器的常用的操作。
有两个问题:1、容器之间的数据通信(第四节)。2、容器之间的数据共享(第五节)。这两个问题在下面也将展开介绍。
一、什么是Docker及其体系架构
1、什么是Docker?体系架构
(1)Docker是一个容器的引擎(虚拟机)
(2)让开发人员可以打包自己的应用程序(依赖:包、资源)
(3)虚拟化
(4)组成:
- Docker Client客户端:Docker命令
- Docker Daemon守护进程
- Docker Image镜像模板:分层结构
- Docker Container容器
docker就是一个管理员,管理其内部的容器,而每个容器可以看做一个服务,那么,如何把服务装配在容器之中,是通过镜像进行创建,就可以把服务装进容器之中,进而提供服务。那么,可能会产生两个问题:1、容器之间是如何进行通信。2、容器之间如何进行数据共享。这两个问题在下面都会提到。
2、安装和配置Docker实验环境:Ubuntu 16.04
Ubuntu进行安装docker
apt-get install docker.io
启动Docker服务
systemctl start docker
systemctl enable docker 开机自启
查看Docker版本
docker version
二、Docker的镜像:image(模板---->创建容器)
什么是Docker镜像?
(1)镜像是一个模板
(2)镜像采用分层的文件系统
(3)镜像是容器运行的基石
(4)可以从镜像仓库中进行拉取(公有、私有harbor)
0、持久化镜像
Save命令用于持久化镜像(不是容器)。所以,我们就需要通过以下方法得到镜像名称:
sudo docker images
接着执行保存:
sudo docker save busybox-1 > /home/save.tar
加载命令 docker load --input ***.tar
0.0 持久化容器
Export命令用于持久化容器(不是镜像)。所以,我们就需要通过以下方法得到容器ID:
sudo docker ps -a
接着执行导出:
sudo docker export <CONTAINER ID> > /home/export.tar
加载命令
docker import **.tar name:version
0.0.0 修改镜像名字和TAG
docker tag 1417b43a3ff5 faster-rcnn-3d:v1
1、使用和访问官方的Docker的镜像仓库(hub) https://hub.docker.com
常用命令:
docker search **** 搜索镜像模板
docker pull *** 拉取镜像(下载本地)
docker run 命令创建容器
docker ps 查看正在运行的容器
举例1:拉取MySQL的镜像,创建一个容器
docker search mysql
docker pull mysql ----> 默认:latest版本
docker images ----> 查看本地下载的镜像
docker run --name my_mysql_demo -p 3306:3306 -e MYSQL_ROOT_PASSWORD=Welcome_1 -d mysql
说明:
--name 指定容器的名称
-p 指定宿主机和容器之间的端口映射
-e 设置环境变量
-d 启动容器进程(后台,返回container id)
mysql 镜像的名称
进入容器:
docker exec -it CONTAINER_ID /bin/bash
docker exec -it eadee3a87f29 /bin/bash
2、配置和使用阿里云提供的Docker镜像加速器
阿里云官方配置
Ubuntu,其他点击上方链接
1. 安装/升级Docker客户端
推荐安装1.10.0以上版本的Docker客户端,参考文档 docker-ce
2. 配置镜像加速器
针对Docker客户端版本大于 1.10.0 的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://7s1e9gp7.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
加速地址:https://7s1e9gp7.mirror.aliyuncs.com
3、管理镜像(Docker命令)
docker search [NAME] 在镜像仓库中搜索镜像
docker pull [NAME] 拉取镜像(latest)
docker push [NAME] 上传到镜像仓库中
docker images 列出本地的所有镜像(基本信息)
docker images m* 支持通配符
docker inspect [NAME]/[CONTAINER_ID] 列出镜像(容器)的详细信息
docker rmi [NAME] 删除镜像
参数:-f 强制删除
如果有多个镜像,采用空格进行分隔
docker run 使用镜像创建容器
4、构建Docker镜像(上传到docker hub)
(1)使用docker commit
举例:
1、使用Docker部署一个Tomcat的容器
docker pull tomcat
docker run -d --name tomcat_web_app -p 8080:8080 tomcat
2、在Tomcat容器中部署一个简单的Web应用(修改容器)
docker exec -it 6490798df72b /bin/bash
cd webapps
mkdir mydemo
cd mydemo
echo '<h1>Hello Tomcat</h1>' > a.html
3、将容器保存docker commit -----> 本地
docker commit 6490798df72b tomcat_web_app_local
将容器保存docker commit -----> 镜像仓库中
登录 docker login,首先在https://hub.docker.com 进行创造用户。
注意 :collenzhao/tomcat_web_app_remote ,创建这个名字必须和自己创建的仓库保持一致,并且‘/’前必须指定自己的用户名。
docker commit 6490798df72b collenzhao/tomcat_web_app_remote
4、使用docker push命令上传的镜像
docker push collenzhao/tomcat_web_app_remote
(2)使用Dockerfile(命令:docker build)
Dockerfile就是根据自己的需求构建本地镜像
1、创建一个Dockerfile(-f参数指定文件名称)
基于Nginx镜像,部署一个简单的Web App应用
FROM nginx
RUN echo '<h1>This is a Demo WebApp</h1>' > /usr/share/nginx/html/index.html
2、使用docker build命令,生成镜像
docker build -t nginx:mylatest .
-f : 指定dockerfile文件名
-t : 指定生成镜像的名字
: :指标签、备注
. : 意思是把构成的最后的镜像保本到本地
3、创建一个容器
docker run -d -p 7788:80 nginx:mylatest
5、Dockerfile使用(综合例子)
(1)Docker镜像、Docker容器、Dockerfile三者的关系
实际上dockerfile就是构建一个新的镜像,dockerfile里的每一条指令都会生成一个新的镜像,并且输出最后生成的哪个镜像。
(2)Dockerfile的基本概念
- Docker镜像是一个特殊的文件系统
- Dockerfile基于文本的配置文件,包含一条条的指令。每一条指令构建分层文件系统中的一层
- docker build构建image镜像
(3)Dockerfile文件格式:4部分
- 基础镜像信息
- 维护者的信息,miantainer
- 镜像操作命令
- 容器启动执行的命令,cmd 、entrypoint
FROM 指定基础镜像
MAINTAINER 维护者的信息
RUN 执行一条命令
COPY 从宿主机上拷贝一个文件到镜像模板中
ENV 设置环境变量
ADD 添加一个URL的地址(下载文件)
ENTRYPOINT 启动容器的时候,执行命令
CMD与ENTRYPOINT的区别
-
ENTRYPOINT指令
执行docker run如果带有其他命令参数,不会覆盖ENTRYPOINT指令。
ENTRYPOINT [“top”,"-b", “-H”]
exec格式,也被称为JSON风格[“command”,“arg1”]。
在创建容器实例执行docker run命令时,设置的任何命令参数,都将作为ENTRYPOINT指令的命令参数,追加到ENTRYPOINT指令的命令之后。 -
CMD指令
执行docker run如果带有其他命令参数,将会覆盖CMD指令。
(4)综合的例子:
(#)从一个基本的centos基础镜像开始
(#)安装JDK和Tomcat
(#)在tomcat中部署一个Web App应用
(#)启动容器,访问Web App的应用
创建Dockerfile
FROM centos
MAINTAINER zhaoqiang zhaoqiang@example.com
RUN mkdir /root/training
RUN mkdir /root/tools
COPY jdk-8u144-linux-x64.tar.gz /root/tools
RUN tar zxvf /root/tools/jdk-8u144-linux-x64.tar.gz -C /root/training/
ENV JAVA_HOME /root/training/jdk1.8.0_144
ENV PATH $JAVA_HOME/bin:$PATH
ADD http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.5.35/bin/apache-tomcat-8.5.35.tar.gz /root/tools
RUN tar zxvf /root/tools/apache-tomcat-8.5.35.tar.gz -C /root/training/
COPY MyDemoWeb.war /root/training/apache-tomcat-8.5.35/webapps
ENTRYPOINT ["/root/training/apache-tomcat-8.5.35/bin/catalina.sh","run"]
编译的命令:docker build -t mywebapp .
启动容器: docker run -d -p 8080:8080 mywebapp
三、Docker的容器(container)
1、容器的基本操作:创建容器、停止容器、进入容器、删除容器
(1)创建容器
命令:run、create、start
区别:run = create + start
例子:docker create --name mycontainer1 centos
无法通过docker ps命令来查看容器,因为容器没有运行
docker start [container id]
(2)停止容器 docker stop
(3)进入容器 docker exec -it 47ceba4e6e66 /bin/bash
参数 -i 保持标准输入打开 、 -t 分配一个伪终端
(4)删除容器: docker rm 47ceba4e6e66
docker rmi [镜像id] 是删除镜像,注意区分。
(5)导入和导出容器(迁移)
注意:不管容器处于什么状态,都可以使用export导出操作
docker export
docker export -o mywebapp.tar 47ceba4e6e66
docker import 把导入的tar包变成一个镜像
docker import mywebapp.tar mywebapp_imported
2、容器的日志
(1)Docker引擎的日志:一般来说,由操作系统来维护
Ubuntu16.04: journalctl -u docker.service
(2)容器的日志:命令 docker logs [CONTAINER_ID]
命令:docker logs -f -t --since=“2018-12-01” --tail=20 47ceba4e6e66
-f 查看实时日志,类似 tail -f
-t 查看日志产生的日期
--since 指定了输入日志的开始期(只输出指定日期后产生的日志)
--tail 查看最后的20条日志
3、管理容器的资源
(1)基础知识:Linux Control Groups
(-)什么是Linux Control Groups?
简单来说:以一组进程为目标进行系统资源的分配和控制。对资源的限制。
(-)功能
- 限制资源的使用
- 优先级的控制
- 审计
- 控制功能:挂起进程、恢复执行进程
(-)查看Linux的内核中,是否启用了cgroup的功能
uname -r
cat /boot/config-4.4.0-142-generic |grep CGROUP
y代表yes
(-)Demo1:限制进程(应用程序)对CPU的使用率
开发一个c程序:死循环
int main(void){
int i=0;
for(;;) i++;
return 0;
}
使用gcc进行编译: yum install gcc
gcc -o hello hello.c
== 对应用程序的CPU的使用率进行限制:20% ==
cd /sys/fs/cgroup/cpu
mkdir my001
cd my001
查看cat cpu.cfs_quota_us
-1 表示:没有任何的限制
echo 20000 > cpu.cfs_quota_us
把hello的进程号 ---> tasks中
echo 6565 > tasks
再启动一个hello程序
两个hello程序总的CPU的使用:20%
(-)Demo2:限制进程(应用程序)对内存的使用
cd /sys/fs/cgroup/memory/my001 如果没有这个目录,创建这个目录
查看cat memory.limit_in_bytes
9223372036854771712 可以没有任何限制
规定hello的应用程序最多只能使用64K的内存
echo 64k > memory.limit_in_bytes
把hello的进程号写到tasks
echo 6633 > tasks
== 如果6633(hello的应用程序)的内存使用超过64K,自动被kill ==
(-)Demo3:限制进程(应用程序)对I/O使用
安装工具:iotop 类似top命令 监视磁盘的IO的情况
命令:dd if=/dev/sda of=/dev/null 不断访问磁盘
使用iotop监视磁盘的IO的情况
cd /sys/fs/cgroup/blkio/my001 如果没有这个目录,创建这个目录
显示对磁盘的IO的访问:10M之内
echo '8:0 10485760' > blkio.throttle.read_bps_device
把进程号输出到tasks中(生效)
echo 6671 > tasks
(2)Docker对容器使用CPU的使用率:是相对权重
准备实验的环境 Dockerfile
FROM centos:latest
RUN yum install -y epel-release && yum install -y stress
ENTRYPOINT ["stress"]
stress 启动压力测试
docker build -t centos001 .
启动两个容器,分配CPU使用率的不同权重(相对)
docker run -it centos001 --cpu 4 ----> 默认CPU使用率的权重:1024
docker run -it -c 512 centos001 --cpu 4 ----->CPU使用率的权重:512
注意:-c 512,必须卸载centos001之前,因为写在之后,会变成stress的参数。
通过命令:docker stats
CONTAINER CPU %
ecd45c19e72d 32.50%
3562d2c5a40f 66.21%
(3)Docker对容器使用的内存管理和限制
默认:一个容器可以使用宿主机上所有的内存
使用命令:docker run -m开关:使用内存的大小
docker run -it -m 128m centos001 --cpu 4
-m 指定容器的使用内存的上限
通过docker stats查看
CONTAINER CPU % MEM USAGE / LIMIT
1cb50eaff3f4 97.36% 192 KiB / 128 MiB
(4)Docker对容器使用I/O的管理和限制
- Demo1: --blkio-weight 参数(测试的时候,效果不是很理想)
docker run -it --blkio-weight 100 centos /bin/bash
docker run -it --blkio-weight 1000 centos /bin/bash
在两个容器中,同时执行dd命令
dd if=/dev/zero of=test.out bs=1M count=3000
- Demo2:–device-read-bps和–device-write-bps
限制容器读入和写出的速率:1M(每秒)
写入速率的上限:1M
docker run -it --device-write-bps /dev/sda:1mb centos /bin/bash
在容器内部:dd if=/dev/zero of=test.out bs=1M count=20 oflag=direct
oflag=direct表示:读写数据采用直接IO
读取数据速率的上限:1M
docker run -it --device-read-bps /dev/sda:1mb centos /bin/bash
- Demo3: --device-write-iops和–device-read-iops
以写数据为例:容器write iops 是5/秒(次数)
docker run -it --device-write-iops /dev/sda:5 centos /bin/bash
在容器内部执行: dd if=/dev/zero of=test.out bs=1M count=200 oflag=direct
使用命令观察: iostat 1 (安装:yum install sysstat)
也能针对读,进行限制
docker run -it --device-read-iops /dev/sda:5 centos /bin/bash
四、Docker网络和容器的通信
docker的网络通信的实质就是虚拟的接口的隐射
1、Docker网络通信的基本原理
(1)Docker的网络接口是虚拟的接口
(2)虚拟的网络接口的转发的效率高
(3)宿主机的信息
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:52ff:fe4b:4e4c prefixlen 64 scopeid 0x20<link>
ether 02:42:52:4b:4e:4c txqueuelen 0 (Ethernet)
RX packets 8 bytes 536 (536.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
vethd1b406d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::78da:cfff:feef:44b5 prefixlen 64 scopeid 0x20<link>
ether 7a:da:cf:ef:44:b5 txqueuelen 0 (Ethernet)
RX packets 8 bytes 648 (648.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 16 bytes 1296 (1.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
(4)到容器内部查看网卡的信息
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe11:2 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 1819 bytes 8445579 (8.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1687 bytes 95886 (93.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
(5)Docker创建容器的时候,会执行下面的操作
- 创建一对的虚拟的网络接口,一个放在本地的主机和新容器的各自的命名空间中
- 本地主机一端的虚拟的接口连接到默认的docker0的网桥上,取名:veth****
- 容器一端:把虚拟的网络接口放到新容器中,改名:eth0
- 从网桥(docker0)获取一个空闲的IP地址,分配给容器的eth0的网卡
2、Docker的网络模式:
四种不同的网络模式:host、container、bridge(默认)、none
命令:docker network ls
NETWORK ID NAME DRIVER SCOPE
845b88ede2ca bridge bridge local
74a262ef9181 host host local
6bcd1c1ff2ea none null local
镜像:busybox集成了一百多个Linux的工具箱
(1)host:容器不会虚拟出自己的网卡,直接使用宿主机的IP和端口
docker run -it --network=host busybox /bin/sh
信息:
docker0 Link encap:Ethernet HWaddr 02:42:52:4B:4E:4C
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:52ff:fe4b:4e4c/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:1692 errors:0 dropped:0 overruns:0 frame:0
TX packets:1812 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:72456 (70.7 KiB) TX bytes:8444973 (8.0 MiB)
(2) container:容器不会虚拟出自己的网卡,和一个指定的容器共享IP和端口
启动两个容器:第一个 docker run -it busybox /bin/sh —> 使用bridge的模式
信息
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
第二个 docker run -it --network=container:d8c0a1aa2673 busybox /bin/sh 、 其中:d8c0a1aa2673是另一个容器的ID
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
(3)bridge:默认的模式,会为每一个新创建的容器分配网络配置(IP等等)
(4)none:关闭了容器的网络功能
docker run -it --network=none busybox /bin/sh
通过ifconfig,无法查看到eth0的信息
(5) 自定义bridge的模式
- 创建自己的网络:bridge
docker network create -d bridge --ip-range=192.168.78.0/24 --gateway=192.168.78.1 --subnet=192.168.78.0/24 bridge2
查看网络模式的详情:docker network inspect 3e7b5641cbeb
- 创建自己的容器,使用自定义的网络模式(bridge2)
docker run -it --network=bridge2 --ip=192.168.78.3 busybox
docker run -it --network=bridge2 --ip=192.168.78.4 busybox
3、容器间的通信
可以通过IP进行访问,也可以通过name进行访问。
(1)IP通信
docker run -it --network=bridge2 --ip=192.168.78.3 busybox
docker run -it --network=bridge2 --ip=192.168.78.4 busybox
缺点:不够灵活
(2)Docker DNS Server
参数:–name
docker run -it --network=bridge2 --name box1 busybox
docker run -it --network=bridge2 --name box2 busybox
(3)Joined容器:本质就是container网络模式
基于httpd的镜像创建容器
docker run -it --name box3 httpd
使用Joined容器创建一个新的容器
docker run -it --network=container:box3 busybox
测试:在第二个容器中执行wget 127.0.0.1
4、容器访问控制
(1)容器访问外部网络
需要宿主机的转发
docker run -it centos
sysctl net.ipv4.ip_forward ---> 是1,开启了转发功能
是0,没有开启转发
通过下面方式开启
sysctl -w net.ipv4.ip_forward=1
更简单:启动docker服务的时候指定: --ip-forward=true
(2)外部访问容器网络:通过指定-p参数进行端口映射
docker run -it -p 80:80 centos bash
在宿主机上:iptables -nL查看
五、Docker的数据管理:数据的共享
1、Docker的数据卷(共享目录)
(1)相当于mount操作,mount:它可以将分区挂接到Linux的一个文件夹下,从而将分区和该目录联系起来,因此我们只要访问这个文件夹,就相当于访问该分区了。
(2)是一个可供容器使用的特殊的目录
(3)实现主机操作系统与容器之间进行目录的映射
(4)特性:
- 数据卷可以在容器之间实现数据的共享和重用
- 对数据卷内数据的修改会立即生效
- 对数据卷的更新不会影响镜像
- 数据卷会一直存在,直到没有容器使用
(5)Demo演示
在主机和容器之间创建数据卷,实现数据共享(共享目录)
docker run -it -v /root/mydatavolume:/root/container/mydatavolume centos /bin/bash
-v 指定数据卷的目录
默认:挂载的数据卷默认权限是读写(RW),也可以通过指定ro参数标识为只读
docker run -it -v /root/mydatavolume:/root/container/mydatavolume:ro centos /bin/bash
宿主机地址在前,容器地址在后。
(6)新版本的docker:使用命令: docker volume 命令管理数据卷
docker volume create ----> 也可以创建数据卷
(6)问题:Permission denied
原因:Centos 7的安全模块selinux把权限给禁掉了
(1)--privileged=true 加入到docker run中
(2)临时关闭SeLinux: setenforce 0
2、Docker的数据卷容器
(1)数据卷容器也是一个容器,目的:专门用来提供数据卷供其他的容器挂载
(2)实现在多个容器之间数据数据的共享
(3)Demo演示:创建数据卷容器
创建一个数据卷容器dbdatacontainer,在这个容器中创建一个数据卷挂载: /dbdata
docker run -it -v /dbdata --name dbdatacontainer centos
可以在其他的容器中使用 --volumes-from来挂载dbdatacontainer容器中的数据卷
docker run -it --volumes-from dbdatacontainer --name db1 centos
docker run -it --volumes-from dbdatacontainer --name db2 centos
3、利用数据卷容器来实现数据的迁移:数据的备份和恢复
备份与恢复的本质,就是借助数据卷这个在宿主机与容器之间的桥梁,让数据在宿主机与容器之间来回传递。
3.1、备份:使用下面的命令备份dbdatacontainer数据卷容器内的数据卷(tar包)
docker run --volumes-from dbdatacontainer -v $(pwd):/backup --name myworker centos tar cvf /backup/backup.tar /dbdata
3.2、恢复:如果要将数据恢复到一个容器中
-
创建一个带有数据卷的容器
docker run -it -v /dbdata --name dbdatacontainer2 centos -
docker run -it --volumes-from dbdatacontainer2 -v $(pwd):/backup --name worker2 centos /bin/bash