# 通过 DockerFile 打包镜像
在介绍 Docker 具体的操作前,先简要复习下 Docker 的架构,这样可以更好地帮助我们理解 Docker 中的各个命令。
首先我们一直对 Docker 这个叫法就有些误解,Docker 其实指代的是用于开发,部署,运行应用的一个平台。平常中说的 Docker 准确来说是 Docker Engine.
Docker Engine 是一个 C/S 架构的应用。其中主要的组件有:
- Docker Server:长时间运行在后台的程序,就是熟悉的 daemon 进程.
- Docker Client: 命令行接口的客户端。
- REST API: 用于和 daemon 进程的交互。
我们通过给 Docker Client 下发各种指令,然后 Client 通过 Docker daemon 提供的 REST API 接口进行交互,来让 daemon 处理编译,运行,部署容器的繁重工作。 大多数情况下, Docker Client 和 Docker Daemon 运行在同一个系统下,但有时也可以使用 Docker Client 来连接远程的 Docker Daemon 进程,也就是远程的 Server 端。
清楚了 Docker 的简单架构,就可以了解下具体的命令了。
Docker 镜像构建指令
指令1:构建镜像
docker build [OPTIONS] PATH | URL | -
Docker 构建镜像的上下文。
这里的上下文指的就是命令的最后一个参数 PATH | URL| -
,具体来说就 docker build .
中的 .
很多人以为这个 .
是 DockerFile 的位置,其实不然,准确来说是构建上下文的位置。前面说到 Docker 是 C/S 架构,在 Client 端下发具体的命令,在 Server 端(Daemon)执行具体的内容。这也就意味着,构建镜像的过程其实是在 Server 端完成的。而上下文的出现,就是为了把需要的内容传递给 Server,这也就为什么在每次构建时都能看到这样一句话。
[root@localhost python_shell]# docker build --rm -t temp/python-test .
Sending build context to Docker daemon 4.608kB
这里的 Sending 其实就是把本地 Client 端的文件内容,拷贝到 Server 端。而许多初学者,在 DockerFile 中写出了 COPY /opt/xxxx /app
这样的话,其实就是没有理解上下文的概念,并不知道在 Server 端是没有 opt/xxxx
的文件的。
还有的人将 Docker File 放在硬盘根目录执行,殊不知,这样会将根目录所有的文件都拷贝到 Server 端,造成构建极其缓慢。
Options 常用参数:
-t
: 打包出镜像的名称及标签,通常写法为name:tag
--rm
: 构建成功后,删除中间产生的容器。--force-rm=true
: 无论是否构建成功,都删除中间产生的容器--no-cache
: 构建镜像时不使用缓存。-f
: 指定 DockerFile 的路径
docker build --no-cache --force-rm -t --no-cache local/centos7:v1 .
DockerFile 指令及编写规范
指令1:指定基础镜像
通过 FROM
来制定基础镜像,命令很简单,但有一点需要注意的是,一定确切指定基础镜像的版本,而不是写成 latesst
, 因为随着时间推移,官方的最新镜像都会一直更新,这样就会造成无法构建的情况。
FROM centos:7 # That's perfect!
FROM centos:latest # That's so bad!
指令2:容器中执行命令
RUN 命令用于在容器中执行命令行的命令。一般有两种写法:
- shell 形式:
RUN 后面直接跟 shell 命令就可以了。切记,在 shell 形式下,不要把命令拆成多行 RUN。因为每一次的 RUN 都会构建一层新的镜像,保存了很多没有用的运行信息。而且 Union FS 是由最大层数限制的。所以尽量将命令合成一行。
RUN yum -y install httpd; yum clean all; systemctl enable httpd.service # That's perfect!
RUM yum -y install httpd / # Another perfect solution!
yum clean all /
systemctl enable httpd.service
RUN yum -y install httpd # That's so bad!
RUN yum clean all;
....
还有一点需要注意,把构建时没用的依赖包想着清空。否则的话,随着镜像的重复构建,保存了大量的没有信息。
- exec 写法
exec 写法更像函数调用中的格式。
RUN ["可执行文件", "参数1", "参数2"]
RUN ["yum", "-y", "install", "httpd"]
指令3:设置工作目录
WORKDIR 用于改变各层的工作目录(也就是进入容器内的默认目录),如果指定的目录不存在就会创建它。工作目录在构建过程中,可以被各层都访问到。
WORKDIR /src
指令4:设置匿名卷
在容器运行时,尽量对容器的存储层不进行写操作,对于像数据库中这样动态的数据文件应该用 VOLUME 来保存。而在 DockerFile VOLUME 可以将目录指定为匿名卷。这样在运行时,如果没有挂载指定的目录,并不会像容器的存储层写入数据,保证存储层的无状态化。
VOLUME /data
开启 Systemd Centos7 镜像
官方 Centos7 的镜像已经包含了 systemd 的功能,只是没有开启。这里只需要以其为基础镜像,打开 systemd 的功能即可。需要注意的是,打开 systemd 需要在运行时开启特权以挂载 Cgroup 等内容。
编写 DockerFile
[root@localhost docker_images]# cat Dockerfile
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
- VOLUME 指定了匿名目录,不会在存储层保存该目录的内容,适用于动态变化等持久性文件。
- CMD 保证容器启动时开启 systemd
打包镜像
docker build --rm -t local/c7-systemd .
- --rm: 表示删除打包时临时的容器
运行镜像
docker run --privileged=true -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro local/c7-systemd
- --privileged: 给予容器特殊的权限,来挂载 Cgroup 等。
Httpd 镜像
下面基于上面开启 systemd 的镜像为基础,打包 Httpd 镜像。
编写 DockerFile
FROM local/c7-systemd
RUN yum -y install httpd; yum clean all; systemctl enable httpd.service
EXPOSE 80
- 下载依赖包后,删除没有用的内容,是编写 DockerFile 好习惯。
编译 DockerFile
docker build --rm -t local/c7-systemd-httpd .
运行 Container
docker run --privileged=true -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
-p 80:80 local/c7-systemd-httpd
在下载依赖时出现网络问题,请查看 Docker 代理 这篇文章。
Python 镜像
有时我们需要在容器中运行 python 脚本,下面来打包类似的镜像。在下载需要的依赖时,通常的服务器并没访问公网的能力,这时需要为容器配置配置代理,在下载依赖后,有时由于代理的原因,导致内部的服务器无法访问,这时可以再将设置的代理清空。
创建文件
注意,这里的文件要和 DockerFile 在同级目录下。
# 创建 requirements 文件保存依赖
[root@localhost home]# cat python_shell/requirements.txt
requests==2.21.0
# 编写 Python 脚本
[root@localhost home]# cat python_shell/success.py
print("python Running", "!");
编写 DockerFile
FROM python:3.6.8
# set proxy
ENV MY_PROXY_URL="http://173.39.112.117:80"
ENV HTTP_PROXY=$MY_PROXY_URL \
HTTPS_PROXY=$MY_PROXY_URL \
FTP_PROXY=$MY_PROXY_URL \
http_proxy=$MY_PROXY_URL \
https_proxy=$MY_PROXY_URL \
ftp_proxy=$MY_PROXY_URL
WORKDIR /src
COPY . .
RUN ["pip", "install", "--no-cache-dir", "-r", "./requirements.txt"]
# clear the proxy
ENV MY_PROXY_URL=
ENV HTTP_PROXY=$MY_PROXY_URL \
HTTPS_PROXY=$MY_PROXY_URL \
FTP_PROXY=$MY_PROXY_URL \
http_proxy=$MY_PROXY_URL \
https_proxy=$MY_PROXY_URL \
ftp_proxy=$MY_PROXY_URL
CMD ["python", "./success.py"]
打包镜像
docker build --rm -t temp/python-test .
运行镜像
[root@localhost home]# docker run temp/python-test
python Running !
参考
https://blog.fundebug.com/2017/05/15/write-excellent-dockerfile/
# 通过 DockerFile 打包镜像的更多相关文章
- Kbengine游戏引擎-【5】用Dockerfile打包镜像kbengine
本文是以docker为例,以ubuntu 16.04做基础镜像 kengine 1.0.0 用supervisor来管理启动 先放下目录结构图: kb--里面放的是kbengine的编译后的引擎以及d ...
- 利用dockerfile定制镜像
利用dockerfile定制镜像 镜像的定制就是定制每一层所添加的配置.文件.如果可以吧每一层修改.安装.构建.操作的命令都写入到一个脚本,用脚本来构建.定制镜像,这个脚本就是dockerfile. ...
- Docker Dockerfile 定制镜像(转)
转自: https://yeasy.gitbooks.io/docker_practice/ 及 https://blog.csdn.net/wo18237095579/article/details ...
- SpringBoot 部署 docker 打包镜像
SpringBoot 部署 docker 打包镜像 环境: 1.代码编写工具:IDEA 2.打包:maven 3.docker 4.linux 7.JDK1.8 8.Xshell 9.Xftp 第一步 ...
- Docker Dockerfile 定制镜像
使用 Dockerfile 定制镜像 镜像的定制实际上就是定制每一层所添加的配置.文件.如果我们可以把每一层修改.安装.构建.操作的命令都写入一个脚本,用这个脚本来构建.定制镜像,那么无法重复的问题 ...
- docker(常见调试技巧):docker打包镜像调试技巧
写Dockerfile可以先不指定CMD.ENTRYPOINT等启动命令,只要拷贝就好了 如下: # Dockerfile for basic-app-client # Build with: # d ...
- Docker用Dockerfile定制镜像
用Dockerfile定制镜像 镜像的定制实际上就是定制每一层所添加的配置.文件.如果我们可以把每一层修改.安装.构建.操作的命令都写入一个脚本,用这个脚本来构建.定制镜像,那之前提示的无法重复的问题 ...
- docker将jar打包镜像文件
1.首先需要编写dockerfile文件,通过dockerfile文件将jar包打成镜像 编写dockerfile文件 # 定义父镜像 FROM java:8 # 维护者信息 MAINTAINER c ...
- docket打包镜像内部报错
临时记录,后面再完善 对于前端docker一般不太熟悉,当我们想要打包镜像的时候会去找教程,我按着教程去打包一个使用KOA框架搭建的node服务. 这是一个 koa + ts + pm2的项目 结果出 ...
随机推荐
- mysql oracle sql获取树 父级 子级 及自己
select * from ( select t.*,d.TABLE_NAME,d.QUERY_SQL,d.data_control_col,d.id table_id,d.where_sql fro ...
- 【5min+】你怎么穿着品如的衣服?IEnumerable AND IEnumerator
系列介绍 简介 [五分钟的dotnet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的. ...
- cogs 2098. [SYOI 2015] Asm.Def的病毒 LCA 求两条路径是否相交
2098. [SYOI 2015] Asm.Def的病毒 ★☆ 输入文件:asm_virus.in 输出文件:asm_virus.out 简单对比时间限制:1 s 内存限制:256 M ...
- Java配置文件读取中文乱码问题
背景 这是我之前在做的用友服务对接开发,昨天领导拿给财务测试时告诉我有乱码,当时我第一想法是用友那边的编码格式有问题,因为还在做其他任务,我说等问一下用友他们用的什么编码格式我们这边改一下,然后今天早 ...
- 【转】KAFKA分布式消息系统
Kafka[1]是linkedin用于日志处理的分布式消息队列,linkedin的日志数据容量大,但对可靠性要求不高,其日志数据主要包括用户行为(登录.浏览.点击.分享.喜欢)以及系统运行日志(CPU ...
- 20190925Java课堂记录(二)
1. testrandom public class test2{ public static void main(String[] args) { int[] n=new int [1001]; n ...
- 2019CSP复赛游记
Day 0 作为一个初三的小蒟蒻…… 什么算法都不会打…… 做一道LCA+生成树的图论题调了两个小时…… 明日裸考…… Day 1 Morning 买了两个士力架,带了一盒牛奶,准备在考场上食用(这个 ...
- importlib 根据字符串导入模块
应用: Django中间件,rest framework 组件的全局配置文件 import importlib path = "abc.def.foo" module_path,c ...
- (分块)楼房重建 HYSBZ - 2957
题意 长度为n的坐标轴上,从1-n上的每一点都有一栋楼房,楼房的初识高度都为0,每一天都有一栋楼房的高度被修改(也可以不变),一栋楼房能被看见当且仅当其最高点与远点的连线不会与其他之前连线相交,问你每 ...
- 玩转Django2.0---Django笔记建站基础十二(Django项目上线部署)
第十二章 Django项目上线部署 目前部署Django项目有两种主流方案:Nginx+uWsGI+Django或者Apache+uWSGI+Django.Nginx作为服务器最前端,负责接收浏览器的 ...