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,一经查实,立即删除!

相关文章

创业的N种死法

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

Docker容器实战思维

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

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

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

了解.NET中的垃圾回收

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

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

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

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

数据结构与算法–字符串&#xff1a;字符串替换 字符串的优化 由于字符串在编程时候使用的评率非常高&#xff0c;为了优化&#xff0c;很多语言都对字符串做了特殊的规定。下面我们讨论java中字符串的特性java中的字符数组以’\0’ 结尾&#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;您可能不会…

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…

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

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

Redis高效性探索--线程IO模型,通信协议

Redis线程IO模型 Redis是单线程&#xff0c;这个毋庸置疑Redis单线程能做到这么高的效率&#xff1f;不用怀疑&#xff0c;还有很多其他的服务都是单线程但是也有超高的效率&#xff0c;比如Node.js&#xff0c;Nginx也是单线程。Redis单线程高效原因&#xff1a; Redis所有数…

Redis持久化-深入理解AOF,RDB

持久化 Redis数据全部在内存中&#xff0c;如果宕机&#xff0c;数据必然丢失&#xff0c;因此必须有一种机制保证Redis数据不会因为故障丢失&#xff0c;这就是Redis的持久化机制持久化方式两种&#xff1a;AOF&#xff0c;RDB&#xff0c;如下图 RDB快照模式是一次全量备份&…

推荐一个集录屏、截图、音频于一体的软件给大家

捕获屏幕&#xff0c;网络摄像头&#xff0c;音频&#xff0c;光标&#xff0c;鼠标单击和击键GitHub&#xff1a;https://github.com/MathewSachin/Captura特性 免费 100%免费&#xff0c;你不需要花一分钱开源 根据MIT许可的条款&#xff0c;可以在Github上获得Captura的源…

Redis高效性探索--管道

管道 开始接触Redis时候&#xff0c;对应Redis管道有一个错误认识&#xff0c;任务是redis服务器提供的一种特别的技术&#xff0c;有了这种技术可以加速Redis的存取效率&#xff0c;但是实际上Redis的管道计算&#xff08;Pipeline&#xff09;本身是客户端提供的技术&#x…

Redis--事务理解

事务 一个成熟的数据库系统一般都会有事务的支持&#xff0c;Redis作为一个缓存数据库也不例外&#xff0c;Redis的事务比之关系型数据库mysql&#xff0c;oracle等算比较简单的&#xff0c;Redis中无需理解那么多事务模型&#xff0c;可以直接使用。不过也正是因为简单&#…

.NET中的内存管理

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。 .NET中的内存管理资源分配Microsoft .NET公共语言运行时要求从托管堆分配所有资源。当应用程序不再需要对象时&#xff0c;它们将自动释放。初始化进程后&#xff0c;运行时将保留地址空间的连续区域&#xff0c;该区域最…

Redis存储优化--小对象压缩

小对象压缩 Redis是一种内存数据库&#xff0c;内存是计算机中一种比较宝贵的资源&#xff0c;如果我们不注意节约&#xff0c;Redis很可能出现内存不足&#xff0c;最终导致崩溃。Redis为了优化数据结构的内存占用&#xff0c;增加了非常多的优化点&#xff0c;这些优化也是牺…

.Net微服务实战之技术架构分层篇

一拍即合上一篇《.Net微服务实战之技术选型篇》&#xff0c;从技术选型角度讲解了微服务实施的中间件的选择与协作&#xff0c;工欲善其事&#xff0c;必先利其器&#xff0c;中间件的选择是作为微服务的基础与开始&#xff0c;也希望给一直想在.Net入门微服务的同行有一个很好…

Redis高可用基石--主从同步

主从同步 当我们将Redis用于线上环境&#xff0c;单机肯定是不行的&#xff0c;即使不做集群&#xff0c;我们也应该做主从&#xff0c;有了主从&#xff0c;当主节点&#xff08;master&#xff09;挂掉时候&#xff0c;让运维将从节点&#xff08;slave&#xff09;接管&…