Dockerfile介绍、常用命令及演示示例
docker-compose

在之前的文章对docker和docker常用命令做了简单介绍,接下来我们来看看怎么使用Dockerfile构建定制镜像和使用docker-compose来编排容器

Dockerfile

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明,docker可以读取Dockerfile文件并根据文件中的描述来构建镜像

  • Dockerfile文件内容一般分为4个部分:
    • 基础镜像信息
    • 维护者信息(已弃用)
    • 镜像操作指令
    • 容器启动时执行的指令

Dokcerfile常用命令

  • 每条保留字指令都必须为大写字母后面要跟随至少一个参数
  • Dockerfile指令从上到下顺序执行
  • # 表示注释
  • 每条指令都会创建一个新的镜像层,并对镜像进行提交,docker再基于之前提交的新的镜像运行一个新的容器,执行dockerfile的下一个指令,直到没有指令
命令 作用
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>] 定义可使用哪个基础镜像启动构建流程
ENV <key>=<value> 设置环境变量,可多条
RUN <command>
RUN ["executable", "param1", "param2"]
Dockerfile的核心部分,可多条
ADD [--chown=<user>:<group>] <src>... <dest> 将宿主机的文件复制到容器内,如果是一个压缩文件,将会在复制后自动解压
COPY [--chown=<user>:<group>] <src>... <dest> 和ADD相似,但如果是压缩文件不解压
WORKDIR /path/to/workdir 设置工作目录,终端默认登陆进来的工作目录
EXPOSE <port> [<port>/<protocol>...] 设置容器对外暴露的端口
CMD ["executable","param1","param2"](推荐)
CMD ["param1","param2"]
CMD command param1 param2
指定一个容器启动时要运行的命令,一个Dockerfile仅可一条,如果包含多条,仅最后一条生效
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
指定一个容器启动时要运行的命令,可以有多个,ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数

更多及详细说明可参考官方文档Dockerfile reference

  1. ADD和COPY的区别
    COPY指令和ADD指令都可以将主机上的资源复制或加入到容器镜像中,都是在构建镜像的过程中完成的
    COPY指令只能从执行docker build所在的主机上读取资源并复制到镜像中。而ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中
    ADD指令中如果<src>是一个可识别的压缩格式的文件,那么它将被解压缩为一个目录。但如果是远程 url 的资源不会被解压缩。当一个目录被复制或解压缩时,它的行为与tar-x相同

  2. CMD和ENTRYPOINT的区别
    CMD支持三种格式:
    CMD ["executable","param1","param2"]使用 exec 执行,推荐方式;CMD command param1 param2/bin/sh 中执行,提供给需要交互的应用;CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数

  • 每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行
  • 如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令

ENTRYPOINT支持两种格式:
ENTRYPOINT ["executable", "param1", "param2"]使用 exec 执行,推荐方式;ENTRYPOINT command param1 param2,shell中执行

  • 配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖
  • 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效

Dockerfile简单示例

制作自定义centos7镜像,设置工作目录,并支持vim编辑器

$ mkdir mycentos
$ cd mycentos
$ vim Dockerfile

Dockerfile文件内容如下:

FROM centos:centos7
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
EXPOSE 80
# 注意多个CMD的效果!!!
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
  • 使用docker build命令构建镜像
docker build -t mycentos:1.0 .
  • 使用docker run运行
$ docker run -itd mycentos:1.0
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
68c113dc089b   mycentos:1.0          "/bin/sh -c /bin/bash"   3 seconds ago    Up 2 seconds    80/tcp                                                 epic_jennings
$ docker exec -it 68c113dc089b bash
[root@68c113dc089b local]# vim
  • 使用docker history查看下镜像构建历史
  • 使用docker inspect查看容器/镜像的元数据

Docker Compose

Docker-compose是用于定义和运行多个容器的Docker应用程序的工具,通过compose,可以使用YAML文件来配置应用程序的服务

在工作中,经常碰到需要多个容器相互配置来完成某项任务的情况,如部署一个web项目,除了web服务容器,往往还需要后端的数据库服务容器,甚至还包含负载均衡容器等

compose的使用一般分为三步:

  1. 使用Dockerfile定义应用程序的环境,以便可以在任何地方复制它
  2. 在docker-compose.yml中定义组成应用程序的服务,以便它们可以在隔离的环境中一起运行
  3. 运行docker-compose up,然后compose启动并运行整个应用程序

docker-compose安装

  • mac上安装的Docker Desktop for Mac包含Compose,所以不需要单独安装
  • linux
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

或者直接下载对应的linux版本安装包并拷贝到平台机器上解压到对应目录并加上可执行权限即可
其他平台可参考官方文档Install Docker Compose

  • 安装校验
docker-compose version

docker-compose常用命令

命令 作用
docker-compose config 查看配置
docker-compose up -d 后台(-d) 启动服务
docker-compose build 构建镜像
docker-compose pull 下载镜像
docker-compose ps 展示容器列表
docker-compose top 展示运行中的进程
docker-compose start 启动服务
docker-compose restart 重新启动服务
docker-compose stop 停止服务
docker-compose pause 暂停服务
docker-compose unpause 恢复暂停的服务

更多命令可参看docker-compose CLI

docker-compose官方示例

参看Get started with Docker Compose

  1. 创建项目目录
 mkdir composetest
 cd composetest
  1. 编写flask项目代码app.py
import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)
  1. 编写文件requirements.txt,写入flask项目依赖的第三方库 flask和redis
flask
redis
  1. 编写Dockerfile文件
# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
  1. 编写docker-compose.yml文件
version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  redis:
    image: "redis:alpine"

更多关于compose file的编写可参看Compose file reference

  1. 构建和运行app
docker-compose up

浏览器访问http://localhost:8000/ 查看效果

问题解决:怎么在docker容器中运行基于selenium的python项目

工作中自动化项目可能用到了selenium,众所周知,selenium需要chrome-driver配套使用,物理机部署倒是很方便,那怎么在docker容器中部署呢?

  1. 编写python项目app.py文件
from selenium import webdriver
from selenium.webdriver import ChromeOptions
import time

options = ChromeOptions()
options.add_argument('--headless')
options.add_argument('--window-size=1920,1080')

time.sleep(5)
driver = webdriver.Remote(
    command_executor="http://127.0.0.1:4444/wd/hub",  # 注意
    options=options
)

driver.get("http://www.baidu.com")
print(driver.title)
driver.close()
  1. 编写Dockerfile文件,部署python项目运行环境
FROM python:alpine3.6
COPY requirements.txt /tmp/requirements.txt
RUN ["pip", "install", "-r", "/tmp/requirements.txt"]
# RUN pip install -r requirements.txt
  1. 编写python项目运行环境的依赖库文件requirements.txt文件
selenium
  1. 编写docker-compose.yml文件
version: "2.0"
services:
  app:
    image: selenium_python:v1
    volumes:
      - ./app.py:/code/app.py  # 这里把刚刚的代码映射到这个目录
    command: python /code/app.py  # 定义启动容器执行的命令
    depends_on:
      - chrome
  chrome:
    image: selenium/standalone-chrome:latest
    ports:
      - "4444:4444"
    shm_size: 2g
  1. docker-compose up

docker-selenium

参考及扩展阅读