docker,Dockerfile,docker-compose操作指南及最佳实践

容器管理工具 docker 的出现使开发及运行环境的配置变得更加便利,服务器运维更高效,也成为了后端工程师必须要掌握的效率工具,我们在这里总结一下它的具体使用,关于 Linux 下安装 docker 相关请看前面一篇:CentOS7安装Docker配置服务端和容器自启动,这里我们将详细介绍 docker 的使用, dockerfile 的编写规则和实例, docker-compose 工具的使用和实例,基本上想学会 docker ,看这一篇就够了。

Docker基本操作

镜像操作

配置阿里云镜像加速器

为了提高官方镜像拉取速度,我们使用阿里云提供的镜像加速器。

注册一个阿里云账号

进入容器镜像服务 => 镜像加速器,获取自己的加速器地址,替换到下面,运行下面的命令即可。

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://*****.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

拉取镜像

比如我们要拉取 php 官方镜像,先到 hub.docker.com上找到我们想要的 php 镜像版本(tags),可以看到,这里有非常多的满足不同需求的版本镜像,我们选 7.1-fpm`,我们的拉取命令就是:

docker pull php:7.1-fpm

不指定 taghub 拉取镜像可能会报错,比如:

[root@localhost docker]# docker pull opensips/opensips
Using default tag: latest
Error response from daemon: manifest for opensips/opensips:latest not found

这里是因为 pull 默认使用 latest 作为镜像 tag ,但这个镜像下没有这个未指定这个 tag ,所以我们需要手动指定一个存在的 tag 拉取。

[root@localhost docker]# docker pull opensips/opensips:2.4

拉取的镜像并不总能直接满足需求,大部分时候我们需要创建自定义镜像,看下面的 Dockerfile的使用 部分。

提交镜像

第一步:在 https://hub.docker.com/ 注册账户并创建仓库;
第二步: 为镜像设置 tag
比如我要把本地的php71镜像提交到仓库 hsu1943/php71:latest

docker tag php:7.1 hsu1943/php71:latest

第三步:推送镜像:

docker push hsu1943/php71:latest

容器操作

查看所有容器(包括已停止的)

[root@localhost /]# docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                     PORTS                                      NAMES
03861a98f878        php:7.1                 "docker-php-entrypoi…"   11 days ago         Up 33 minutes              0.0.0.0:9000->9000/tcp                     php71
d3e84fdcd630        nginx:1.14              "nginx -g 'daemon of…"   12 days ago         Up 33 minutes              0.0.0.0:80->80/tcp, 0.0.0.0:443->433/tcp   nginx114
0d47cf1170a8        redis:4.0               "docker-entrypoint.s…"   12 days ago         Up 33 minutes              0.0.0.0:6379->6379/tcp                     redis4
076c3f7b2d07        mysql:5.7               "docker-entrypoint.s…"   12 days ago         Up 33 minutes              0.0.0.0:3306->3306/tcp, 33060/tcp          mysql57
24ecc15d6bda        opensips/opensips:2.4   "/run.sh"                3 weeks ago         Exited (137) 3 weeks ago                                              opensips

重新启动容器,以下的 ID 指的是上面的 CONTAINER ID 或者是 NAMES

docker restart ID

关闭容器

docker stop ID

强制关闭容器

docker kill ID

删除容器

docker rm ID

查看容器日志

docker logs ID

进入容器并打开终端

docker exec -it ID /bin/bash

查询容器ip地址

docker inspect --format '{{ .NetworkSettings.IPAddress }}' ID

容器中 viipconfigping 命令报错:

command not found ,由于一般镜像未安装这些工具,需要我们安装,当然也可以在自己的镜像 Dockfile 中加入。

apt-get update
#vim
apt-get install vim
#ipconfig
apt install net-tools
#ping
apt install iputils-ping

设置容器网络:

使用docker network进行网络相关配置

# 新建网络
[root@localhost /]# docker network create --subnet=172.18.0.0/16 mynetwork
c387a6bdaf315fb156bfddea2edbe772bfa2981e55ee5f23bdbf5aa38a669903
# 查看已有网络
[root@localhost /]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
11a662a47a82        bridge              bridge              local
1cde9f1dc93e        host                host                local
c387a6bdaf31        mynetwork           bridge              local
0d42b5bfe5e1        none                null                local
# 查看网络连接情况
[root@localhost /]# docker network inspect mynetwork
# 让容器连接到指定网络指定ip
[root@localhost /]# docker network connect --ip 172.18.0.8 --alias mysql_test mynetwork containerID
# 断开容器网络连接
[root@localhost /]# docker network disconnet mynetwork containerID
# 移除网络,需要该网络中的容器全部断开连接才可以
[root@localhost /]# docker network rm mynetwork

运行容器:

使用 docker run 直接来运行一个基于官方镜像 mysql:5.7 的容器,根据参数说明,我们就知道如何启动一个容器了。

docker run -d -p 3306:3306 --privileged=true 
-v /home/docker/mysql/conf/my.cnf:/etc/mysql/my.cnf 
-v /home/docker/mysql/data:/var/lib/mysql 
-v /home/docker/mysql/log:/var/log/mysql 
--restart=always 
--network mynetwork --network-alias mysql 
-e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7

参数说明:
-d 后台运行
-p 开放端口 格式|主机端口:容器端口
--privileged 提供权限
-v 文件挂载
--restart=always 保持在线
--network mynetwork 使用自定义网络mynetwork
--network-alias mysql 网络别名mysql
-e MYSQL_ROOT_PASSWORD=123456 配置环境变量
--name mysql mysql:5.7 容器名称

备份 mysql 容器数据库:

docker exec mysql sh -c 'exec mysqldump --all-databases -uroot -p"123456"' > /some/path/on/your/host/all-databases.sql

从临时容器中获取配置文件

在容器构建过程中需要配置文件挂载,手上没有现成的配置文件?先跑一个临时容器,把默认的配置文件拷贝出来,然后根据自己的情况编辑好配置文件,挂载到使用的容器中去,就可以大道快速部署的目的了。

$ docker run --name tmp-nginx-container -d nginx
$ docker cp tmp-nginx-container:/etc/nginx/nginx.conf /host/path/nginx.conf
$ docker rm -f tmp-nginx-container

# 这里使用了cp命令,在主机和容器之间拷贝文件

Dockerfile的使用

镜像库里的镜像并不能满足所有人的需求,需要根据不同的项目需要来制作自己的镜像, Dockerfile 就很方便的是我们可以以某个镜像为基础(基础镜像),制作一个完全满足自己需求的自定义镜像了供项目需要。具体 Dockerfile 的使用技巧,可以参考这里:Dockerfile reference,这里大概总结一下常用操作和基本格式。

在这之前,先了解一下创建镜像。

docker build命令

# build命令默认上下文是当前目录
docker build 
# 指定生成镜像的名称以及tag,可以多次指定以生成多个
docker build -t shykes/myapp:1.0.2

docker build 的工作原理(上下文)解析, Docker 在运行时分为 Docker daemon (服务端守护进程)和客户端工具。 Docker daemon 提供了一组 REST API ,被称为 DockerRemote API ,而如 docker 命令这样的客户端工具,则是通过这组 APIDocker daemon 交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 docker 功能,但实际上,一切都是使用的远程调用形式在服务端( Docker daemon )完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker daemon 变得轻而易举。

当我们进行镜像构建的时候,并非所有定制都会通过 RUN 指令完成,经常会需要将一些本地文件复制进镜像,比如通过 COPY 指令、 ADD 指令等。docker build 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker daemon 中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?

这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径, docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker daemon 。这样 Docker daemon 收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

# 会将上下文(context)发送给Docker daemon
docker build .
Sending build context to Docker daemon  6.51 MB
...

docker build 命令的上下文还可以是 git 仓库,压缩文件甚至是文本文件。更多的关于 docker build 命令相关看这里:docker build

千万不要在根目录之类的目录作为上下文,一般使用一个空目录,把 Dockerfile 和需要的文件放在该目录下进行创建。

Dockerfile 中使用一些操作(比如 COPY )将上下文目录中的文件添加到镜像中,可以使用 .dockerignore 文件指定要忽略的目录或者文件,不知道如何编写一个 .dockerignore 文件?传送门

默认会使用上下文目录下的 Dockerfile ,也可以在命令中指定它:

$ docker build -f /path/to/a/Dockerfile .

在执行 Dockerfile 前, Docker daemon 会一条条去校验其中的指令,如果有错误将会提示错误并停止执行。

Docker daemon 会一条一条的执行指令,每一条产生一个新的 ,每一层是独立存在,所以在上一个指令中的 cd /tmp 对后面的指令没有影响,为了提高执行效率,应该尽量将同一类的指令放到一起执行,减少 ,在执行过程中,默认会使用缓存,也就是如果之前有执行过,生成的 层镜像 和现在需要的是一样的,那就直接用缓存了。

Dockerfile格式

# 开头后面视为注释(除解析器指令); Dockerfile 指令不区分大小写,不过一般约定指令使用大写,与参数区分;

FROM:必须使用 FROM 指令开头,来指定基础镜像;

  • 镜像可以是任意有效的镜像 – 这个很容易从公共仓库拉取一个镜像。
  • FROM必须是Dockerfile中的首个非注释指令。
  • FROM可以在单个Dockerfile中出现多次,这样可以创建多个镜像。只需记下在每个新的FROM命令之前由提交输出的最后一个图像ID。
  • tag或digest值是可选的。如果都不指定,那么默认是latest。如果找不到tag的值将返回错误。
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>

MAINTAINER:设置生成这个镜像的作者。

MAINTAINER hsu1943 "88888888@qq.com"

ENV:声明环境变量,可以在其他指令中使用;

  • Dockerfile 引用环境变量可以使用 $variable_name${variable_name} 。它们是等同的,其中大括号的变量是用在没有空格的变量名中的,如 ${foo}_bar
  • ${variable_name} 变量也支持一些标准的 bash 修饰符,如:
    • ${variable:-word} 表示如果 variable 设置了,那么结果就是设置的值。否则设置值为 word
    • ${variable:+word} 表示如果 variable 设置了,那么结果是 word 值,否则为空值
  • word 可以是任意的字符,包括额外的环境变量。
  • 转义符可以添加在变量前面:$foo 或者 ${foo} ,例如,会分别转换为 $foor${foo}
FROM busybox
ENV foo /bar
ENV PHP_INI_DIR /usr/local/etc/php
WORKDIR ${foo}   # WORKDIR /bar
ADD . $foo       # ADD . /bar
COPY $foo /quux # COPY $foo /quux

COPY:将上下文目录中的文件复制到docker镜像中

这个命令很直观,也很可靠,在这里大家可能会想到 ADD 命令,这个命令除了复制文件以外还会做更多(复制远程文件,可以自动解压缩),但我们还是建议直接用 COPY 就够了,降低复杂度,提高成功率。

对于目录而言, COPY 只复制目录中的内容而不包含目录自身,所以当你需要复制包含目录的话,应该指定目标路径目录。

COPY docker-php-source /usr/local/bin/

ENTRYPOINT和CMD:设置容器启动时要执行的命令

这两个命令功能上是很相似的,所以也很容易混淆,基本原则:

  • Dockerfile中至少有一个( ENTRYPOINT 或者 CMD ),不然回会报错;
  • 多个 ENTRYPOINT 或多个 CMD 只会执行最后一条;
  • 如果 ENTRYPOINT 使用了 shell 模式, CMD 指令会被忽略;
  • 如果 ENTRYPOINT 使用了 exec 模式, CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数;
  • 如果 ENTRYPOINT 使用了 exec 模式, CMD 也应该使用 exec 模式。

对于 CMDENTRYPOINT 的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMDENTRYPOINT 提供默认的可选参数。

如果还是不清楚,看看官方给出的这个图,大概就能理解了:

Dockerfile中ENTRYPOINT和CMD的使用

LABEL:添加关于镜像的一些信息

LABEL version="1.0"
LABEL description="This text illustrates 
that label-values can span multiple lines."
LABEL maintainer="SvenDowideit@home.org.au" # 代替MAINTAINER的使用,推荐

因为每一个LABEL都会生成一个新的镜像层,所以建议将LABEL放到一起,可以使用换行达到目的,使用 docker inspect 可以查看镜像的 LABEL s,对于同名(key)的情况,后面的LABEL会覆盖前面的,包括FROM指定的基础镜像中的,多个LABEL合并一起:

LABEL version="1.2.0" 
      description="about lnmp" 
      maintainer="SvenDowideit@home.org.au" 
      other="other value"

EXPOSE:声明容器运行时应该打开的端口

这个指令告诉要运行 docker run 这个镜像的运维人员本镜像哪些端口需要映射,在 run 的之后可以通过 -p 来指定端口映射,或者用 -P 随机映射端口,随机映射会将 EXPOSE 声明过的端口映射出来。

对于在同一个 docker network 中的容器,无需打开端口他们之间就可以通过任何端口来访问彼此。

EXPOSE 9000

USER:指定执行后面RUN,CMD,ENTRYPOINT的用户(组)

使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当不需要管理员权限时,可以通过该命令指定运行用户。一般会在之前创建所需要的用户。

运行容器 docker run 时,可以通过 -u 参数来覆盖所指定的用户。

WORKDIR:指定工作目录

可以为后面的 RUN , CMD , ENTRYPOINT , COPY 以及 ADD 指令指定工作目录,目录中可以解析之前使用 ENV 指定的环境变量。

ENV DIRPATH /var
WORKDIR $DIRPATH/www/html
echo pwd 
# 会输出 /var/www/html

ARG:构建参数,指定在build时可以传递过来的变量

使用 ARG 指定的变量可以在 docker build 中通过 --build-arg <varname>=<value> 的形式进行传递,这区别于 ENV 指定的环境变量,环境变量无法在 build 时传递进来。

ARG user1=someuser # 没有传递进来就使用默认值
ARG buildno=1

可以将 ARGENV 结合一起使用:

ARG var
ENV var=${var}

ONBUILD:构建子镜像时在FROM之后立即执行在的任务

本镜像并不执行这个指令,而是在子镜像(下一层)中去执行。

# 父容器中Dockerfile内容
FROM busybox
ONBUILD RUN echo "第二次构建(子构建)才执行"

# 构建父镜像
docker build -t father .

# 构建过程中不会打印"第二次构建(子构建)才执行"

创建子容器
# 子容器中Dockerfile内容
FORM father

# 构建子镜像
docker build -t child .
# 构架过程中打印了"第二次构建(子构建)才执行"

VOLUME:指定容器数据挂载点

指定容器中需要挂载到宿主机的挂载点,在宿主机会生成对应的目录(目录名随机)存放数据,需要注意这里跟 docker run 中可以指定宿主机目录不同, Dockerfile 中的挂载无法指定宿主机目录,这是为了保证可移植性,规定的目录并不一定在每个宿主机都存在。

VOLUME /var/log/mysql
VOLUME ["/var/log/mysql", "/data2"]

更多关于 VOLUME (共享 --volumes-from )的知识可以参考官方文档。

Dockerfile小技巧:apt使用国内源

# Dockfile开头加一行,使用国内debian源
COPY ./sources.list /etc/apt/sources.list
# 在Dockerfile同目录新建sources.list,内容:
deb http://mirrors.ustc.edu.cn/debian/ stretch main non-free contrib
deb http://mirrors.ustc.edu.cn/debian/ stretch-updates main non-free contrib
deb http://mirrors.ustc.edu.cn/debian/ stretch-backports main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian/ stretch main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian/ stretch-updates main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian/ stretch-backports main non-free contrib
deb http://mirrors.ustc.edu.cn/debian-security/ stretch/updates main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian-security/ stretch/updates main non-free contrib
# 不同版本的debian修改stretch即可

Dockerfile实例:

FROM php:7.1-fpm
# 使用国内源
ADD sources.list /etc/apt/
# install any custom system requirements
RUN apt-get update && apt-get install -y --no-install-recommends 
        libfreetype6-dev 
        libjpeg-dev 
        libjpeg62-turbo-dev 
        libmcrypt-dev 
        libpng-dev 
        libpq-dev 
        libicu-dev 
        libz-dev 
        libbz2-dev 
        libmemcached-dev 
        libxml2-dev 
        git 
    && rm -rf /var/lib/apt/lists/*

# Install various PHP extensions
RUN docker-php-ext-configure bcmath --enable-bcmath 
    && docker-php-ext-configure pcntl --enable-pcntl 
    && docker-php-ext-configure pdo_mysql --with-pdo-mysql 
    && docker-php-ext-configure pdo_pgsql --with-pdo-pgsql 
    && docker-php-ext-configure mbstring --enable-mbstring 
    && docker-php-ext-configure soap --enable-soap 
    && docker-php-ext-install 
        bcmath 
        intl 
        mbstring 
        mcrypt 
        mysqli 
        pcntl 
        pdo_mysql 
        pdo_pgsql 
        soap 
        sockets 
        zip 
          iconv 
  && docker-php-ext-configure gd 
    --enable-gd-native-ttf 
    --with-jpeg-dir=/usr/lib 
    --with-freetype-dir=/usr/include/freetype2 
  && docker-php-ext-install gd 
  && docker-php-ext-install opcache 
  && docker-php-ext-enable opcache 
  && pecl install xdebug redis 
  && docker-php-ext-enable xdebug redis 
  && rm -rf /tmp/pear

# AST
RUN git clone https://github.com/nikic/php-ast /usr/src/php/ext/ast/ 
    && docker-php-ext-configure ast 
    && docker-php-ext-install ast

# ICU - intl requirements for Symfony 由于下载巨慢,改成直接COPY压缩包
# Debian is out of date, and Symfony expects the latest - so build from source, unless a better alternative exists(?)
# RUN curl -o /tmp/icu.tar.gz -L http://download.icu-project.org/files/icu4c/63.1/icu4c-63_1-src.tgz 
COPY ./icu4c-58_2-src.tgz /tmp/icu.tar.gz
RUN tar -zxf /tmp/icu.tar.gz -C /tmp 
    &&  ( 
      cd /tmp/icu/source 
      && ./configure --prefix=/usr/local 
      && make 
      && make install 
    ) 
    && rm -rf /tmp/icu 
    && rm /tmp/icu.tar.gz 
    && docker-php-ext-configure intl --with-icu-dir=/usr/local 
    && docker-php-ext-install intl

# Install the php memcached extension
RUN curl -L -o /tmp/memcached.tar.gz "https://github.com/php-memcached-dev/php-memcached/archive/php7.tar.gz" 
  && mkdir -p memcached 
  && tar -C memcached -zxvf /tmp/memcached.tar.gz --strip 1 
  && (   
    cd memcached 
    && phpize 
    && ./configure 
    && make -j$(nproc) 
    && make install 
  ) 
  && rm -r memcached 
  && rm /tmp/memcached.tar.gz 
  && docker-php-ext-enable memcached


# set timezone
RUN rm /etc/localtime 
  && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

#composer
RUN curl -sS https://getcomposer.org/installer | php -- 
    --install-dir=/usr/bin 
    --filename=composer

这个 PHP7.1Dockerfile 以官方镜像 php:7.1-fpm 为计出镜像,安装了常用的工具及扩展,设置时区及 composer ,开包即用,非常方便。

为了更好的理解 build 命令的上下文,看一下当前目录结构:

[root@localhost docker]# tree php7
php7
├── Dockerfile
├── icu4c-58_2-src.tgz
└── sources.list
0 directories, 3 files

docker-compose的使用

用于定义和运行多个 docker 容器的工具,为运维工作服务器的部署和自动化运维提供了极大的便利,通过一个 docker-compose.yml 命令就可以实现多个

安装docker-compose

安装

curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

添加执行权限

chmod +x /usr/local/bin/docker-compose

关于 docker-compose 的使用,以及 docker-compose.yml 文件的书写格式,见:
docker-compose官方文档

docker-compose.yml实例

version: '3'
services:
    nginx:
        image: nginx:1.14
        restart: always
        # 端口映射
        ports:
            - "80:80"
            - "443:433"
        environment:
            - TZ=Asia/Shanghai
        # 依赖关系
        depends_on:
            - "php"
        # 数据卷
        volumes:
            # 映射主机./conf.d目录wwwroot目录nginx.conf文件
            - $PWD/nginx/conf.d:/etc/nginx/conf.d
            - $PWD/wwwroot:/usr/share/nginx/html
            - $PWD/nginx/nginx.conf:/etc/nginx/nginx.conf
            - $PWD/logs/nginx:/var/log/nginx
        networks:
            - app_net
        # 容器名称
        container_name: "nginx114"
    php:
        build: ./php7
        restart: always
        # image指定build 上下文./php7目录下Dockerfile生成镜像的名称
        image: php:7.1
        # php-fpm记录日志用
        cap_add:
            - SYS_PTRACE
        ports:
            - "9000:9000"
        volumes:
            # 网站文件目录,配置目录
            - $PWD/wwwroot:/var/www/html
            - $PWD/php:/usr/local/etc
        networks:
            - app_net
        container_name: "php71"
    mysql:
        image: mysql:5.7
        restart: always
        ports:
            - "3306:3306"
        # 环境变量
        environment:
            # mysql密码
            - TZ=Asia/Shanghai
            - MYSQL_ROOT_PASSWORD=123456
        volumes:
            # 挂载数据库文件,配置文件
            - $PWD/mysql/data:/var/lib/mysql
            - $PWD/mysql/conf:/etc/mysql
            - $PWD/logs/mysql:/var/log/mysql
        networks:
            - app_net
        container_name: "mysql57"
    redis:
        image: redis:4.0
        restart: always
        # 如果不需要外网访问,使用"127.0.0.1:6379:6379"来限制
        ports:
            - "6379:6379"
        environment:
            - TZ=Asia/Shanghai
        volumes:
            - $PWD/redis/data:/data
            - $PWD/redis/redis.conf:/etc/redis/redis.conf
        networks:
            - app_net
        container_name: "redis4"
networks:
    # 配置docker network
    app_net:
        driver: bridge
        ipam:
            config:
                # 子网络
                - subnet: 178.18.0.0/16

这是一个完整的 nginx + php + mysql + redis 多容器的运行环境,结合上面 php7.1Dockerfile 实例只需要按需要修改挂载目录及配置文件即可运行。

标题:docker,Dockerfile,docker-compose操作指南及最佳实践

原文链接:https://beltxman.com/2417.html

若无特殊说明本站内容为 行星带 原创,未经同意请勿转载。

docker,Dockerfile,docker-compose操作指南及最佳实践”上有 4 条评论;

  1. 感谢博主,文章总结得很全面,受益匪浅

评论已关闭。

Scroll to top