docker 进阶总结

1,749 阅读8分钟

Dockerfile

定义

Dockerfile类似于我们学习过的脚本,将我们在上面学到的docker镜像,使用自动化的方式实现出来。

作用

  1. 找一个镜像: ubuntu
  2. 创建一个容器: docker run ubuntu
  3. 进入容器: docker exec -it 容器 命令
  4. 操作: 各种应用配置
  5. ...
  6. 构建新的镜像

Dockerfile 使用准则

记得网上有一个最佳实践,可以🔍搜索一下。

  1. 大:首字符必须大写
  2. 空:尽量将 Dockerfile 放在空目录中
  3. 单: 每个容器尽量只有一个功能
  4. 少: 执行的命令越少越好

Dockerfile 基础四指令

  • 基础镜像信息: 从哪里来
  • 维护者信息: 我是谁
  • 镜像操作指令: 怎么干
  • 容器启动时执行指令: 嗨 !!!

Dockerfile 使用命令

构建镜像命令格式:

docker build -t [镜像名]:[版本号] [Dockerfile所在目录]

构建样例:

docker build -t nginx:v0.2 /opt/dockerfile/nginx/
  • -t: 指定构建之后的镜像信息
  • /opt/dockerfile/nginx/ 代表 Dockerfile 的存放位置,如果是当前的目录,可以使用 . 表示。

快速入门

准备环境

创建 Dockerfile 专用目录:

创建秘钥认证:

准备软件源:

cp /etc/apt/source.list ./

注意:我们要清除 docker 相关的配置,只留下原始的软件源。 给出一份 source.list 如下:

# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial main main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse

# 预发布软件源,不建议启用
# deb http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse

定制文件

创建 Dockerfile 文件:

# 构建一个基于 ubuntu 的 ssh 定制镜像 
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER ruiyang0715@gmail.com 
# 执行命令
# 增加软件源
ADD sources.list /etc/apt/sources.list
#安装ssh服务
RUN apt-get update
RUN apt-get install -y openssh-server curl vim net-tools 
RUN mkdir -p /var/run/sshd
RUN mkdir -p /root/.ssh
#取消pam限制
RUN sed -i "s/.*pam_loginuid.so/#&/" /etc/pam.d/sshd 
RUN apt-get autoclean
RUN apt-get clean
RUN apt-get autoremove
# 复制配置文件到相应位置,并赋予脚本可执行权限
ADD authorized_keys /root/.ssh/authorized_keys
# 对外端口 
EXPOSE 22
#启动ssh
ENTRYPOINT ["/usr/sbin/sshd","-D"]

这时候的文件夹如下:

构建镜像:

docker build -t ubuntu-ssh .

使用新镜像启动一个容器,查看效果:

查看端口:

ssh 查看效果:

基础命令详解

FROM

格式:

FROM <image>
FROM <image>:<tag>

解释:

FROM 是 Dockerfile里的第一条而且只能是除了首行注释之外的第一条指令。

MAINTAINER

格式:

MAINTAINER <name>

解释:

指定该 dockerfile 文件的维护者信息。类似我们在 docker commit 时候使用-a 参数指定的信息

RUN

格式:

RUN <command>
RUN["executable", "param1", "param2"] 

解释: shell模式:类似于 /bin/bash-ccommand 举例: RUN echo hello exec 模式:类似于 RUN ["/bin/bash", "-c", "command"] 举例: RUN ["echo", "hello"]

EXPOSE

格式:

EXPOSE <port> [<port>...]

解释: 设置 Docker 容器对外暴露的端口号,Docker 为了安全,不会自动对外打开端口,如果需要外部提供访问,还需要启动容 器时增加-p 或者-P 参数对容器的端口进行分配。

ENTRYPOINT

格式:

ENTRYPOINT ["executable", "param1","param2"] (exec 模式) 
ENTRYPOINT command param1 param2 (shell 模式)

解释: 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

文件编辑指令详解

ADD

格式:

ADD <src>... <dest>
ADD ["<src>",... "<dest>"]

解释:

  • 将指定的 文件复制到容器文件系统中的
  • src 指的是宿主机,dest 指的是容器
  • 如果源文件是个压缩文件,则 docker 会自动帮解压到指定的容器中(无论目标是文件还是目录,都会当成目录处理)

COPY

格式:

COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

解释: 单纯复制文件场景,Docker 推荐使用 COPY

VOLUME

格式:

VOLUME ["/data"]

解释:

  • VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点
  • 通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。 举例: VOLUME ["/var/lib/tomcat7/webapps/"]
  • 参考: segmentfault.com/q/101000000…

实践

首先在当前目录下面创建一个用于测试的压缩文件:

然后创建一个测试的单个文件 index.html

在 Dockerfile 中添加拷贝文件的命令:

# 构建一个基于 ubuntu 的 ssh 定制镜像 
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER ruiyang0715@gmail.com 
# 执行命令
# 增加软件源
ADD sources.list /etc/apt/sources.list
#安装ssh服务
RUN apt-get update
RUN apt-get install -y openssh-server curl vim net-tools 
RUN mkdir -p /var/run/sshd
RUN mkdir -p /root/.ssh
#取消pam限制
RUN sed -i "s/.*pam_loginuid.so/#&/" /etc/pam.d/sshd 
RUN apt-get autoclean
RUN apt-get clean
RUN apt-get autoremove
# 复制配置文件到相应位置,并赋予脚本可执行权限
ADD authorized_keys /root/.ssh/authorized_keys
# 增加文件
ADD ["sources.list","/etc/apt/sources.list"]
# 增加压缩文件
ADD ["hello.tar.gz", "/hello/"]
# 使用 COPY 增加一个文件 
RUN mkdir -p /var/www/html 
COPY index.html /var/www/html/
# 在容器中创建一个挂载点 
VOLUME ['/data/']
# 对外端口 
EXPOSE 22
#启动ssh
ENTRYPOINT ["/usr/sbin/sshd","-D"]

环境指令详解

ENV 环境设置指令

格式:

ENV <key> <value>
ENV <key>=<value> ...

解释: 设置环境变量,可以在 RUN 之前使用,然后 RUN 命令时调用,容器启动时这些环境变量都会被指定。

WORKDIR

格式:

WORKDIR /path/to/workdir (shell 模式)

解释: 切换目录,为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。 相当于 cd 可以多次切换(相当于 cd 命令),也可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径

举例:

WORKDIR /a 
WORKDIR b 
WORKDIR c
RUN pwd

则最终路径为 /a/b/c。

ENV 实践

在上一个Dockerfile的基础上,在 RUN 下面加一个ENV 如下:

ENV NAME=furuiyang

Dockerfile:

# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER ruiyang0715@gmail.com
# 增加软件源
ADD sources.list /etc/apt/sources.list
# 安装ssh服务
RUN apt-get update
RUN apt-get install -y openssh-server curl vim net-tools
RUN mkdir -p /var/run/sshd
RUN mkdir -p /root/.ssh
# 取消pam限制
RUN sed -i "s/.*pam_loginuid.so/#&/" /etc/pam.d/sshd
RUN apt-get autoclean
RUN apt-get clean
RUN apt-get autoremove
# 设置环境变量
ENV NAME=furuiyang
# 复制配置文件到相应位置,并赋予脚本可执行权限
ADD authorized_keys /root/.ssh/authorized_keys
# 增加文件
ADD ["sources.list","/etc/apt/sources.list"]
# 对外端口
EXPOSE 22
# 启动ssh
ENTRYPOINT ["/usr/sbin/sshd","-D"]

重新生成镜像,开启容器运行:

docker build -t ubuntu-ssh .
docker run -d -p 10086:22 ubuntu-ssh
ssh 172.18.222.137 -p 10086

进入使用 env 命令查看环境变量是否被设置上。

(这里有个问题就是我ssh进入就没有但是exec进入才可看到被设置的 NAME 环境变量)

Dockerfile 的构建过程

  • 从基础镜像 1 运行一个容器 A
  • 遇到一条 Dockerfile 指令,就对容器 A 进行一次修改
  • 执行完一条命令,提交生成一个新镜像 2
  • 再基于新的镜像 2 运行一个容器 B
  • 遇到一条 Dockerfile 的指令,都对容器进行一次修改操作
  • 执行完一条指令,提交生成一个新镜像 3
  • ...

构建过程中的镜像介绍

构建过程中,创建了很多镜像,这些中间镜像,我们可以直接使用来启动容器,通过查看容器效果,从侧面能看到我们每次构建的效果。提供了镜像调试的能力

我们可以通过docker history <镜像名> 来查看整个构建过程所产生的镜像

查看 ubuntu-ssh 的整个构建过程中创建的镜像:

使用中间镜像来启动容器:

docker run -d -p 10087:22 0ca50222ff8c

拓展: 执行的步骤越多越好呢?还是越少越好?

构建缓存

我们的第一次构建会很慢,但是之后的构建都会变快,因为利用到了构建的缓存。

不使用构建缓存的两种做法: 全部不用缓存:

docker build --no-cache -t [镜像名]:[镜像版本] [Dockerfile位置]

部分使用缓存:在 Dockerfile 中使用

# 创建构建刷新时间
ENV REFRESH_DATE 2019-08-30

只要构建的时间不变,那么就用缓存,时间一旦改变,就不用缓存了。

查看构建过程的历史:

docker history [镜像名]

清理构建缓存:

docker system prune 
docker system prune --volumes 

使用 Dockfile 构建 Django 环境 (FIXME)

技术关键点:

  1. docker环境部署:
    • 使用docker镜像启动一个容器即可
  2. django环境部署
    • django软件的依赖环境
    • django软件的基本环境配置
  3. django项目部署
    • django框架的下载
    • 项目文件配置
    • 启动django项目
  4. 测试
    • 宿主机测试

流程:

docker 环境配置

  1. 获取 docker 镜像,这里就使用前面创建的 ubuntu-ssh 镜像

2. 启动 docker 容器,名称叫做 django

docker run -d -p 10086:22 --name django ubuntu-ssh

  1. 进入容器: (可以使用 ssh ip -p 10086 的形式进入) 因为 MacOs开启了连接保护,所以我使用 exec 进入

docker 环境部署

# mkdir /data/{server,softs} -p
# cd data/softs
# scp root@192.168.8.14:/data/softs/Django-2.1.2.tar.gz ./

注: scp 适用于 ssh 连接方式。若使用 exec 模式,可以在启动容器的时候 使用 -v 将项目文件挂载进来。 (TODO)

安装基本的依赖软件:

apt-get install python3-pip python-dev build-essential -y

安装 Django 软件:

cd /data/softs
tar xf Django-2.1.2.tar.gz cd Django-2.1.2
python3 setup.py install

Django 项目部署

项目启动

设置访问主机:

# vim itcast/settings.py 
...
ALLOWED_HOSTS = ['*']

启动项目:

python3 manage.py runserver 172.17.0.2:8000

注意: 要提前使用 ifconfig 来检查一下当前容器的 ip,以方便接下来的测试。

测试

在宿主机, 查看容器的ip地址

docker inspect django

浏览器、或curl查看效果:

172.17.0.2:8000/hello/

这一章节需要后续修改完善,实际的部署不完全是这样的,只是一个部署的初级版本。