8 Docker V2 实用版
你将学到哪些
- Docker相关
- 如何使用Dockerfile快速构建镜像
- Docker镜像、容器、仓库的常用操作
- Docker容器的网络(Bridge下的SNAT、DNAT)
- Dockerfile
- Docker实战 python+uwsgi+nginx+mysql
安装
配置宿主机网卡转发
## 配置网卡转发,看值是否为1
$ sysctl -a |grep -w net.ipv4.ip_forward
net.ipv4.ip_forward = 1
## 若未配置,需要执行如下
$ cat <<EOF > /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
EOF
$ sysctl -p /etc/sysctl.d/docker.conf
Yum安装配置docker
## 下载阿里源repo文件
$ curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
$ curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
$ yum clean all && yum makecache
## yum安装
$ yum install -y docker-ce
## 查看源中可用版本
$ yum list docker-ce --showduplicates | sort -r
## 安装指定版本
##yum install -y docker-ce-18.09.9
## 配置源加速
## https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
mkdir -p /etc/docker
vi /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://8xpk5wnt.mirror.aliyuncs.com",
"https://dockerhub.azk8s.cn",
"https://registry.docker-cn.com",
"https://ot2k4d59.mirror.aliyuncs.com/"
]
}
## 设置开机自启
systemctl enable docker
systemctl daemon-reload
## 启动docker
systemctl start docker
## 查看docker信息
docker info
## docker-client
which docker
## docker daemon
ps aux |grep docker
核心要素及常用操作详解

三大核心要素:镜像(Image)、容器(Container)、仓库(Registry)
(先整体看下流程,再逐个演示)
镜像(Image)
打包了业务代码及运行环境的包,是静态的文件,不能直接对外提供服务。
容器(Container)
镜像的运行时,可以对外提供服务。本质上讲是利用namespace和cgroup等技术在宿主机中创建的独立的虚拟空间。
仓库(Registry)
- 公有仓库,Docker Hub,阿里,网易...
- 私有仓库,企业内部搭建
- Docker Registry,Docker官方提供的镜像仓库存储服务
- Harbor, 是Docker Registry的更高级封装,它除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能
- 镜像访问地址形式 registry.devops.com/demo/hello:latest,若没有前面的url地址,则默认寻找Docker Hub中的镜像,若没有tag标签,则使用latest作为标签
- 公有的仓库中,一般存在这么几类镜像
- 操作系统基础镜像(centos,ubuntu,suse,alpine)
- 中间件(nginx,redis,mysql,tomcat)
- 语言编译环境(python,java,golang)
- 业务镜像(django-demo...)
操作演示

-
解压离线包
为了保证镜像下载的速度,因此提前在一台节点下载了离线镜像包,做解压:
$ tar zxf registry.tar.gz -C /opt $ ll /opt/registry-data total 25732 drwxr-xr-x 3 root root 4096 Apr 9 20:11 registry -rw------- 1 root root 26344448 Apr 9 22:15 registry-v2.tar -
查看所有镜像:
$ docker images
- 拉取镜像:
$ docker pull nginx:alpine
- 如何唯一确定镜像:
- image_id
- repository:tag
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine 377c0837328f 2 weeks ago 19.7MB
-
导出镜像到文件中
$ docker save -o nginx-alpine.tar nginx:alpine -
从文件中加载镜像
$ docker load -i nginx-alpine.tar -
部署镜像仓库
https://docs.docker.com/registry/
## 使用docker镜像启动镜像仓库服务 $ docker run -d -p 5000:5000 --restart always -v /opt/registry-data/registry:/var/lib/registry --name registry registry:2 ## 默认仓库不带认证,若需要认证,参考https://docs.docker.com/registry/deploying/#restricting-access假设启动镜像仓库服务的主机地址为172.21.32.6,该目录中已存在的镜像列表:
现镜像仓库地址 原镜像仓库地址 172.21.32.6:5000/coreos/flannel:v0.11.0-amd64 quay.io/coreos/flannel:v0.11.0-amd64 172.21.32.6:5000/mysql:5.7 mysql:5.7 172.21.32.6:5000/nginx:alpine nginx:alpine 172.21.32.6:5000/centos:centos7.5.1804 centos:centos7.5.1804 172.21.32.6:5000/elasticsearch/elasticsearch:7.4.2 docker.elastic.co/elasticsearch/elasticsearch:7.4.2 172.21.32.6:5000/fluentd-es-root:v1.6.2-1.0 gcr.io/google_containers/fluentd-elasticsearch:v2.4.0 172.21.32.6:5000/kibana/kibana:7.4.2 docker.elastic.co/kibana/kibana:7.4.2 172.21.32.6:5000/kubernetesui/dashboard:v2.0.0-beta5 kubernetesui/dashboard:v2.0.0-beta5 172.21.32.6:5000/kubernetesui/metrics-scraper:v1.0.1 kubernetesui/metrics-scraper:v1.0.1 172.21.32.6:5000/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 -
推送本地镜像到镜像仓库中
$ docker tag nginx:alpine localhost:5000/nginx:alpine $ docker push localhost:5000/nginx:alpine ## 我的镜像仓库给外部访问,不能通过localhost,尝试使用内网地址172.21.16.3:5000/nginx:alpine $ docker tag nginx:alpine 172.21.16.3:5000/nginx:alpine $ docker push 172.21.16.3:5000/nginx:alpine The push refers to repository [172.21.16.3:5000/nginx] Get https://172.21.16.3:5000/v2/: http: server gave HTTP response to HTTPS client ## docker默认不允许向http的仓库地址推送,如何做成https的,参考:https://docs.docker.com/registry/deploying/#run-an-externally-accessible-registry ## 我们没有可信证书机构颁发的证书和域名,自签名证书需要在每个节点中拷贝证书文件,比较麻烦,因此我们通过配置daemon的方式,来跳过证书的验证: $ cat /etc/docker/daemon.json { "registry-mirrors": [ "https://8xpk5wnt.mirror.aliyuncs.com" ], "insecure-registries": [ "172.21.16.3:5000" ] } $ systemctl restart docker $ docker push 172.21.16.3:5000/nginx:alpine $ docker images # IMAGE ID相同,等于起别名或者加快捷方式 REPOSITORY TAG IMAGE ID CREATED SIZE 172.21.16.3:5000/nginx alpine 377c0837328f 4 weeks ago nginx alpine 377c0837328f 4 weeks ago localhost:5000/nginx alpine 377c0837328f 4 weeks ago registry 2 708bc6af7e5e 2 months ago -
删除镜像
docker rmi nginx:alpine -
查看容器列表
## 查看运行状态的容器列表 $ docker ps ## 查看全部状态的容器列表 $ docker ps -a -
启动容器
## 后台启动 $ docker run --name nginx -d nginx:alpine ##查看run流程# ##查看容器进程 ## 等同于在虚拟机中开辟了一块隔离的独立的虚拟空间 ## 启动容器的同时进入容器,-ti与/bin/sh或者/bin/bash配套使用,意思未分配一个tty终端 $ docker run --name nginx -ti nginx:alpine /bin/sh (注意:退出容器后,该容器会变成退出状态,因为容器内部的1号进程退出) ## 实际上,在运行容器的时候,镜像地址后面跟的命令等于是覆盖了原有的容器的CMD命令,因此,执行的这些命令在容器内部就是1号进程,若该进程不存在了,那么容器就会处于退出的状态,比如,宿主机中执行 1. echo 1,执行完后,该命令立马就结束了 2. ping www.baidu.com,执行完后,命令的进程会持续运行 $ docker run -d --name test_echo nginx:alpine echo 1,容器会立马退出 $ docker run -d --name test_ping nginx:alpine ping www.baidu.com,容器不会退出,但是因为没有加-d参数,因此一直在前台运行,若ctrl+C终止,则容器退出,因为1号进程被终止了 ## 映射端口,把容器的端口映射到宿主机中,-p <host_port>:<container_port> $ docker run --name nginx -d -p 8080:80 nginx:alpine ## 资源限制,-cpuset-cpus用于设置容器可以使用的 vCPU 核。-c,--cpu-shares用于设置多个容器竞争 CPU 时,各个容器相对能分配到的 CPU 时间比例。假设有三个正在运行的容器,这三个容器中的任务都是 CPU 密集型的。第一个容器的 cpu 共享权值是 1024,其它两个容器的 cpu 共享权值是 512。第一个容器将得到 50% 的 CPU 时间,而其它两个容器就只能各得到 25% 的 CPU 时间了。如果再添加第四个 cpu 共享值为 1024 的容器,每个容器得到的 CPU 时间将重新计算。第一个容器的CPU 时间变为 33%,其它容器分得的 CPU 时间分别为 16.5%、16.5%、33%。必须注意的是,这个比例只有在 CPU 密集型的任务执行时才有用。在四核的系统上,假设有四个单进程的容器,它们都能各自使用一个核的 100% CPU 时间,不管它们的 cpu 共享权值是多少。 $ docker run --cpuset-cpus="0-3" --cpu-shares=512 --memory=500m nginx:alpine![]()
-
容器数据持久化
## 挂载主机目录 $ docker run --name nginx -d -v /opt:/opt -v /var/log:/var/log nginx:alpine $ docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d -v /opt/mysql/:/var/lib/mysql mysql:5.7 ## 使用volumes卷 $ docker volume ls $ docker volume create my-vol $ docker run --name nginx -d -v my-vol:/opt/my-vol nginx:alpine $ docker exec -ti nginx touch /opt/my-vol/a.txt ## 验证数据共享 $ docker run --name nginx2 -d -v my-vol:/opt/hh nginx:alpine $ docker exec -ti nginx2 ls /opt/hh/ a.txt -
进入容器或者执行容器内的命令
$ docker exec -ti <container_id_or_name> /bin/sh $ docker exec -ti <container_id_or_name> hostname -
主机与容器之间拷贝数据
## 主机拷贝到容器 $ echo '123'>/tmp/test.txt $ docker cp /tmp/test.txt nginx:/tmp $ docker exec -ti nginx cat /tmp/test.txt 123 ## 容器拷贝到主机 $ docker cp nginx:/tmp/test.txt ./ -
查看容器日志
## 查看全部日志 $ docker logs nginx ## 实时查看最新日志 $ docker logs -f nginx ## 从最新的100条开始查看 $ docker logs --tail=100 -f nginx -
停止或者删除容器
## 停止运行中的容器 $ docker stop nginx ## 启动退出容器 $ docker start nginx ## 删除退出容器 $ docker rm nginx ## 删除运行中的容器 $ docker rm -f nginx -
查看容器或者镜像的明细
## 查看容器详细信息,包括容器IP地址等 $ docker inspect nginx ## 查看镜像的明细信息 $ docker inspect nginx:alpine
Django应用容器化实践
django项目介绍
-
python3 + uwsgi + nginx + mysql
-
内部服务端口8002
构建命令
$ docker build . -t ImageName:ImageTag -f Dockerfile
如何理解构建镜像的过程?
Dockerfile是一堆指令,在docker build的时候,按照该指令进行操作,最终生成我们期望的镜像
-
FROM 指定基础镜像,必须为第一个命令
格式: FROM <image> FROM <image>:<tag> 示例: FROM mysql:5.7 注意: tag是可选的,如果不使用tag时,会使用latest版本的基础镜像 -
MAINTAINER 镜像维护者的信息
格式: MAINTAINER <name> 示例: MAINTAINER Yongxin Li MAINTAINER inspur_lyx@hotmail.com MAINTAINER Yongxin Li <inspur_lyx@hotmail.com> -
COPY|ADD 添加本地文件到镜像中
格式: COPY <src>... <dest> 示例: ADD hom* /mydir/ # 添加所有以"hom"开头的文件 ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/ ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/ -
WORKDIR 工作目录
格式: WORKDIR /path/to/workdir 示例: WORKDIR /a (这时工作目录为/a) 注意: 通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行 -
RUN 构建镜像过程中执行命令
格式: RUN <command> 示例: RUN yum install nginx RUN pip install django RUN mkdir test && rm -rf /var/lib/unusedfiles 注意: RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache -
CMD 构建容器后调用,也就是在容器启动时才进行调用
格式: CMD ["executable","param1","param2"] (执行可执行文件,优先) CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数) CMD command param1 param2 (执行shell内部命令) 示例: CMD ["/usr/bin/wc","--help"] CMD ping www.baidu.com 注意: CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。 -
ENTRYPOINT 设置容器初始化命令,使其可执行化
格式: ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先) ENTRYPOINT command param1 param2 (shell内部命令) 示例: ENTRYPOINT ["/usr/bin/wc","--help"] 注意: ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令 -
ENV
格式: ENV <key> <value> ENV <key>=<value> 示例: ENV myName John ENV myCat=fluffy -
EXPOSE
格式: EXPOSE <port> [<port>...] 示例: EXPOSE 80 443 EXPOSE 8080 EXPOSE 11211/tcp 11211/udp 注意: EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口![]()
run.sh
#!/bin/bash
python3 manage.py collectstatic
uwsgi --ini ./uwsgi.ini
nginx -c /usr/local/nginx/conf/myblog.conf -g 'daemon off;'
myblog.conf
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name 127.0.0.1;
charset utf-8;
access_log /opt/my520/log/nginx_access.log;
error_log /opt/my520/log/nginx_error.log;
client_max_body_size 75M;
location /static {
alias /opt/myblog/static;
}
location /media {
alias /opt/myblog/media;
}
location / {
root /opt/myblog;
include /usr/local/nginx/conf/uwsgi_params;
uwsgi_pass 127.0.0.1:8000;
}
}
}
uwsgi.ini
[uwsgi]
socket = 127.0.0.1:8000
chdir=/opt/myblog
pidfile=%(chdir)/uwsgi.pid
module=myblog.wsgi:application
master = true
processes=2
threads=2
max-requests=2000
chmod-socket=664
vacuum=true
daemonize = /opt/myblog/log/uwsgi.log
Dockerfile
dockerfiles/myblog/Dockerfile
# This my first django Dockerfile
# Version 1.0
# Base images 基础镜像
FROM centos:centos7.5.1804
#MAINTAINER 维护者信息
LABEL maintainer="inspur_lyx@hotmail.com"
#ENV 设置环境变量
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
#RUN 执行以下命令
RUN curl -so /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum install -y python36 python3-devel gcc pcre-devel zlib-devel make net-tools
#工作目录
WORKDIR /opt/myblog
#拷贝文件至工作目录
COPY . .
#安装nginx
RUN tar -zxf nginx-1.13.7.tar.gz -C /opt && cd /opt/nginx-1.13.7 && ./configure --prefix=/usr/local/nginx \
&& make && make install && ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
RUN cp myblog.conf /usr/local/nginx/conf/myblog.conf
#安装依赖的插件
RUN pip3 install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt
RUN chmod +x run.sh && rm -rf ~/.cache/pip
#EXPOSE 映射端口
EXPOSE 8002
#容器启动时执行命令
CMD ["./run.sh"]
执行构建:
$ docker build . -t myblog:v1 -f Dockerfile
定制化基础镜像
dockerfiles/myblog/Dockerfile-base
# Base images 基础镜像
FROM centos:centos7.5.1804
#MAINTAINER 维护者信息
LABEL maintainer="inspur_lyx@hotmail.com"
#ENV 设置环境变量
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
#RUN 执行以下命令
RUN curl -so /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum install -y python36 python3-devel gcc pcre-devel zlib-devel make net-tools
COPY nginx-1.13.7.tar.gz /opt
#安装nginx
RUN tar -zxf /opt/nginx-1.13.7.tar.gz -C /opt && cd /opt/nginx-1.13.7 && ./configure --prefix=/usr/local/nginx && make && make install && ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
## 构建基础镜像
$ docker build . -t centos-python3-nginx:v1 -f Dockerfile-base
$ docker tag centos-python3-nginx:v1 172.21.32.6:5000/base/centos-python3-nginx:v1
$ docker push 172.21.32.6:5000/base/centos-python3-nginx:v1
简化Dockerfile
dockerfiles/myblog/Dockerfile-optimized
# This my first django Dockerfile
# Version 1.0
# Base images 基础镜像
FROM centos-python3-nginx:v1
#MAINTAINER 维护者信息
LABEL maintainer="inspur_lyx@hotmail.com"
#工作目录
WORKDIR /opt/myblog
#拷贝文件至工作目录
COPY . .
RUN cp myblog.conf /usr/local/nginx/conf/myblog.conf
#安装依赖的插件
RUN pip3 install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt
RUN chmod +x run.sh && rm -rf ~/.cache/pip
#EXPOSE 映射端口
EXPOSE 8002
#容器启动时执行命令
CMD ["./run.sh"]
$ docker build . -t myblog -f Dockerfile-optimized
运行mysql
$ docker run -d -p 3306:3306 --name mysql -v /opt/mysql/mysql-data/:/var/lib/mysql -e MYSQL_DATABASE=myblog -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
## 查看数据库
$ docker exec -ti mysql bash
#/ mysql -uroot -p123456
#/ show databases;
## navicator连接
启动Django应用
## 启动容器
$ docker run -d -p 8002:8002 --name myblog -e MYSQL_HOST=172.21.32.6 -e MYSQL_USER=root -e MYSQL_PASSWD=123456 myblog
## migrate
$ docker exec -ti myblog bash
#/ python3 manage.py makemigrations
#/ python3 manage.py migrate
#/ python3 manage.py createsuperuser
## 创建超级用户
$ docker exec -ti myblog python3 manage.py createsuperuser
## 收集静态文件
## $ docker exec -ti myblog python3 manage.py collectstatic
访问62.234.214.206:8002/admin
构建镜像,替换默认编码:
dockerfiles/mysql/my.cnf
$ cat my.cnf
[mysqld]
user=root
character-set-server=utf8
lower_case_table_names=1
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
dockerfiles/mysql/Dockerfile
FROM mysql:5.7
COPY my.cnf /etc/mysql/my.cnf
## CMD或者ENTRYPOINT默认继承
$ docker build . -t mysql:5.7-utf8
$ docker tag mysql:5.7-utf8 172.21.16.3:5000/mysql:5.7-utf8
$ docker push 172.21.16.3:5000/mysql:5.7-utf8
## 删除旧的mysql容器,使用新镜像启动,不用再次初始化
$ docker rm -f mysql
$ rm -rf /opt/mysql/mysql-data/*
$ docker run -d -p 3306:3306 --name mysql -v /opt/mysql/mysql-data/:/var/lib/mysql -e MYSQL_DATABASE=myblog -e MYSQL_ROOT_PASSWORD=123456 172.21.32.6:5000/mysql:5.7-utf8
## 重新migrate
$ docker exec -ti myblog bash
#/ python3 manage.py makemigrations
#/ python3 manage.py migrate
#/ python3 manage.py createsuperuser


浙公网安备 33010602011771号