设为首页 收藏本站
查看: 1281|回复: 0

[经验分享] Docker快速入门——Docker镜像制作

[复制链接]

尚未签到

发表于 2019-2-20 11:28:01 | 显示全部楼层 |阅读模式
Docker快速入门——Docker镜像制作

一、Dockerfile脚本

1、Dockerfile脚本简介
  Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容就是描述该层应当如何构建。
Dockerfile文件示例如下:

##  Dockerfile文件格式
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# 1、第一行必须指定 基础镜像信息
FROM centos
# 2、维护者信息
MAINTAINER docker_user docker_user@email.com
# 3、镜像操作指令
RUN yum install -y nginx
# 4、容器启动执行指令
CMD /usr/sbin/nginx
  Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动执行指令。第一部分必须指明基础镜像名称;第二部分通常说明维护者信息;第三部分是镜像操作指令,例如RUN指令,每执行一条RUN 指令,镜像添加新的一层,并提交;第四部分是CMD指令,指明运行容器时的操作命令。
Dockerfile官方文档:
https://docs.docker.com/engine/reference/builder/
Dockerfile最佳实践文档:
https://docs.docker.com/engine/userguide/eng-
image/dockerfile_best-practices/
Docker官方镜像Dockerfile:
https://github.com/docker-library/docs

2、FROM指令
  FROM用于指定基础镜像,因此Dockerfile中FROM是必备指令,并且必须是第一条指令。
在Docker Store有非常多的高质量的官方镜像,有直接可用的服务类镜像,如nginx、redis、mongo、mysql 、httpd、ph、tomcat    等;有方便开发、构建、运行各种语言应用的镜像,如node、openjdk、 python、ruby、golang等;有基础的操作系统镜像,如ubuntu、debian、centos、fedora、alpine等。
Docker存在一个特殊的scratch镜像,scratch镜像是虚拟的概念,并不实际存在,表示一个空白的镜像。
如果以scratch  为基础镜像,不以任何镜像为基础,后续所写的指令将作为镜像第一层开始存在。不以任何系统为基础,直接将可执行文件复制进镜像如swarm、coreos/etcd。Linux下静态编译的程序并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里,因此直接FROM scratch会让镜像体积更加小巧。
FROM语法格式为:

FROM
FROM :
FROM :
  FROM限制如下:
A、FROM必须是Dockerfile中第一条非注释命令
B、在一个Dockerfile文件中创建多个镜像时,FROM可以多次出现。只需在每个新命令FROM前,记录提交上次的镜像ID。
C、tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像。

3、RUN指令
  在镜像的构建过程中执行特定的命令,并生成一个中间镜像。格式:

#shell格式
RUN
#exec格式
RUN ["executable", "param1", "param2"]
  RUN命令将在当前image中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行Dockerfile中的下一个指令。
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache。

4、COPY指令
  COPY指令语法格式:

COPY ...     
COPY ["",...  ""]   
  COPY    指令将从构建上下文目录中的文件/目录复制到新的一层的镜像内的位置。
可以是多个,甚至可以是通配符,其通配符规则要满足Go 的filepath.Match规则,如:

COPY hom* /mydir/
COPY hom?.txt /mydir/
  目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用WORKDIR指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
使用COPY指令,源文件的各种元数据都会保留,比如读、写、执行权限、文件变更时间等。

5、ADD指令
  ADD指令在COPY基础上增加了一些功能,比如可以是一个URL,Docker引擎会试图去下载URL链接的文件放到。
在构建镜像时,复制上下文中的文件到镜像内,格式:

ADD ...
ADD ["",... ""]
  如果Docker发现文件内容被改变,则后续指令都不会再使用缓存。

6、CMD指令
  CMD用于指定在容器启动时所要执行的命令。CMD有三种格式:

CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
  省略可执行文件的exec格式,使CMD中的参数当做ENTRYPOINT的默认参数,此时ENTRYPOINT应该是exec格式。
如果CMD是/bin/bash,使用docker run -it ubuntu启动容器时,会直接执行进入bash。docker run -it ubuntu cat /etc/os-release会在启动容器时输出系统版本信息。
在CMD指令格式上,推荐使用exec格式,exec格式在解析时会被解析为JSON数组,因此必须使用双引号,而不要使用单引号。
如果使用shell格式,CMD命令会被包装为sh -c的参数的形式进行执行。比如:
CMD echo    $HOME会将其变更为:
CMD ["sh",  "-c","echo  $HOME"]

7、ENTRYPOINT指令
  ENTRYPOINT指令用于给容器配置一个可执行程序。每次使用镜像创建容器时,通过ENTRYPOINT指定的程序都会被设置为默认程序。ENTRYPOINT有两种形式:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
  通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
docker run运行容器时指定的参数都会被传递给ENTRYPOINT,且会覆盖 CMD命令指定的参数。执行docker run image -d时,-d指定的参数将被传递给入口点。也可以通过docker run --entrypoint重写 ENTRYPOINT 入口点。
ENTRYPOINT ["/usr/bin/nginx"]

8、ENV指令
  ENV指令用于设置环境变量,后续的指令可以直接使用。

ENV  
ENV = =...
  ENV示例如下:

ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"
9、ARG指令
  ARG指令用于指定传递给构建运行时的变量。

ARG [=]
  通过ARG指定两个变量:

ARG site
ARG build_user=scorpio
  上述指令指定site和build_user两个变量,其中build_user指定了默认值。使用docker build构建镜像时,可以通过

--build-arg =
  选项参数来指定或重设置相应变量的值。
docker build --build-arg site=www.baidu.com -t baidu/test .
build_user变量使用默认值scorpio。

10、VOLUME指令
  VOLUME指令用于创建挂载点,即向基于所构建镜像创始的容器添加卷:
VOLUME ["/data"]
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
A、卷可以容器间共享和重用
B、容器并不一定要和其它容器共享卷
C、修改卷后会立即生效
D、对卷的修改不会对镜像产生影响
E、卷会一直存在,直到没有任何容器在使用它
VOLUME可以将源代码、数据或其它内容添加到镜像中,而不提交到镜像中,并使多个容器间共享数据。

11、EXPOSE指令
  EXPOSE指令为构建的镜像设置监听端口,使容器在运行时监听。格式如下:

EXPOSE  [...]
  EXPOSE指令并不会让容器监听host的端口,如果需要容器监听Host端口,需要在docker run时使用 -p、-P 参数来发布容器端口到host的某个端口上。

12、WORKDIR指令
  WORKDIR指令用于在容器内设置一个工作目录。
WORKDIR /path/to/workdir
通过WORKDIR设置工作目录后,Dockerfile中的后续命令RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在工作目录下执行。

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
  pwd最终将会在 /a/b/c 目录中执行。使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。

13、USER指令
  USER指令用于指定运行镜像所使用的用户。
USER daemon
使用USER指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。

USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
  使用USER指定用户后,Dockerfile中的后续命令RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过docker run 运行容器时,可以通过-u参数来覆盖所指定的用户。

14、HEALTHCHECK指令
  HEALTHCHECK [OPTIONS] CMD command  
通过运行一个容器内部的命令来检测容器是否健康
HEALTHCHECK NONE
关闭任何来自基础image的健康检测
options
--interval=DURATION (default: 30s)
--timeout=DURATION (default: 30s)
--retries=N (default: 3)

15、ONBUILD指令
  ONBUILD指令用于设置镜像触发器。
ONBUILD [INSTRUCTION]
当所构建的镜像被用作其它镜像的基础镜像,镜像中的触发器将会被触发。当镜像被使用时,可能需要做一些处理:

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
16、LABEL
  LABEL指令用于为镜像添加元数据,元数以键值对的形式指定。

LABEL = = = ...
  使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
LABEL version="1.0" description="hello world" by="scorpio"
LABEL指定的元数据可以通过docker inspect查看。

17、STOPSIGNAL
  STOPSIGNAL指令用于设置停止容器所要发送的系统调用信号。
STOPSIGNAL signal
所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。

18、SHELL
  SHELL指令用于设置执行命令(shell)所使用的的默认shell类型。
SHELL ["executable", "parameters"]
SHELL在Windows环境下比较有用,Windows下通常会有cmd和 powershell两种shell,可以通过SHELL来指定所使用的shell类型。

二、Dockerfile构建镜像

1、Dockerfile构建简介
  docker build命令会根据Dockerfile文件及上下文构建新Docker镜像。构建上下文是指Dockerfile所在的本地路径或一个URL(Git仓库地址)。构建上下文环境会被递归处理,所以构建所指定的路径还包括子目录,而URL还包括其中指定的子模块。
构建会在Docker后台守护进程(daemon)中执行,而不是CLI中。构建前,构建进程会将全部内容(递归)发送到守护进程。通常,应该将一个空目录作为构建上下文环境,并将Dockerfile文件放在该目录下。
在构建上下文中使用的Dockerfile文件,是一个构建指令文件。为了提高构建性能,可以通过.dockerignore文件排除上下文目录下不需要的文件和目录。
在Docker构建镜像的第一步,docker CLI会先在上下文目录中寻找.dockerignore文件,根据.dockerignore 文件排除上下文目录中的部分文件和目录,然后把剩下的文件和目录传递给Docker服务。
Dockerfile文件一般位于构建上下文的根目录下,也可以通过-f指定Dockerfile文件的位置:
docker build -f /path/to/a/Dockerfile .
构建时,还可以通过-t参数指定构建成镜像的仓库、标签。如果存在多个仓库下,或使用多个镜像标签,就可以使用多个-t参数:
docker build -t nginx/v3:1.0.2 -t nginx/v3:latest .
在Docker守护进程执行Dockerfile中的指令前,首先会对Dockerfile进行语法检查,有语法错误时会返回错误提示信息。
Dockerfile文件:

FROM ubuntu:14.04  
ADD run.sh /  
VOLUME /data  
CMD ["./run.sh"]  
  Dockerfile文件构建的容器如下:


2、同构的镜像构建
  同构的镜像构建是指镜像构建环境与运行环境兼容。
同构镜像构建一般要求编译环境与镜像所使用的base image是兼容的,比如在Ubuntu 14.04上编译应用,并将应用打入基于ubuntu系列base image的镜像。因为应用的编译环境与其部署运行的环境是兼容的,在Ubuntu 14.04下编译出来的应用,可以基本无缝地在基于ubuntu:14.04及后续版本base image镜像中运行;但在不完全兼容的base image中,比如CentOS中就可能会运行失败。

package main
import (
"net/http"
"log"
"fmt"
)
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Welcome to this website!\n"))
}
func main() {
http.HandleFunc("/", home)
fmt.Println("Webserver start")
fmt.Println("  -> listen on port:1111")
err := http.ListenAndServe(":1111", nil)
if err != nil {
log.Fatal("ListenAndServe:", err)
}
}
  编译:
go build -o httpserver httpserver.go 
Dockerfile文件:

From ubuntu:14.04
COPY ./httpserver /root/httpserver
RUN chmod +x /root/httpserver
WORKDIR /root
ENTRYPOINT ["/root/httpserver"]
  构建httpserver服务镜像:
docker build -t httpserver:latest . 
启动httpserver服务容器:
docker run httpserver 
基于ubuntu基础镜像构建出的应用镜像太过臃肿,因此有必要基于golang:latest构建自己专用的golang-builder image,Dockerfile.build可以用于build golang-builder image:

FROM golang:latest
WORKDIR /go/src
COPY httpserver.go .
RUN go build -o httpserver ./httpserver.go
  构建golang-builder镜像:
docker build -t golang-builder:latest -f Dockerfile.build . 
从golang-builder创建一个容器appsource
docker create --name appsource golang-builder:latest
从appsource容器中将httpserver拷贝到主机当前目录
docker cp appsource:/go/src/httpserver ./
删除appsource容器
docker rm -f appsource
删除golang-builder镜像
docker rmi golang-builder:latest
从当前目录构建出httpserver镜像
docker build -t httpserver:latest .
httpserver镜像的大小依旧停留在200MB。要想减小httpserver镜像的大小,必须使用更小的base image,即alpine 。 Alpine image的大小不到4M,再加上应用的size,最终应用镜像的大小估计可以缩减到20M以下。
Dockerfile.alpine 文件:

From alpine:latest
COPY ./httpserver /root/httpserver
RUN chmod +x /root/httpserver
WORKDIR /root
ENTRYPOINT ["/root/httpserver"]
  构建alpine版应用镜像:
docker build -t httpserver-alpine:latest -f Dockerfile.alpine .
启动httpserver-alpine容器会失败,因为alpine image并非ubuntu环境的同构image。

3、异构的镜像构建
  异构镜像构建是指构建环境与运行环境不兼容。
Go将runtime中的C代码都用Go重写,对libc的依赖已经降到最低,但提供了两个版本的实现:C实现和Go实现。默认情况下,即在CGO_ENABLED=1情况下,程序和预编译的标准库都采用C的实现。因此采用不同libc实现的debian系和alpine系自然存在不兼容的情况。考虑异构镜像创建首先对Go程序进行静态构建,然后将静态构建后的Go应用放入alpine image中。
Dockerfile.build文件如下:

FROM golang:alpine
WORKDIR /go/src
COPY httpserver.go .
RUN go build -o httpserver ./httpserver.go
  构建builder镜像:

docker build -t myrepo/golang-static-builder:latest -f Dockerfile.build . 
docker create --name appsource golang-static-builder:latest
docker cp appsource:/go/src/httpserver ./
docker rm -f appsource
docker rmi golang-static-builder:latest
docker build -t httpserver-alpine:latest -f Dockerfile.alpine .
  运行httpserver服务容器:
docker run httpserver-alpine:latest 
alpine版golang builder镜像Dockerfile:

FROM golang:alpine
WORKDIR /go/src
COPY httpserver.go .
RUN go build -o httpserver ./httpserver.go
三、Docker多阶段构建

1、Dockerfile多阶段构建
  2017年5月发布的 Docker 17.05.0-ce 中,Docker官方提供了简便的多阶段构建(multi-stage build)方案。
对于多阶段构建,可以在Dockerfile中使用多个FROM语句。每个FROM指令可以使用不同的基础镜像,作为一个构建阶段,多条 FROM 就是多阶段构建,虽然最后生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中的文件拷贝到后边的阶段中。
多阶段构建最大的使用场景是将编译环境和运行环境分离。

# 编译阶段
FROM golang:1.10.3
COPY server.go /build/
WORKDIR /build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOARM=6 go build -ldflags '-w -s' -o server
# 运行阶段
FROM scratch
# 从编译阶段的中拷贝编译结果到当前镜像中
COPY --from=0 /build/server /
ENTRYPOINT ["/server"]
  Dockerfile的COPY指令--from=0参数,从前边的阶段中拷贝文件到当前阶段中,多个FROM语句时,0代表第一个阶段。除了使用数字,还可以给阶段命名,比如:

# 编译阶段
FROM golang:1.10.3 as builder
COPY server.go /build/
WORKDIR /build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOARM=6 go build -ldflags '-w -s' -o server
# 运行阶段
FROM scratch
# 从编译阶段的中拷贝编译结果到当前镜像中
COPY --from=builder /build/server /
ENTRYPOINT ["/server"]
  COPY –from指令从单独的image中复制,使用本地image名称,本地或Docker镜像仓库中可用的标记或标记ID。 

2、停在特定构建阶段
  构建映像时,不一定需要构建整个Dockerfile文件的每个阶段,可以指定目标构建阶段。使用Dockerfile构建,在builder阶段停止:
docker build --target builder -t builder:latest .
停在特定构建阶段非常适合的场景如下:
A、调试特定的构建阶段
B、在debug阶段,启用所有调试或工具,而在production阶段尽量精简
C、在testing阶段,应用程序将填充测试数据,但在production阶段则使用生产数据

3、Dockerfile多项目构建
  利用多阶段构建可以多个项目的二进制文件构建在一个镜像中发布。

from debian as build-essential
arg APT_MIRROR
workdir /src
from build-essential as A
copy srcA .
run make
from build-essential as B
copy srcB .
run make
from alpine
copy --from=A binA .
copy --from=B binB .
cmd ...
四、C++镜像制作

1、C++应用开发
  HelloDocker.cpp文件如下:

#include
int main()
{
std::cout

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-674837-1-1.html 上篇帖子: Jenkins在Kubernetes中构建Docker镜像并推送至Registry 下篇帖子: Docker快速入门——Docker
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表