docker是dotcloud公司开源的一个基于LXC的高级容器引擎,源代码托管在github上,基于go语言编写并遵从apache2.0协议开源,主要是基于PAAS平台为开发者提供服务
容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源
docker设想交付运行环境如同海运,OS如同一艘货轮,每一个在OS基础上的软件如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱内容可以用户自定义,也可以由专业人士制造
传统虚拟化技术
容器化技术
安装命令:curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
设置阿里云仓库:yum-config-manager
–add-repo
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
启动docker:systemctl start docker
检验是否安装成功:docker run hello-world
docker pull:下载镜像
docker run:运行镜像
docker info:查看docker容器信息
docker search:docker仓库查询
docker pull:docker仓库下载
docker images:docker镜像查询
docker rmi:docker镜像删除
docker ps:容器查询
docker run:容器创建启动
docker start/stop:容器启动/停止
docker inspect:查看容器详情
docker logs:查看容器日志
docker stats:查看容器占用系统资源
docker exec:容器执行命令
docker exec -it 容器名 /bin/bash:登录容器bash
容器创建是需要指定使用的镜像,每个镜像都由唯一的标识Image ID,和容器的Container ID一样,他们默认都是128位,可以使用前16位作为缩略形式,也可以使用镜像镜像名和版本号两个部分组合成唯一表示,例如nginx:latest,如果省略版本号,默认使用的是最新版本标签,也就是latest,所以如果默认直接写nginx,其实系统执行的实际命令就是nginx:latest。
Linux系统包含内核空间kernal和用户空间rootfs两部分,Docker容器只使用各自的rootfs但共用主机host的内核kernal,这样就产生了镜像结构分层。
rootfs是Docker容器在启动时内部进程可见的文件系统,也就是Docker容器的根目录。rootfs包含一个操作系统运行所需的文件系统。例如:可能包含典型类UNIX系统中的目录系统/dev/、/proc、/bin、/etc、/usr、/tmp…及运行Docker容器所需的配置文件、工具等。
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
FROM:定制的镜像都是基于 FROM 的镜像
RUN:用于执行后面跟着的命令行命令。有以下俩种格式
shell 格式:
RUN <命令行命令>
<命令行命令> 等同于,在终端操作的 shell 命令。
RUN [“可执行文件”, “参数1”, “参数2”]
例如:RUN ["./test.php", “dev”, “offline”] 等价于 RUN ./test.php dev offline
COPY [–chown=:] <源路径1>… <目标路径>
COPY [–chown=:] ["<源路径1>",… “<目标路径>”]
[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
格式:
CMD
CMD ["<可执行文件或命令>","","",…]
CMD ["","",…] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
ENTRYPOINT ["","","",…]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT [“nginx”, “-c”] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
1 不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
ENV
ENV = =…
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0
RUN curl -SLO “https://nodejs.org/dist/v N O D E V E R S I O N / n o d e − v NODE_VERSION/node-v NODEVERSION/node−vNODE_VERSION-linux-x64.tar.xz”
&& curl -SLO “https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc”
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:
ARG <参数名>[=<默认值>]
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
VOLUME ["<路径1>", “<路径2>”…]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
仅仅只是声明端口。
作用:
EXPOSE <端口1> [<端口2>…]
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
格式:
WORKDIR <工作目录路径>
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:
USER <用户名>[:<用户组>]
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
格式:
ONBUILD <其它指令>
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
LABEL = = = …
比如我们可以添加镜像的作者:
LABEL org.opencontainers.image.authors=“runoob”
Registry 是一个开源的,无状态的(stateless),高可扩展的(highly scalable)服务器端应用,用来存储和获取你的分布式 Docker 镜像。
Registry 是一个存储(storage)和内容分发(content delivery)系统,持有命名的(named)Docker 镜像,通过使用不同的标签版本来区分。
$ docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --restart=always --name registry registry
修改 daemon.json 文件
vim /etc/docker/daemon.json
{
“registry-mirrors”: [“https://yy28v837.mirror.aliyuncs.com”],
“insecure-registries”:[“192.168.243.128:5000”]
}
registry-mirrors 是配置的国内下载镜像的地址,因为默认拉取镜像是从国外地址拉取,导致下载镜像速度非常慢。
insecure-registries:[“宿主机ip:容器端口号”],配置安全端口
systemctl restart docker
docker start localregistry
docker tag mynginx 192.168.243.128:5000/mynginx
docker restart localregistry
docker push 宿主机ip:私服容器端口号/镜像名
私服仓库部署在 192.168.243.128 现在用192.168.243.129 服务器拉取私服仓库中的镜像
{
“insecure-registries”:[“192.168.243.128:5000”]
}
systemctl restart docker
docker run --name mynginx -p 80:80 -d 192.168.243.128:5000/mynginx
本机安装并启动docker后会多一个docker0的网卡,可以理解为一个交换机。每启动一个容器,就会创建一个虚拟网卡和命名空间(vethX),容器和主机通过交换机通讯。
容器之间通过namespace隔离,隔离为两端,一端放在容器内部充当虚拟网卡,另一端放在宿主机上进行联通。不同容器间通过docker0网桥进行通讯
-dns 用于指定启动容器的DNS
-net 用于指定网络的通讯方式,有四个值
在同一个宿主机内,不同的docker容器默认工作在同一个网络域名命名空间内
查看当前可用网络类型:
创建新的网络类型:docker network create -d 类型 网络空间名称
类型包括两种
- overlay
- bridge
指定网络空间启动容器
这样不同的容器就通过不同的网络空间实现隔离
[root@centos01 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens32
<!--修改docker宿主机物理网卡桥接到网桥网卡br0-->
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
NAME=ens32
DEVICE=ens32
ONBOOT=yes
BRIDGE=br0 <!--添加此行-->
[root@centos01 ~]# cp /etc/sysconfig/network-scripts/ifcfg-ens32 /etc/sysconfig/network-scripts/ifcfg-br0
<!--创建并生成br0网桥-->
[root@centos01 ~]# vim /etc/sysconfig/network-scripts/ifcfg-br0
TYPE=Bridge <!--修改此行-->
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
NAME=br0 <!--修改名字-->
DEVICE=br0 <!--修改名字-->
ONBOOT=yes
IPADDR=192.220.130.10 <!--添加宿主机IP地址-->
NETMASK=255.255.255.0
[root@centos01 ~]# systemctl restart network
[root@centos01 ~]# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.220.130.10 netmask 255.255.255.0 broadcast 192.168.100.255
br-0c69de4672ec: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
br-35687468c903: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.19.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 00:0c:29:18:d3:26 txqueuelen 1000 (Ethernet)
ens34: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::4ad2:dd37:4341:5d8e prefixlen 64 scopeid 0x20<link>
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
veth7b0bb5f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::ccd3:86ff:fee6:5725 prefixlen 64 scopeid 0x20<link>
veth7e0f471: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::684c:fdff:fe13:b436 prefixlen 64 scopeid 0x20<link>
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
[root@centos01 ~]# yum -y install git
[root@centos01 ~]# git clone https://github.com/jpetazzo/pipework
<!--下载docker容器网络管理工具pipework-->
[root@centos01 ~]# cp pipework/pipework /usr/local/bin/
[root@centos01 ~]# chmod +x /usr/local/bin/pipework
[root@centos01 ~]# docker run -d --name centos6.703 --network=none hub.c.163.com/public/centos:6.7-tools
<!--通过镜像运行容器-->
adea0ad48bdde947ec595382d96cba06eb6522ec046e9b3c7bfcb1edb5c84545
[root@centos01 ~]# pipework br0 centos6.703 192.168.100.101/24
<!--给centos6.703容器配置IP地址-->
[root@centos01 ~]# docker exec -it centos6.703 /bin/bash
[root@adea0ad48bdd /]# ifconfig
eth1 Link encap:Ethernet HWaddr FA:3A:9D:ED:C0:FF
inet addr:192.168.100.101 Bcast:192.168.100.255 Mask:255.255.255.0
[root@adea0ad48bdd /]# ping 192.168.220.130
PING 192.168.100.10 (192.168.220.130) 56(84) bytes of data.
64 bytes from 192.168.220.130: icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from 192.168.220.130: icmp_seq=2 ttl=64 time=0.097 ms
64 bytes from 192.168.220.130: icmp_seq=3 ttl=64 time=0.039 ms
Docker镜像由多个只读层叠加而成,启动容器时,Docker镜像会加载只读镜像层并在镜像顶部添加一个读写层。
如果运行中的容器修改了一个已经存在的文件,那么该文件会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,即写时复制的机制
docker容器关闭或重启,其数据不受影响。但是删除docker容器后,其改变的数据将全部丢失。
综上所述,docker容器存在的问题如下几点
- 卷是容器上的一个目录或多个目录,此类目录可以绕过联合文件系统,与宿主机上的某目录绑定
- 卷可以在运行容器时即完成创建与绑定操作。当然,前提是拥有对应的声明
- 卷的初衷就是数据持久化
Docker-managed volume:需要人为设置,一旦引导转换为容器后,docker容器会字型管理。一般存在于/var/lib/docker下。
默认情况下docker容器是没有资源(内存、CPU)限制的,docker进程会尽可能榨干系统资源。正式的生产环境中容器资源都是会做限制的
Linux系统中经常有个需求就是希望能限制某个或者某些进程的所能使用的系统资源。比如:有分配好的特定比例的cpu时间,IO时间,可用内存大小等。于是就出现了cgroup的概念,cgroup就是control group,最初由google的工程师提出,后来被整合进Linux内核中。
Cgroup是Linux内核提供的一种可以限制、记录、隔离进程组所使用的物理资源的机制。它是将任意进程进行分组化管理的Linux内核功能。cgroup本身提供将进程进行分组化管理的功能和接口的基础结构