Docker 是一个开源的应用容器引擎,主要利用 linux 内核 namespace 实现沙盒隔离,用cgroup 实现资源限制。
目录:
yum install docker-engine-17.03.1.ce-1.el7.centos.x86_64.rpm docker-engine-selinux-17.03.1.ce-1.el7.centos.noarch.rpm -y
开启服务
systemctl start docker
docker run -it --name vm1 ubuntu bash #创建容器
docker ps -a #查看容器状态
docker attach vm1 #连接容器
docker top vm1 #查看容器进程
docker logs vm1 #查看容器指令输出 -f 参数可以实时查看
docker inspect vm1 #查看容器详情
docker stats vm1 #查看容器资源使用率
docker diff vm1 #查看容器修改
docker run -d --name vm1 ubuntu bash -c "while true; do echo westos; sleep 1; done" #后台运行
docker stop vm1 #停止容器
docker start vm1 #启动容器
docker kill vm1 #强制干掉容器
docker restart vm1 #重启容器
docker pause/unpause vm1 #暂停/恢复容器
docker rm vm1 #删除容器
docker export vm1 > vm1.tar #导出容器
docker import vm1.tar image #导入容器为镜像 image
镜像用来创建容器,是容器的只读模板,默认可以从 docker hub 上下载。docker 的镜像是增量修改,每次创建新的镜像都会在父镜像上构建一个增量的层,基于 AUFS 技术。
docker search #查询镜像
docker pull #拉取镜像
docker push #推送镜像
docker images #查看本地镜像
docker save ubuntu > ubuntu.tar #导出镜像
docker load -i ubuntu.tar #导入镜像
docker commit #更新镜像
docker rmi #删除镜像
开启一个2048游戏容器
docker load -i *.tar
docker images
docker images game2048
docker run -d --name vm1 game2048
docker inspect vm1
在https://www.aliyun.com/注册阿里云帐号
在https://cr.console.aliyun.com/cn-hangzhou/mirrors获得自己的镜像加速器地址
配置镜像加速器
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://1tade4qz.mirror.aliyuncs.com"]
}
systemctl daemon-reload
systemctl restart docker
直接拉取镜像
docker search nginx
docker pull nginx
测试nginx镜像是否可用
mkdir -p /tmp/docker/web
docker run -d --name vm2 -v /tmp/docker/web:/usr/share/nginx/html nginx
vim /tmp/docker/web/index.html
nginx
docker cp index.html vm2:/usr/share/nginx/html/
bridge 桥接模式、host 模式、container 模式和 none 模式
启动容器时可以使用 –net 参数指定,默认是桥接模式
以下是 docker 网络初始化的过程
Bridge 桥接模式的实现步骤主要如下:
(1) Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为
veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将
报文传输给另一方。
(2) Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
(3) Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。
如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到
Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网
络环境的隔离性。
bridge 桥接模式下的 Docker Container 在使用时,并非为开发者包办了一切。最明显的是,
该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致
的结果是宿主机以外的世界不能直接和容器进行通信。虽然 NAT 模式经过中间处理实现了
这一点,但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器
内部服务的访问者需要使用服务发现获知服务的外部端口等。另外 NAT 模式由于是在三层
网络上的实现手段,故肯定会影响网络的传输效率。
打开一个vm1
docker run -it --name vm1 --volumes-from datavol rhel7 bash
docker stop vm1
host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用
宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公
有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。当然,
有这样的方便,肯定会损失部分其他的特性,最明显的是 Docker Container 网络环境隔离性
的弱化,即容器不再拥有隔离、独立的网络栈。另外,使用 host 模式的 Docker Container 虽
然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱
化,该容器会与宿主机共享竞争网络栈的使用;另外,容器内部将不再拥有所有的端口资
源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网
络模式容器的端口映射。
docker run -it --name vm2 --net host ubuntu
(1) 查找 other container(即需要被共享网络环境的容器)的网络 namespace;
(2) 将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,使用
other container 的 namespace。
Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,它并没有改善容器与宿主机以外世界通信的情况。
docker run -it --name vm4 --net container:vm3 ubuntu #vm4的网络环境与vm3一样
网络环境为 none,即不为 Docker Container 任何的网络环境。一旦 Docker Container 采用了
none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none 模式为 Docker Container 做了极少的网络设定,但是俗话说得好“少即是多”,在没有网络配置的情况下,作为 Docker 开发者,才能在这基础做其他无限多可能的网络定制开发。这也恰巧体现了Docker 设计理念的开放。
docker run -it --name vm4 --net none ubuntu bash
netns:
netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟
化出多个网络环境,目前 netns 在 lxc 容器中被用来为容器提供网络。使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则
等都是独立的,就好像进入了另外一个网络一样。
例如:创建一个test网络
ps ax
cd /proc/15581/ns
ip netns add test
ip netns list
cd /var/run #查看创建的网络
cd netns/
ls
ip netns del test #删除网络
给容器添加eth0
ln -s /proc/15581/ns/net /var/run/netns/15581
ip netns list
15581
ip link add name veth0 type veth peer name veth1
brctl addif docker0 veth0
ip link set up veth0 #激活veth0
ip link set up veth1 #激活veth1
ip link set veth1 netns 15581
将 veth1命名为eth0
ip netns exec 15581 ip link set veth1 name eth0
给vm4添加ip、网关
ip netns exec 15581 ip link set up dev eth0 #激活eth0
ip netns exec 15581 ip addr add 172.17.0.31/24 dev eth0 #给eth0增加ip
ip netns exec 15581 ip route add default via 172.17.0.1 #给vm4添加网关
link 参数可以在不映射端口的前提下为两个容器间建立安全连接, –link 参数可以连接一个
或多个容器到将要创建的容器。
–link 参数的格式为 –link name:alias,其中 name 是要链接的容器的名称,alias 是这个连
docker run -d --name vm1 -p 8080:80 nginx
iptables -t nat -nL
docker run -it --name vm2 --link vm1:nginx ubuntu
root@aa72a211edb9:/# env
root@aa72a211edb9:/# ping nginx
指定容器运行的用户
该用户将作为后续的 RUN 命令执行的用户。比如提供 hadoop 服务的容器通常会使用 hadoop 用户来启动服务。
命令使用方式,例如使用 shiyanlou 用户来执行后续命令:
USER shiyanlou
对外连接端口号
EXPOSE 命令。
例如在镜像操作部分增加下面一句:
EXPOSE 80
向镜像中增加文件
向镜像中添加文件有两种命令:COPY 和 ADD。
COPY 命令可以复制本地文件夹到镜像中:
COPY website /var/www/html
ADD 命令支持添加本地的 tar 压缩包到容器中指定目录,压缩包会被自动解压为目录,也可以自动下载 URL 并拷贝到镜像,例如:
ADD html.tar /var/www
ADD http://www.westos.org/html.tar /var/www
CMD 与 ENTRYPOINT
ENTRYPOINT 容器启动后执行的命令,让容器执行表现的像一个可执行程序一样,与CMD 的 区 别 是 不 可 以 被 docker run 覆 盖 , 会 把 docker run 后 面 的 参 数 当 作 传 递 给ENTRYPOINT 指令的参数。Dockerfile 中只能指定一个 ENTRYPOINT,如果指定了很多,只 有 最 后 一 个 有 效 。 docker run 命 令 的 -entrypoint 参 数 可 以 把 指 定 的 参 数 继 续 传 递 给ENTRYPOINT。
vim /tmp/docker/Dockerfile
FROM rhel7
ENV HOSTNAME server1
EXPOSE 80
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb && yum install -y httpd && yum clean all
VOLUME ["/var/www/html"]
CMD ["/usr/sbin/httpd","-D","FOREGROUND"] #镜像启动命令,默认只能启动一条
配置好yum源
vim /tmp/docker/dvd.repo
[dvd]
name=rhel7.3
baseurl=http://172.25.31.250/rhel7.3
gpgcheck=0
构建镜像 rhel7:v1
docker build -t rhel7:v1 .
测试
docker run -d --name vm1 rhel7:v1
docker inspect vm1
浏览器访问172.17.0.2,http已开启
将ssh服务件如镜像
cd /tmp/docker
mkdir ssh
cd ssh/
vim Dockerfile
FROM rhel7
ENV HOSTNAME server2
EXPOSE 22
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb && yum install -y openssh-server openssh-clients && yum clean all && ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -N "" && ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N "" && ssh-keygen -q -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" && echo root:westos | chpasswd
CMD ["/usr/sbin/sshd","-D"]
构建镜像
cp ../dvd.repo .
docker build -t rhel7:v2 .
测试
docker run -d --name vm2 rhel7:v2
docker ps
docker run -it --name vm2 rhel7:v2 bash
bash-4.2# ssh localhost
CMD 如果只有一个命令,那如果我们需要运行多个服务怎么办呢?最好的办法是分别在不
同的容器中运行,通过 link 进行连接,比如先前实验中用到的 web,app,db 容器。如果一
定要在一个容器中运行多个服务可以考虑用 Supervisord 来进行进程管理,方式就是将多个
启动命令放入到一个启动脚本中。
编辑Dockerfile
vim /tmp/docker/Dockerfile
FROM rhel7
EXPOSE 80 22
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb && yum install -y httpd openssh-server openssh-clients supervisor && yum clean all && ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -N "" && ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N "" && ssh-keygen -q -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" && echo root:westos | chpasswd
COPY supervisord.conf /etc/supervisord.conf
CMD ["/usr/bin/supervisord"]
配置好yum源
vim /tmp/docker/dvd.repo
[dvd]
name=rhel7.3
baseurl=http://172.25.31.250/rhel7.3
gpgcheck=0
[docker]
name=docker
baseurl=http://172.25.31.250/pub/docker
gpgcheck=0
编辑supervisor配置文件
vim /tmp/docker/supervisord.conf
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:httpd]
command=/usr/sbin/httpd
构建镜像
cd /tmp/docker/
docker build -t rhel7:v3 .
测试httpd服务和ssh服务是否开启
docker run -d --name vm1 -v /tmp/docker/web/:/var/www/html rhel7:v3
curl 172.17.0.2
ssh -l root 172.17.0.2
对写入速度做限制–device-write-bps
docker run --rm -it --device-write-bps /dev/sda:10M ubuntu
root@fb2a9ca40410:/# dd if=/dev/zero of=testfile bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 9.95477 s, 10.5 MB/s
root@fb2a9ca40410:/#
Docker 官方已经把仓库封装为镜像,直接通过启动容器就可以部署完成仓库:
docker run -d --name registry -p 5000:5000 -v /opt/registry:/var/lib/registry registry:2.3.1
目录 /var/lib/registry 是仓库存放镜像的位置。除了使用数据卷做镜像存储之外,Registry还支持将镜像存储到 亚马逊的 S3,OpenStack 的 Swift/Glance 等存储后端。
docker tag nginx localhost:5000/nginx
镜像的命名规则 localhost:5000/nginx 中,localhost:5000 表示 Registry 的地址和端口。
推送镜像到 localhost:5000 仓库
docker push localhost:5000/nginx:latest
docker rmi localhost:5000/nginx:latest
拉取镜像到本地
docker pull localhost:5000/ngin
默认 docker 仓库远程推送拉取需要 TLS 加密支持,走的是 https 协议,如需开启 http 方式,需要做如下修改:
vim /etc/systemd/system/docker.service
ExecStart=/usr/bin/docker daemon -H fd:// -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
--bip 192.168.0.1/24 --insecure-registry 172.25.31.250:5000
systemctl daemon-reload
systemctl restart docker
或
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://1tade4qz.mirror.aliyuncs.com"]
"insecure-registry": ["172.25.31.250:5000"] #添加这一行
}
默认 docker 仓库远程推送拉取需要 TLS 加密支持,走的是 https 协议
给docker仓库加密
cd /tmp/docker/
mkdir certs
openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt
docker run -d --restart=always --name registry -v `pwd`/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key -p 443:443 registry:2
docker tag nginx westos.org/nginx
cd /etc/docker/
mkdir -p certs.d/westos.org
cd certs.d/westos.org/
cp /tmp/docker/certs/domain.crt ./ca.crt
docker push westos.org/nginx
给仓库增加认证
cd /tmp/docker/
mkdir auth
docker run --entrypoint htpasswd registry:2 -Bbn wyh westos > auth/htpasswd #设置用户名和密码
cat auth/htpasswd
docker run --entrypoint htpasswd registry:2 -Bbn admin admin >> auth/htpasswd
运行仓库
docker run -d --restart=always --name registry -v `pwd`/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key -v `pwd`/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd -p 443:443 registry:2
登陆仓库,上传镜像
docker login -u wyh -p westos westos.org
docker push westos.org/nginx
cd .docker/
ls
cat config.json
docker run 在创建容器时使用 -v 参数可以挂载一个或多个数据卷到当前运行的容器中,-v
的作用是将宿主机上的目录作为容器的数据卷挂载到容器中,使宿主机和容器之间可以共
享一个目录
不指定挂载位置的话容器会自己创建目录挂载
docker run -d --name vm1 -v /usr/share/nginx/html nginx
docker inspect vm1 | grep vol
cd /var/lib/docker/volumes/7c7cbd800d309f3d779b3169c41df72bcd963a8523526510c3ea1001f245c11a/_data
ls
编辑Dockerfile文件
mkdir /tmp/docker/test
vim /tmp/docker/test/Dockerfile
FROM rhel7
ADD html.tar /usr/share
VOLUME ["/usr/share/nginx/html"]
因为rhel7镜像中没有/usr/share/nginx/html,所以打包目录用在Dockerfile中用ADD命令添加
mkdir /tmp/docker/test/nginx
mkdir /tmp/docker/test/nginx/html
vim /tmp/docker/test/nginx/html/index.html #为方便测试编辑一个首页文件
tar -cf html.tar nginx
tar tf html.tar
docker build -t rhel7:v4 .
创建数据卷容器
docker create --name vol rhel7:v4 bash
利用数据卷容器挂载
docker run -d --name vm1 --volumes-from vol nginx
测试
curl 172.17.0.2
编写docker-compose.yml文件
cd /tmp/docker/
mkdir compose
cd compose/
vim docker-compose.yml
apache:
image: rhel7:v1
expose:
- 80
volumes:
- ./web:/var/www/html
nginx:
image: nginx
expose:
- 80
haproxy:
image: haproxy
volumes:
- ./haproxy:/usr/local/etc/haproxy
links:
- apache
- nginx
ports:
- "8080:80"
expose:
- 80
编辑apache首页文件
cp -r web/ compose/
编写haproxy配置文件
cd compose/
mkdir haproxy
vim haproxy/haproxy.cfg
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
stats uri /status
frontend balancer
bind 0.0.0.0:80
default_backend web_backends
backend web_backends
balance roundrobin
server weba apache:80 check
server webb nginx:80 check
运行
docker-compose up
创建集群
docker swarm init
docker swarm join \
--token SWMTKN-1-24xykxp45mjlfxlbz9b97e7o66ktaci1n23jl0mk5pmg1xqtd6-cc37q5yzqe49ippms760dcity \
172.25.31.1:2377
查看集群
docker node ls
让nginx在集群中运行
docker service create --name nginx --publish 80:80 --replicas 3 westos.org/nginx
加监控
给自己的私有仓库中加入westos.org/visualizer镜像,在任一节点执行如下命令
docker service create --name=viz --publish=8080:8080/tcp --constraint=node.role==manager --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock westos.org/visualizer
为方便测试给每个节点的nginx中加入一个首页
[root@server1 ~]# echo server1 > index.html
[root@server1 ~]# docker container cp index.html nginx.2.n39h34ussexn8669hkz2bq954:/usr/share/nginx/html
[root@server2 ~]# echo server2 > index.html
[root@server2 ~]# docker container cp index.html nginx.3.xrfdd8dqqtbasoa9eyu3v7kq7:/usr/share/nginx/html
[root@server3 ~]# echo server3 > index.html
[root@server3 ~]# docker container cp index.html nginx.1.kkaqglyi1isos87p0lrzxfrki:/usr/share/nginx/html
更新
docker service scale nginx=30 #开启30个nginx集群
docker service update --image westos.org/game2048 --update-parallelism 3 --update-delay 10s nginx #经nginx更新为game2048