Docker之Dockerfile详解

使用Dockerfile创建镜像

  • Dockerfile是一个文本格式的配置文件,我们可以利用Dockerfile来快速的创建一个自定义的镜像。
基本结构
  • Dockerfile由一行命令语句组成,并且支持以#开头的注释
  • 一般包括四个部分:基础镜像信息,维护者信息,镜像操作指令,容器启动时执行指令,如下一个案例
# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
FROM ubuntu
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user docker_user@email.com
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx
  • 如上是一个官网的Demo,一开始指定所基于的镜像名称,之后是维护者的信息,后面才是镜像操作的指令,例如RUN指令将对镜像执行跟随在后面的命令,CMD用来指定运行容器时候的操作命令。
  • 如下是一个更复杂一点的案例,基于buildpack-deps:jessie-scm基础镜像,安装Golang相关环境,制作一个GO语言的运行环境镜像(先看看就行):
FROM buildpack-deps:jessie-scm
# gcc for cgo
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
gcc \
libc6-dev \
make \
&& rm -rf /var/lib/apt/lists/*
ENV GOLANG_VERSION 1.6.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 cdde5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd
7561275a87aeb
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
&& echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - \
&& tar -C /usr/local -xzf golang.tar.gz \
&& rm golang.tar.gz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin/
指令说明
  1. FROM
  • 指定所创建镜像的基础镜像,如果本地不存在,默认去Docker Hub上下载,格式:FROM < image>
  • 任何一个Dockerfile中第一条指令必须是FROM,并且,如果在同一个Dockerfile中创建多个镜像,可以用多个FROM指令
  1. MAINTAINER
  • 指定维护者信息,格式MAINTAINER< name>。信息会写入生成镜像的Author属性域中例如:
MAINTAINER ljmadmin@docker.com
  1. RUN
  • 运行指定命令格式如下
  • 上面第一个命令默认将在shell中断中运行,即 /bin/sh -C ,后面的使用exec执行不会启动shell环境
  • 每一条RUN指令将在当前镜像的基础上执行指定的命令,并且提交为新的进行,当命令比较长的时候,可以用\ 来换行,比如:
RUN <command>  或者 RUN ["executable", "param1","param2"],
//案例
RUN apt-get update \&& apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \&& rm -rf /var/cache/apt
  1. CMD
  • CMD指令用来指定启动容器时候默认执行的命令,他支持三种格式:
    • CMD[“executable”, “param1”, “param2”] 使用exec执行,是推荐使用的方式
    • CMD command param1 param2 在/bin/sh 中执行,提供给需要交互的应用
    • CMD [“param1”, “param2”]提供给ENTRYPOINT的默认数
  • 每个DOckerfile只能有一条CMD命令,如果指定多条,最后一条覆盖之前的
  1. LABEL
  • LABEL指令用来指定生成镜像的元数据标签信息
  • 格式为如下例如
LABEL<key> = <value><key>=<value>....
//案例
LABEL version="1.0"
LABEL description="This text illustrates \ that label-values can span multiple lines."
  1. EXPOSE
  • 声明镜像内服务所监听的端口
  • 格式如下。 例如
EXPOSE <port>[ <port>......]
//案例
EXPOSE 22 80 8443
  • 改指令只是起到声明作用,不会自动完成端口映射
  • 启动容器时候需要使用-P,Docker主机会自动分配一个宿主机临时端口转发到指定的端口,使用-p,则可以具体的指定哪个宿主机本地端口会映射过来。
  1. ENV
  • 指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在
  • 格式…。如下:
ENV <key><value> 或者 EVN <key>=<value>
//案例
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/
postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
  • 指令指定的环境变量在运行时可以被覆盖掉,比如docker run --evn< key>=< value>built_image
  1. ADD
  • 该命令将复制指定额< src> 路径下的内容到容器中的< dest> 路径下,格式如下
  • 其中< src> 可以是Dockerfile所在的目录的一个相对路径,也可以是一个URL,还可以是一个tar文件。< desc>可以使镜像内部的绝对路径,或者相对于工作目录的相对路径。
ADD <src><desc>
  1. COPY
  • 格式如下,复制本地主机的< src> (为Dockerfile所在目录的相对路径,文件,或者目录) 下的内容 到镜像中的< dest> 下。目标路径不存在时候回自动创建 。路径支持正则,当使用本地目录为源目录时候,推荐使用COPY
COPY<src><desc>
  1. ENTRYPOINT
  • 指定镜像的默认入口命令,该入口命令会在启动容器时候作为命令执行,所有传入值作为改命令的参数,支持如下两种格式
ENTRYPOINT ["executable", "param1", "param2"](exec调用执行)
ENTRYPOINT command param1 param2(shell中执行)
  • 每个Dockerfila中只能有一个ENTRYPOINT,当指定过个时候,只有最后一个有效,在运行时候可以被–entrypoint参数覆盖掉,如docker run–entrypoint
  1. VOLUME
  • 创建一个数据卷挂载点, 可以从本地主机或者其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等。格式如下
VULUME ["/data"]
  1. USER
  • 指定运行容器时候的用户名或者UID,后续的RUN等指令也会使用指定的用户身份格式如下:
USER daemon
//案例
RUN groupadd -r postgres && useradd -r -g postgres postgres
  • 需要临时获取管理员权限可以使用gosu或者sudo
  1. WORKDIR
  • 为后续的RUN,CMD和ENTRYPOINT指令配置工作目录,格式如下
WORKDIR /path/to/workdir
//案例
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
  • 如上案例,可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。最终的路径为/a/b/c
  1. ARG
  • 指定一些镜像内使用的参数(例如版本号信息等),这些参数在执行docker build命令时以下格式传入
ARG<name>[=<default value>]
//案例
docker build--build-arg<name>=<value>
  1. ONBUILD
  • 配置当所有创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令,格式如下:
ONBUILD [INSTRUCTION]
//Dockerfile使用如下内容创建镜像image-A
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bing/python-build --dir /app/src
[...]
  • 如果基于image-A创建新的镜像时候,新的Dockerfile使用FROM image-A指定基础进行,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令,如下:
FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
  • 使用ONBUILD指令的镜像,推荐在边去中注明,例如ruuby:1.9-onbuild
  1. STOPSIGNAL
  • 指定所创建的镜像启动的容器接受退出的信号值,例如:
STOPSIGNAL signal
  1. HEALTHCHECK
  • 配置所启动容器如何进行健康检查(如何判断健康与否),自Docker1.12开始支持,格式如下:
HEALTHCHECK [OPTIONS] CMS command :根据执行命令返回值是否为0 判断
HEALTHCHECK NONE : 禁止基础镜像中的监看检查
  • OPTION参数支持如下:
    • __interval=DURATION(默认30s):过多久检查一次
    • __timeout=DURATION(默认30s):每次检查等待结果的超时
    • __retries=N(默认为3):如果失败,重试几次才最终确定失败。
创建镜像
  • 编写完Dockerfile后,可以通过docker build命令来创建镜像,基础格式如下:
docker build [选项]
  • 如上命令将读取指定路径下(包括子目录)的Dockerfile文件,并将该路劲下所有内容发送给Docker 服务端,由服务端来创建镜像,因此除非生成镜像需要,否则一般建议放置Dockerfile的目录为空目录。
    • 如果使用非内容路径下Dockerfile,可以通过-f 选项指定其他路径
    • 要指定生成镜像的便签可以用-t 选项
  • 案例:指定Dockerfile路径/tmp/docker_builder/,并且生成镜像标签为build_repo/first_image,命令如下
docker build -t build_repo/first_image /temp/docker_builder
使用.dockerignore文件
  • 上说的,Dockerfile路径下的所有文件都会发到Docker服务端打包,那肯定有响应的规避措施,
  • 我们通过.dockerignore文件(没一行添加一条匹配模式)来让Docker忽略匹配模式路径下的目录和文件。如下:
#comment*/temo**/*/temp*tmp?~*

Dockerfile实战测试

  • 以下将分别通过docker commit命令方式,Dockerfile的方式分别为镜像添加SSH服务并且生成新的镜像文件,来对象两者的区别,
通过docker commit 方式创建镜像
  • Docker提供了docker commit 命令,支持用户提交自己对指定容器的修改,并且生成新的镜像在本地。格式如下:
docker commit CONTAINER [REPOSITORY[:TAG]]
  • 如下步骤依次执行:
//使用ubuntu:lasted
docker run -it ubuntu:lasted /bin/bash
//更新apt缓存,并安装openssh-server
apt-get update; apt-get install openssh-server -y
//如需正常启动SSH服务,则目录/var/run/sshd必须存在,手动创建,并启动SSH服务
mkdir -p /var/run/sshd
/usr/sbin/ssh -D &
//修改SSH服务的安全登录配置,取消pam登录限制
sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd
//在root账户下创建.ssh目录,并负责需要登录的公钥(公钥信息一般为本机主机用户目录下.ssh/id_rsa.pub文件,可由ssh-keygen-t rsa命令生成)到authorized_keys文件中:
mkdir root/.ssh
vi /root/.ssh/authorized_keys
//创建自动启动ssh服务的可执行文件run.sh,并添加权限:
vi /run.sh 
chmod +x run.sh
//编辑内容
#!/bin/bash
/usr/sbin/sshd -D
//退出容器
exit
//保存镜像
docker commit [CONTAINER ID] sshd:ubuntu
//使用docker images查看本地生成的镜像sshd:ubuntu,目前拥有镜像信息如下截图
//使用镜像
docker run -p 10022:22 -d ssh:ubuntu /run.sh
//启动成功后可以在宿主机上看到容器运行的详细信息
docker ps
//可以通过该宿主机ip访问,通过ssh 10022 端口登录容器
ssh 192.168.*.* -p 10022

在这里插入图片描述

使用Dockerfile创建
  • 依次按如下步骤
//创建工作目录sshd_ubuntu工作目录
mkdir sshd_ubuntu
//在其中创建Dockerfile和run.sh文件
cd /sshd_ubuntu/
touch Dockerfile run.sh
//编写run.sh脚本和authorized_key文件
#!/bin/bash
/usr/sbin/sshd -d
//在宿主机上生成SSH秘钥对,并创建authorized_keys文件:
ssh-keygen -t rsa
....
cat ~/.ssh/id_rsa.pub > authorized_keys
  • 编写Dockerfile,下面是Dockerfile的内容以及部分的解释信息,可以对比docker commit 命令创建的过程,操作基本一致:
#设置基础镜像
FROM ubuntu:latest
#提供一些作者信息
MAINTAINER ljmadmin (645121107@qq.com)
#下面开始运行更新命令
RUN apt-get update
#安装ssh服务
RUN apt-get install -y openssh-server
RUN mkdir -p /var/run/sshd
RUN mkdir -p /root/.ssh
#取消pam限制
RUN sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd
#复制配置文件到相应位置,并赋予可执行权限
ADD authorized_keys /root/.ssh/authorized_keys
ADD run.sh /run.sh
RUN chmod 755 /run.sh
#开放端口
EXPOSE 22
#设置自启动命令
CMD ["/run.sh"]
  • 创建镜像:在sshd_ubuntu目录下使用docker build命令创建镜像,
cd sshd_ubuntu
docker build -t ssh:Dockerfile .
  • 查看本地ssh:Dockerfile镜像已经存在:
    在这里插入图片描述
  • 测试启动镜像运行容器效果与上面一致

总结

  • Dockerfile使用前需要熟悉每个命令,多实践,自己写一些简单的案例测试,弄清楚原理在写,Docker Hub官方仓库有很多优秀镜像对应的Dockerfile可以借鉴学习
  • 创建原则有如下几个:
    • 精简镜像用途:
    • 选合适基础镜像
    • 提供足够清晰的命令注释和维护者信息
    • 正确使用版本号码
    • 减少镜像层数
    • 及时删除临时文件和缓存文件
    • 提高生成速度
    • 调整合理的指令顺序
    • 减少外部源干扰

上一篇:Docker中数据管理
下一篇:Docker容器实战思维

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[剑指offer]面试题34:丑数

面试题34&#xff1a;丑数 题目&#xff1a;我们把只包含因子2、3和5的数称作丑数&#xff08;Ugly Number&#xff09;。求按从小到大的顺序的第1500个丑数。例如6、8都是丑数&#xff0c;但14不是&#xff0c;因为它包含因子7。习惯上我们把1当做第一个丑数。 ❖ 逐个判断每…

创业的N种死法

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份互联网的江湖一直流传着大佬们的创业传奇。马云上厕所几分钟敲定几千万美金融资。王石走投无路靠倒卖玉米赚到上百万从此逆袭。扎克伯格为了获得哈佛美女照片&#xff0c;开发一个小玩意从此改变了世界。传奇…

Docker容器实战思维

Docker成功的基础 Docker的实现用到的基础技术&#xff08;cgroups, namespace&#xff0c;分层文件系统&#xff09;在Docker之前已经存在很多年&#xff0c;并且 Linux Containers&#xff08;LXC&#xff09;也在很多企业的环境中得到了大量的应用实践&#xff0c;并得到明…

[剑指offer]面试题35:第一个只出现一次的字符

面试题35&#xff1a;第一个只出现一次的字符 题目&#xff1a;在字符串中找出第一个只出现一次的字符。如输入"abaccdeff"&#xff0c;则输出’b’。 代码如下: char FirstNotRepeatingChar(char *pString) {if (pString nullptr) return \0;const int tableSize…

dotNET Core 3.X 请求处理管道和中间件的理解

理解 dotNET Core 中的管道模型&#xff0c;对我们学习 dotNET Core 有很大的好处&#xff0c;能让我们知其然&#xff0c;也知其所以然&#xff0c;这样在使用第三方组件或者自己写一些扩展时&#xff0c;可以避免入坑&#xff0c;或者说避免同样的问题多次入坑。本文分为以下…

数据结构与算法--实现Singleton模式

题目&#xff1a;设计一个类&#xff0c;我们只生成该类的一个实例。 只生成一个实例的类就是实现Singleton&#xff08;单例&#xff09;模式的类型。本题其实主要考察我们设计模式&#xff0c;因为面试的时候先来一个简单的&#xff0c;并且喜欢面设计模式相关的题目&#x…

[剑指offer]面试题37:两个链表的第一个公共结点

面试题37&#xff1a;两个链表的第一个公共结点 题目&#xff1a;输入两个链表&#xff0c;找出它们的第一个公共结点。链表结点定义如下&#xff1a; struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {} };思路: 两个链表长度分别为L1C、L2C&…

了解.NET中的垃圾回收

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。尽管这是一篇来自2009年的古老的文章&#xff0c;但或许能够对你理解GC产生一些作用。 了解.NET中的垃圾回收一旦了解了.NET的垃圾收集器是如何工作的&#xff0c;那么可能会触及.NET应用程序的一些更为神秘的问题时&…

数据结构与算法--数组:二维数组中查找

数组 数组最简单的是数据结构&#xff0c;占据一整块连续的内存并按照顺序存储数据&#xff0c;创建数组时候&#xff0c;我们需要首先指定数组的容量大小&#xff0c;然后根据大小分配内存。即使我们只在数组中存储一个元素&#xff0c;亚需要为所有数据预先分配内存&#xf…

[剑指offer]面试题41:和为s的两个数字VS和为s的连续正数序列

面试题41&#xff1a;和为s的两个数字VS和为s的连续正数序列 题目一&#xff1a;输入一个递增排序的数组和一个数字s&#xff0c;在数组中查找两个数&#xff0c;使得它们的和正好是s。如果有多对数字的和等于s&#xff0c;输出任意一对即可。 代码如下: bool FindNumbersWit…

数字化演化历史

回顾历史&#xff0c;帮助我们展望未来&#xff0c;在数字化技术出现之前&#xff0c;人类历史几千年的历史中&#xff0c;人类社会中&#xff0c;人类的大脑是唯一可以作信息处理的。比如我们发明了汽车&#xff0c;需要人来开车&#xff1b;发明了飞机&#xff0c;需要人来驾…

数据结构与算法--字符串:字符串替换

数据结构与算法–字符串&#xff1a;字符串替换 字符串的优化 由于字符串在编程时候使用的评率非常高&#xff0c;为了优化&#xff0c;很多语言都对字符串做了特殊的规定。下面我们讨论java中字符串的特性java中的字符数组以’\0’ 结尾&#xff0c;我们可以利用这个特性来找…

[剑指offer]面试题42:翻转单词顺序 VS左旋转字符串

面试题42&#xff1a;翻转单词顺序 VS左旋转字符串 题目一&#xff1a;输入一个英文句子&#xff0c;翻转句子中单词的顺序&#xff0c;但单词内字符的顺序不变。为简单起见&#xff0c;标点符号和普通字母一样处理。例如输入字符串"I am a student."&#xff0c;则输…

数据结构与算法--经典10大排序算法(动图演示)【建议收藏】

十大经典排序算法总结&#xff08;动图演示&#xff09; 算法分类 十大常见排序算法可分为两大类&#xff1a; 比较排序算法&#xff1a;通过比较来决定元素的位置&#xff0c;由于时间复杂度不能突破O(nlogn)&#xff0c;因此也称为非线性时间比较类排序非比较类型排序&…

如何查找,修复和避免C#.NET中内存泄漏的8个最佳实践

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。本文来源&#xff1a;https://michaelscodingspot.com/find-fix-and-avoid-memory-leaks-in-c-net-8-best-practices/从事大型企业项目的任何人都知道内存泄漏就像是大型酒店中的老鼠。当它们很少时&#xff0c;您可能不会…

[剑指offer]面试题47:不用加减乘除做加法

面试题47&#xff1a;不用加减乘除做加法 题目&#xff1a;写一个函数&#xff0c;求两个整数之和&#xff0c;要求在函数体内不得使用、-、、四则运算符号。 代码如下: int add(int num1, int num2) {int sum, carry;do{sum (num1 ^ num2);carry (num1 & num2) <&l…

ASP.NET Core技术研究-探秘依赖注入框架

ASP.NET Core在底层内置了一个依赖注入框架&#xff0c;通过依赖注入的方式注册服务、提供服务。依赖注入不仅服务于ASP.NET Core自身&#xff0c;同时也是应用程序的服务提供者。毫不夸张的说&#xff0c;ASP.NET Core通过依赖注入实现了各种服务对象的注册和创建&#xff0c;…

Redis遍历方式思考--字典扩容方式

全量遍历keys 工作中线上Redis维护&#xff0c;有时候我们需要查询特定前缀的缓存key列表来手动处理数据。可能是修改值&#xff0c;删除key。那么怎么才能快速的从海量的key中查找到对应的前缀匹配项。Redis提供了一下简单的指令&#xff0c;例如keys用来满足特定正则下的key…

[剑指offer]面试题48:不能被继承的类

面试题48&#xff1a;不能被继承的类 题目&#xff1a;用C设计一个不能被继承的类。 ❖ 常规的解法&#xff1a;把构造函数设为私有函数 很多人都能够想到&#xff0c;在 C中子类的构造函数会自动调用父类的构造函数&#xff0c;子类的析构函数也会自动调用父类的析构函数。 …

从项目到产品: 软件时代需要价值流架构师 | IDCF

译者&#xff1a;无敌哥原文地址: https://thenewstack.io/the-age-of-software-needs-value-stream-architects/ 本文翻译仅供学习交流之用。原文作者 Mik Kersten 出版了《Project to Product》本系列共四篇文章&#xff0c;分别是01 从项目到产品&#xff1a;软件需要从物理…