Docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
一个完整的Docker有以下几个部分组成:
DockerClient客户端
Docker Daemon守护进程
Docker Image镜像
DockerContainer容器 [2]
docker常用命令
docker info #查看docker信息i
docker load -i game2048.tar #导入镜像
docker rmi vm1 #删除镜像
docker run --name -d vm1 game2048 #创建并启动容器 -d 打入后台
docker run -it --name vm2 ubuntu bash
docker ps -a #查看所有容器
docker stats vm1 #查看容器资源使用率
docker attach vm1 #连接容器
docker inspect vm1 #查看镜像/容器信息
docker kill vm1 #杀掉容器
docker stop vm1 #停止容器
docker start vm1 #启动容器
docker restart vm #重启容器
docker pause/unpause vm1 #暂停/恢复容器
docker diff vm1 #查看容器修改
docker rm vm1 #删除容器, -f 强制删除
docker rm `docker ps -aq` #删除所有容器 docker ps -aq获取容器id
docker container prune #删除所有已关闭的容器
docker exec #在容器外执行指令
docker logs vm1 #查看在容器中执行的所有操作
docker top vm1 #查看容器进程
docker export vm1 > vm1.tar #导出容器
docker import vm1.tar image #导入容器为镜像image
docker history game2048:latest #查看历史
添加docker仓库
www.aliyun.com
控制台–>管理控制台–>产品与服务–>容器镜像服务–>镜像加速器–>CentOS
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://we0yv7zd.mirror.aliyuncs.com"]
}
systemctl daemon-reload
systemctl restart docker
docker search nginx #查找镜像
docker pull nginx #拉取镜像
docker run -d --name vm1 -p 8080:80 nginx # 创建并启动容器,-p 端口映射 8080物理机端口,80 容器端口
mkdir /tmp/docker
vim /tmp/docker/index.html
server1
docker cp index.html vm1:/usr/share/nginx/html #将页面文件拷到nginx默认发布目录下
访问物理机ip:8080
每次修改页面文件都需要拷到容器中,可以将将物理机的一个目录挂载到nginx默认发布目录下
docker run -d --name vm1 -p 8080:80 -v /tmp/docker/website/:/usr/share/nginx/html nginx
这样直接在物理机中直接修改就可以了
vim website/index.html
server1
server1
server1
server1
server1
server1
浏览器查看
数据卷容器
docker run -it --name vm2 -v /tmp/docker/dvd.repo:/etc/yum.repos.d/dvd.repo:ro -v /tmp/docker/data1:/data1 -v /tmp/docker/data2:/data2 rhel7 bash
这样每次创建容器比较麻烦,可以先创建一个数据卷容器,再由数据卷容器来新建容器
docker create --name datavol -v /tmp/docker/dvd.repo:/etc/yum.repos.d/dvd.repo:ro -v /tmp/docker/data1:/data1 -v /tmp/docker/data2:/data2 rhel7 bash
docker run -it --volumes-from datavol --name vm3 rhel7 bash
在vm3容器中安装httpd
yum install -y httpd
/usr/sbin/httpd #启动服务
vi /var/www/html/index.html #编辑页面文件
www.westos.org
物理机中访问查看
docker inspect vm3 #查看容器ip
curl 172.17.0.3
网络管理
docker rm -f docker ps -aq
Docker 在启动时会创建一个虚拟网桥 docker0,默认地址为 172.17.0.1/16, 容器启动后都会被桥接到 docker0 上,并自动分配到一个 IP 地址
docker容器的四种网络模式:bridge 桥接模式、host 模式、container 模式和 none 模式
启动容器时可以使用 --net 参数指定,默认是桥接模式。
Bridge网络模式
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 模式由于是在三层
网络上的实现手段,故肯定会影响网络的传输效率。
Host网络模式
host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。当然,有这样的方便,肯定会损失部分其他的特性,最明显的是 Docker Container 网络环境隔离性的弱化,即容器不再拥有隔离、独立的网络栈。另外,使用 host 模式的 Docker Container 虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用;另外,容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网络模式容器的端口映射。
docker run -it --name vm2 --net host ubuntu
Container 网络模式
(1) 查找 other container(即需要被共享网络环境的容器)的网络 namespace;
(2) 将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,使用other container 的 namespace。
Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,它并没有改善容器与宿主机以外世界通信的情况。
docker run -it --name vm3 --net container:vm1 ubuntu #共享vm1网络
None 网络模式
网络环境为 none,即不为 Docker Container 任何的网络环境。一旦 Docker Container 采用了none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none 模式为 Docker Container 做了极少的网络设定,但是俗话说得好“
少即是多”,在没有网络配置的情况下,作为 Docker 开发者,才能在这基础做其他无限多可能的网络定制开发。这也恰巧体现了 Docker 设计理念的开放
docker run -it --name vm4 --net none ubuntu
在 none 网络模式下分配固定 ip:
netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟化出多个网络环境,目前 netns 在 lxc 容器中被用来为容器提供网络。使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则等都是独立的,就好像进入了另外一个网络一样。
ip netns list
ip netns add test
ip netns del test
docker inspect vm4 |grep Pid #查看vm4容器Pid
ln -s /proc/26520/ns/net /var/run/netns/26520
ip netns list
ip addr #查看
ip link set up veth0
ip link set up veth1
brctl addif docker0 veth0
ip link set veth1 netns 26520
在vm4容器中查看
ip netns exec 26520 ip link set veth1 name eth0 #修改网络借口名称
ip netns exec 26520 ip link set up eth0 #激活网卡
ip netns exec 26520 ip addr add 172.17.0.100/24 dev eth0 #添加ip
在vm4容器中查看
ip netns exec 26520 ip route add default via 172.17.0.1 #添加网关
在vm4容器中查看
Docker 安全
docker rm -f `docker ps -aq`
设置特权级运行的容器:--privileged=true
docker run -it --name vm1 --privileged=true ubuntu
不开启此参数,root就相当于普通用户,是修改不了ip的
docker inspect -f {{.HostConfig.Privileged}} vm1
Docker容器间互联
–link 参数可以在不映射端口的前提下为两个容器间建立安全连接, --link 参数可以连接一个或多个容器到将要创建的容器。
–link 参数的格式为 --link name:alias,其中 name 是要链接的容器的名称,alias 是这个连接的别名。
docker run -d --name vm3 nginx
docker run -it --name vm4 --link vm3:nginx ubuntu
容器资源管理
docker rm -f `docker ps -aq`
cd /sys/fs/cgroup/cpu
docker run -d --name vm1 nginx #创建一个容器
ab -c 100 -n 10000000 http://172.17.0.2/index.html #压力测试
使用top查看发现 ad和nginx占用cpu 接近100%
docker run -d --name vm2 --cpu-quota 10000 nginx
cd e42d1ca0da129f87dd0c5857cf19558245a3462c52026e95a0ad44211ec31514/
cat cpu.cfs_period_us
cat cpu.cfs_quota_us #文件中数值变为10000,-1为不限制
ab -c 100 -n 10000000 http://172.17.0.3/index.html #压力测试
此时ad和nginx 的cpu占用只有10%
Dockerfile 编写
apache
cd /tmp/docker/
vim Dockerfile
FROM rhel7 #指定基础镜像,要确保有此镜像
ENV HOSTNAME server1 #设置容器主机名
EXPOSE 80 #暴露容器端口
COPY dvd.repo /etc/yum.repos.d/dvd.repo #拷贝文件到指定目录
RUN yum install -y httpd && yum clean all #镜像操作命令
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] #镜像启动命令,默认只能启动一条
vim dvd.repo
[dvd]
name=rhel7.3
baseurl=http://172.25.254.24/rhel7.3
gpgcheck=0
docker build -t rhel7:v1 .
提示报错:Rpmdb checksum is invalid: dCDPT(pkg checksums): systemd-libs.x86_64 0:219-30.el7 - u
需要修改Dockerfile文件
vim 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
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
测试:
docker run -d --name vm1 rhel7:v1 #使用新建的镜像创建一个容器
docker inspect vm1 | grep IP # 查看vm1容器ip
浏览器访问
Apache测试页面
nginx源码包
docker rm -f vm1
vim Dockerfile
FROM rhel7
EXPOSE 80
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.14.0.tar.gz /mnt
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel make && yum clean all
WORKDIR /mnt/nginx-1.14.0 # 指定工作目录
RUN ./configure --prefix=/usr/local/nginx --with-threads --with-file-aio --with-http_stub_status_module
RUN make && make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t rhel7:v2 .
docker run -d --name vm1 rhel7:v2
docker inspect vm1 | grep IP
浏览器访问
镜像压缩
方法:减少层数–>多阶段压缩–>减小base镜像
vim Dockerfile.back
FROM rhel7
EXPOSE 80
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.14.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.14.0
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make && yum clean all && ./configure --prefix=/usr/local/nginx --with-threads --with-file-aio --with-http_stub_status_module && make && make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
vim Dockerfile
FROM nginx as base
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG Asia/Shanghai
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base
COPY --from=base /opt /
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
docker build -t nginx:v1 .
docker run -d --name vm2 nginx:v1
docker ps
私有仓库
当时用ip上传时因为是https所以会报错
docker tag rhel7 172.25.254.24:5000/rhel7
docker push 172.25.254.24:5000/rhel7
此时需要指定一个私有仓库
vim /etc/docker/daemon.json
{
"insecure-registries": ["172.25.254.24:5000"]
}
systemctl restart docker.service
docker start registry
docker push 172.25.254.24:5000/rhel7
添加https证书
cd /tmp/docker/
mkdir certs
openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt
添加本地域名解析
vim /etc/hosts
私有仓库主机ip westos.org
docker run -d --name registry -v `pwd`/certs:/certs -v /tmp/docker/registry:/var/lib/registry -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.3.1 # 此命令需在创建证书的所在目录运行
cp certs/domain.crt /etc/docker/certs.d/westos.org/ca.crt #certs.d和westos.org目录需要自己创建
docker tag ubuntu:latest westos.org/ubuntu
docker push westos.org/ubuntu
登陆认证
docker rm -f 6c4a0bc54af3 #删除之前的仓库
mkdir auth
docker run --rm --entrypoint htpasswd registry:2.3.1 -Bbn admin westos > auth/htpasswd #生成认证用户名和密码
docker run -d --name registry -v `pwd`/certs:/certs -v /tmp/docker/registry:/var/lib/registry -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.3.1
现在不能直接在仓库中上传镜像了
docker tag rhel7:v1 westos.org/rhel7:v1
docker push westos.org/rhel7:v1
需要登陆认证
docker login westos.org #用户名和密码是刚才生成的
docker push westos.org/rhel7:v1 #登陆之后就可以上传了
登陆之后在root主目录下生成一个.docker目录
config.json文件记录了认证信息,这样我们之后就不需要再次登陆认证了
Docker Compose
下载docker-compose二进制程序
cp docker-compose-Linux-x86_64-1.22.0 /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
导入haproxy镜像
docker load -i haproxy.tar
cd /tmp/docker/
mkdir compose
cd compose/
vim docker-compose.yml
web1:
image: nginx
expose:
- 80
web2:
image: nginx
expose:
- 80
haproxy:
image: haproxy
volumes:
- ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
links:
- web1
- web2
ports:
- "80:80"
expose:
- 80
mkdir haproxy
cd haproxy/
vim 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 a web1:80 check
server b web2:80 check
为了避免端口冲突,关闭httpd
cd ..
docker-compose up
为了方便观察结果,再打开一个终端编写页面拷贝到容器中
docker cp index.html compose_web1_1:/usr/share/nginx/html/
docker cp index.html compose_web2_1:/usr/share/nginx/html/
docker inspect compose_haproxy_1 |grep IP #查看haproxy容器ip
curl 172.17.0.5 #实现负载均衡 ,也可以用docker主机ip测试