失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > dockerfile 镜像构建

dockerfile 镜像构建

时间:2020-03-12 22:40:49

相关推荐

dockerfile 镜像构建

docker镜像的构建:commit与dockerfile

构建镜像

docker容器与镜像

当创建一个新容器时,docker会构建出一个镜像栈,每个只读镜像层都是只读的,并且以后永远不会变化,最后在栈的最顶端添加一个读写层。

docker commit(不推荐) 或者 dockerfile + docker build

1 docker commit方式构建镜像

本质上是以新建的容器来构建镜像。

1)创建账号 /

mazhen11

1805354On****

2)docker login登陆

#docker logout 登出

3)创建一个新容器 docker run -i -t ubuntu /bin/bash

4)容器中安装apache

apt-get -yqq update

apt-get -y install apache2

目前:我们启动了一个容器,并且安装了apache。为了不必每次都创建一个新的容器并在此在里面安装apache,所以想要保存该容器的当前状态。

5)执行exit 退出该容器

6)docker ps -l -q 获取刚创建容器的ID

7)docker commit 容器id mazhen11/apache2

说明:docker commit仅仅提交了创建容器镜像于容器当前状态之间有差异的部分,该更新非常轻量。

8)docker images mazhen11/apache2 查看新创建的镜像

也可以再提交镜像是指定更多的数据,如

docker commit -m"a new custom image" -a"mazhen" 43e83b7ccbf5 mazhen11/apache2:webservew

-m"a new custom image" :提交信息

-a"mazhen" :作者信息

43e83b7ccbf5 镜像id

mazhen11/apache2:webservew :用户名/仓库名 webservew标签

docker inspect mazhen11/apache2:webservew查看新镜像的详细信息

dockerfile方式构建镜像

1)宿主机中创建 构建上下文

mkdir static_web

cd static_web

touch Dockerfile

2)向dockerfile中写内容

# Version: 0.0.1

FROM ubuntu:14.04

MAINTAINER mazhen11 "mz@"

RUN apt-get update && apt-get install -y nginx

RUN echo 'hi, i am in your container' > /usr/share/nginx/html/index.html

EXPOSE 80

说明:MAINTAINER指令,该镜像的作者以及电子邮件

RUN指令默认会在shell里面使用命令包装器/bin/sh -c来执行,如果在不支持shell的平台或不希望在shell中运行,可以使用exec格式的RUN指令,如:

RUN ["apt-get", " install", " -y", " nginx"]

EXPOSE:告诉docker该容器内的应用程序将会使用容器的指定端口,但docker并不会自动打开该端口,需要在run容器是指定打开的端口。

基本语法:

1)每条指令都必须为大写字母,如FROM,且后面要跟随一个参数,如ubuntu:14.04

2)每个dockerfile的第一条指令必须是FROM。FROM指定一个已存在的镜像作为基础镜像,后续指令基于该镜像执行

dockerfile中指令整体上顺序执行,内部执行逻辑为:

1)docker从基础镜像运行一个容器

2)执行一条指令,对容器做出修改

3)执行类似docker commit的操作,提交一个新的镜像层

4)基于刚提交的镜像运行一个新的容器

5)执行dockerfile中的下一条指令,修改容器;直到所有指令执行完毕。

基于dockerfile构建新镜像

在Dockerfile文件所在路径下执行:docker build -t "mazhen11/static_web:v1" .

说明:后面的.代表当前路径下的Dockerfile。

-t设置镜像的仓库和名称,仓库为mazhen11,镜像名为static_web,镜像标签为v1

如果没有指定标签,docker会自动为镜像设置标签为latest。

使用URL /creack/docker-firefox 的 Dockerfile 创建镜像

docker build /creack/docker-firefox

也可以通过 -f Dockerfile 文件的位置:

$ docker build -f /path/to/a/Dockerfile .

dockerfile指令失败与调试

如果上面Dockerfile中将nginx错写成ngin,看看此时构建会有什么问题。

其中一段错误日志如下:

=> CACHED [1/3] FROM docker.io/library/ubuntu:14.04@sha256:63fce984528cec8714c365919882f8fb64c8a3edf23fdfa0b218a 0.0s

=> ERROR [2/3] RUN apt-get update && apt-get install -y ngin

生成的中间镜像是63fce984528,在执行apt-get update && apt-get install -y ngin命令的时候出错了。

dockerfile和构建中的缓存

由于每一步的构建过程都会将结果提交为镜像,所以在docker镜像的构建过程中,其会将之前的镜像看做缓存。

假设Dockerfile的内容如下:

FROM ubuntu:14.04

MAINTAINER mazhen11 "mz@"

RUN apt-get update && apt-get install -y ngin

RUN echo 'hi, i am in your container' > /usr/share/nginx/html/index.html

EXPOSE 80

那么在前三步中不会做任何修改,因此docker会将之前构建的镜像当做缓存,并作为新的开始点。

当再次构建时,docker会直接从第四步开始,能节省大量的时间。

但是有些场景,如apt-get update命令,我们需要获取最新的版本,此时不能缓存,可以使用的指令如下:

docker build --no-cache -t "mazhen11/static_web:v1" .

基于构建缓存的Dockerfile模板

为了充分使用构建缓存特性,我们可以使用简单的Dockerfile模板,这样每次通过Dockerfile构建时,都能命中缓存镜像,大大提升效率。

下面给出一个简单的Ubuntu相关镜像Dockerfile模板:

FROM ubuntu:14.04

MAINTAINER mzhen "mz@"

ENV REFRESHED_AT -12-31

RUN apt-get --qq update

该模板通过ENV指令设置了名为REFRESHED_AT的环境变量,该环境变量用来表明该镜像模板最后的更新时间。

RUN apt-get --qq update用来数显apt包的缓存,用来确保我们将要安装的每个软件都更新到最新版本。

如果需要更新,修改REFRESHED_AT对应的时间即可,会更新缓存中的镜像。

docker history

展示docker的完整构建过程

启动一个新容器

docker run -d -p 80 --name static_web mazhen11/static_web:v1 nginx -g "daemon off;"

-d:以detached(分离)的方式在后台运行,该方式适合运行类似Nginx守护进程这样的需要长时间运行的进程。

nginx -g "daemon off;" 以前台的方式启动nginx,作为我们的web容器

-p:控制Docker在运行时应该公开哪些网络端口给外部

Docker有两种方法在宿主机上分配端口。

1)随机:docker在32768-61000中随机选择一个较大的端口号映射到容器中的80端口,docker run即是这种方式。

2)绑端口:指定宿主机一个具体的端口映射到容器的80端口 如 -p 8080:80 会将容器内的80端口绑定到本地宿主机的8080端口

3)绑ip:如:-p 127.0.0.1

4)绑ip和端口:如:-p 127.0.0.1:80:80,即把容器的80端口绑定到宿主机127.0.0.1这个ip的80端口上

-P :对外公开Dockerfile中通过EXPOSE指令公开的所有端口

查看端口的分配情况

1)docker ps 如:结果包含0.0.0.0:32768->80/tcp 容器中的80 端口映射到宿主机的32768端口上

2)docker port 容器名id 结果:80/tcp -> 0.0.0.0:32768

dockerfile中的指令

包括CMD ENTRYPOINT ADD COPY VOLUME WORKDIR USER ONBUILD LABEL STOPSIGNAL ARG ENV

1 CMD 指定容器启动时要运行的命令。

1)与RUN区别:二者运行的时间点不同;CMD 在docker run(即容器启动)时运行;RUN在docker build(即构建镜像时)运行;

2)可以被 docker run指令和自身覆盖

a docker run命令可以覆盖CMD指令,如果在docker run命令行中有指令,且dockerfile中中也有CMD指令,那么此时CMD会被覆盖而失效。

b dockerfile中只能指定一条CMD指令。如果指定了多条CMD指令,则仅有最后一条生效。

CMD语法,CMD + 命令数组,如:

CMD [ "/bin/bash" ]

CMD ["/bin/bash", "-1"]

2 ENTRYPOINT

含义同CMD,区别

1)CMD后面的指令会被docker run后的指令覆盖,但ENTRYPOINT不会,而是将dcoker run后的指令放在ENTRYPOINT指令之后

2)如果确实想让docker run后的指令覆盖ENTRYPOINT,可以在docker run之后增加 --entrypoint标志

实例 如某dockerfile中包含如下语句:

ENTRYPOINT ["/usr/sbin/nginx"]

CMD ["-h"]

docker builder -t "mazhen11/static_web" . 使用上面dockerfile构建镜像mazhen11/static_web

docker run -t -i mazhen11/static_web -g "daemon off;" 根据镜像启动容器

那么最终ENTRYPOIN执行的命令是 /usr/sbin/nginx/ -g "daemon off;"

如果docker run中没有命令,那么ENTRYPOINT最终执行的命令是: /usr/sbin/nginx/ -h

3 WORKDIR

创建新容器时,在容器内部设置一个工作目录。CMD和ENTRYPOINT指定的命令可以在该目录下执行。

如下dockfile代码:

WORKDIR /opt/webapp/db

RUN bundle install

WORKDIR /opt/webapp

ENTRYPOINT ["rackup"]

如果docker run是不想让WORKDIR生效,可以采用 -w参数

如:docker run -ti -w /var/log ubuntu pwd

4 ENV

设置环境变量,如

ENV RVM_PATH /home/rvm

这个新的环境变量可以在后续任何RUN指令中使用,如同在命令前面指定了环境变量前缀一样,如

RUN gem install unicorn,那么实际该命令执行如下:

RVM_PATH=/home/rvm gem install unicorn

在别的指令中使用环境变量,如

WORKDIR $RVM_PATH

设置多个环境变量:

ENV RVM_PATH=/home/rvm RVM_AR="-arch i386"

上面设置的环境变量会被持久保存到从我们的镜像创建的任何容器,在容器中运行如下指令,则可以查看所有环境变量

env

也可以使用 docker run -e来传递环境变量,

如 docker run -ti -e "WEB_PORT=8080" ubuntu env

结果中会包含WEB_PORT=8080

5 USER

指定镜像运行的用户

ru:USER nginx:基于该镜像启动的容器会以nginx用户的身份来运行,还可以指定用户名、uid、组、组id

如:

USER user

USER user:group

USER uid

USER uid:gid

USER user:gid

USER uid:group

也可以再dcoker run命令中 通过-u来覆盖USER指令

说明:如果未指定用户则默认为root

6 VOLUME

向基于该镜像创建的容器中添加卷。

卷:一个特定的目录,该目录可以绕过联合文件系统,并提供数据共享或持久化的功能。

具体包括:

卷可以在容器间共享和重用

对卷的修改立刻生效

对卷的修改不会对镜像产生任何影响

卷会一直存在,直到没有任何容器使用

卷可以让我们将数据、数据库、源代码等添加到镜像而不必提交给镜像,且允许多个容器间共享这些内容。

VOLUME ["/opt/project"]

那基于该镜像创建的任何容器都创建一个名为/opt/project的挂载点。

指定多个卷

VOLUME ["/opt/project", "/data"]

7 ADD

将构建环境中的文件和目录复制到镜像中。如:

ADD software.lic /opt/application/software.lic

即将构建目录下的software.lic指令复制到镜像中的/opt/application/software.lic

其中源文件的位置参数可以是URL 或 构建上下文的文件名或者目录

Docker通过目的地址参数末尾的字符来判断源文件是目录还是文件,如果目的地址以/结束,docker认为源位置指向一个目录。

否则为文件。

如果源文件为tar文件,则目的文件则会自动解压缩

如 ADD latest.tar.gz /var/www/wordpress/,那么命令会将latest.tar.gz解压到/var/www/wordpress/

8 COPY

类似ADD,不同点:

1)文件源路径必须是一个与当前构建环境相对的文件或目录,本地文件都放到和Dockerfile同一目录

2)不会对tar文件自动解压缩

docker copy指令理解

COPY --from=0 /build/server /

COPY 指令的--from=0参数,从前边的阶段中拷贝文件到当前阶段中,多个FROM语句时,0代表第一个阶段。除了使用数字,我们还可以给阶段命名,比如:

# 编译阶段 命名为 builder

FROM golang:1.10.3 as builder

# ... 省略

# 运行阶段

FROM scratch

# 从编译阶段的中拷贝编译结果到当前镜像中

COPY --from=builder /build/server /

更为强大的是,COPY --from不但可以从前置阶段中拷贝,还可以直接从一个已经存在的镜像中拷贝。比如,

FROM ubuntu:16.04

COPY --from=quay.io/coreos/etcd:v3.3.9 /usr/local/bin/etcd /usr/local/bin/

我们直接将etcd镜像中的程序拷贝到了我们的镜像中,这样,在生成我们的程序镜像时,就不需要源码编译etcd了,直接将官方编译好的程序文件拿过来就行了。

9 LABEL

添加元数据,元数据以键值对的形式展现。如:

LABEL type="date cneter" role="web server"

10 STOPSIGNAL

设置停止容器时,发送什么系统调用信号给容器。如9 SIGKILL

11 ARG

定义可以在docker build命令运行时传递的变量。标志为--build-arg

如dockerfile中包含如下内容:

ARG build

ARG webapp_user=user

docker build --build-arg build=1224 -t mazhen11/webapp .

那么在构建mazhen11/webap镜像时,build会被设置为1224,webapp_user变量则会集成设置的默认值user。

docker预定义了一些ARG变零,包括HTTP_PROXY http_proxy HTTPS_PROXT FTP_PROXY NO_PROXY

12 ONBUILD

为镜像添加触发器,当一个镜像被用作别的镜像的基础镜像,该镜像中的触发器将会被执行。

如某dockerfile包含:

ONBUILD ADD . /app/src

上面dockerfile执行build构建出来的镜像(名为mazhen11/apache2)就会有触发器。

docker inspect能查看镜像中的触发器。

以上面mazhen11/apache2为基础镜像,创建新的dockerfile,内容如下:

FROM mazhen11/apache2

MATAINER mazhen "a@"

ENV APPLICATION_NAME webapp

那么在依据上面dockerfile构建镜像时,会在FROM后执行ADD . /app/src指令。

ONBUILD触发器会按照在父镜像中的顺序执行,并且只能被继承一次,不会在孙子镜像中执行。

将镜像推送到docker hub

docker push mazhen11/static_web

说明 mazhen11是仓库名称,如果省略了仓库名称,即直接执行:docker push static_web

那么docker是任务你想要推送到root仓库,而root仓库是由docker公司的团队管理的,所以会被拒绝和失败。

镜像删除

docker rmi mazhen11/static_web

说明:该操作只能删除本地的镜像。如果想删除一个docker hub上的镜像仓库,需要在登陆docker hub后使用delete repository连接来删除。

rmi删除多个镜像的语法:

docker rmi mazhen11/apache2 mazhen11/puppetmaster

docker rmi `docker images -a -q`

运行自己的docker registry

有时存在不想公开的信息或数据的镜像,此时有两种选择:

1)使用docker hub上的私有仓库

2)在防火墙后面运行自己的registry

从容器运行registry

docker run -p 5000:5000 registry:2

该命令会启动一个运行registry2.0版本的容器,并将5000端口绑定到本宿主机。

使用新的registry方法如下:

1)获取镜像id

docker images

这里取镜像id:257e8cbe4448

2)打标签

docker tag 257e8cbe4448 :50000/mazhen11/static_web

说明:为了制定新的registry目的地址,需要在镜像名前加上主机名和端口前缀。

3)推送到新的registry

docker push :50000/mazhen11/static_web

如果觉得《dockerfile 镜像构建》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。