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...)
操作演示

  1. 解压离线包

    为了保证镜像下载的速度,因此提前在一台节点下载了离线镜像包,做解压:

    $ 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
    
  2. 查看所有镜像:

$ docker images
  1. 拉取镜像:
$ docker pull nginx:alpine
  1. 如何唯一确定镜像:
  • image_id
  • repository:tag
$ docker images
REPOSITORY    TAG                 IMAGE ID            CREATED             SIZE
nginx         alpine              377c0837328f        2 weeks ago         19.7MB
  1. 导出镜像到文件中

     $ docker save -o nginx-alpine.tar nginx:alpine
    
  2. 从文件中加载镜像

    $ docker load -i nginx-alpine.tar
    
  3. 部署镜像仓库

    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
  4. 推送本地镜像到镜像仓库中

    $ 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       
    
  5. 删除镜像

    docker rmi nginx:alpine
    
  6. 查看容器列表

    ## 查看运行状态的容器列表
    $ docker ps
    
    ## 查看全部状态的容器列表
    $ docker ps -a
    
  7. 启动容器

    ## 后台启动
    $ 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
    

  8. 容器数据持久化

    ## 挂载主机目录
    $ 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
    
  9. 进入容器或者执行容器内的命令

    $ docker exec -ti <container_id_or_name> /bin/sh
    $ docker exec -ti <container_id_or_name> hostname
    
  10. 主机与容器之间拷贝数据

    ## 主机拷贝到容器
    $ 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 ./
    
  11. 查看容器日志

    ## 查看全部日志
    $ docker logs nginx
    
    ## 实时查看最新日志
    $ docker logs -f nginx
    
    ## 从最新的100条开始查看
    $ docker logs --tail=100 -f nginx
    
  12. 停止或者删除容器

    ## 停止运行中的容器
    $ docker stop nginx
    
    ## 启动退出容器
    $ docker start nginx
    
    ## 删除退出容器
    $ docker rm nginx
    
    ## 删除运行中的容器
    $ docker rm -f nginx
    
  13. 查看容器或者镜像的明细

    ## 查看容器详细信息,包括容器IP地址等
    $ docker inspect nginx
    
    ## 查看镜像的明细信息
    $ docker inspect nginx:alpine
    

Django应用容器化实践

django项目介绍
构建命令
$ 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
posted @ 2022-02-14 00:09  风hua  阅读(112)  评论(0)    收藏  举报