ad如何镜像器件_使用 Dockerfile 制作镜像

前面几篇文章已经给大家介绍了 Docker 的基本概念,相信大家也会使用 Docker 运行自己想要的容器了。但是只有学会制作镜像,才能将 Docker 应用到我们的项目中去。下面我们就来学习如何使用 Dockerfile 来制作镜像。

Dockerfile 是一个文本文件,里面的内容是一条条的指令,每一条指令将会构建一层,因此每条指令的内容就是在描述该层应当如何创建。

编写 Dockerfile

接下来以 nginx 镜像为例,定制一个简单的镜像,首先创建一个目录 mynginx,进入目录再创建一个文本文件,名字为 Dockerfile。

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile

把以下内容写到 Dockerfile 中

FROM nginx
RUN echo '<h1>Hello, Docker!<h1>' > /usr/share/nginx/html/index.html

其中 FROM 用来指定基础镜像,上面的例子是以 nginx 为基础镜像。

RUN 命令则表示执行一个 shell 命令,将文本写进 index.html

构建命令详解

编写完 Dockerfile 之后就可以用来构建镜像。构建 docker 镜像的命令如下:

$ docker build [OPTIONS] PATH | URL | -

选项的说明如下:

--build-arg=[] 设置镜像创建时的变量--cpu-shares 设置 CPU 使用权重--cpu-period 限制 CPU CFS 周期--cpu-quota 限制 CPU CFS 配额--cpuset-cpus 指定使用的 CPU--cpuset-mems 指定使用的内存 id--disable-content-trust 忽略检验,默认开启-f 指定要使用的 Dockerfile 路径--force-rm 设置镜像过程中删除中间容器--isolation 使用容器隔离技术--label=[] 设置镜像使用的元数据-m 设置内存最大最--memory-swap 设置 Swap 的最大值为内存 + swap,'-1' 表示不限 swap--no-cache 创建镜像的过程中不适用缓存--pull 尝试更新镜像的新版本--quiet,-q 安静模式,成功后只输出镜像 ID--rm 设置镜像成功后删除中间容器--shm-size 设置 /dev/shm 的大小,默认值是 64M--ulimit Ulimit 配置--tag,-t 镜像的名字及标签,通常 name:tag 或者 name 格式,可以在一次构建中为一个镜像设置多个标签--network 默认 default。在构建期间设置 RUN 指令的网络模式

下面举几个例子,说明选项的用法

  • 使用当前目录的 Dockerfile 创建镜像,标签为 fedevelop/example:v1
$ docker build -t fedevelop/example:v1 .
  • 使用 URL http://github.com/ad-feiben/qc-remind 的 Dockerfile 创建镜像
$ docker build github.com/ad-feiben/qc-remind
  • 通过 -f Dockerfile 文件的位置
$ docker build -f /path/to/a/Dockerfile .

回到 mynginx 目录中执行下面的命令

$ docker build -t nginx:v2 .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx---> f949e7d76d63
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html---> Running in 88dc64292fa7
Removing intermediate container 88dc64292fa7---> 5d1e253d361c
Successfully built 5d1e253d361c
Successfully tagged nginx:v2

注意不要漏了最后的 .. 代表将当前目录设置为镜像构建上下文(Context)。

例如 Dockerfile 的内容如下:

COPY ./requirements.txt /app/

意思为复制上下文目录下的 requirements.txt,与 Dockerfile、执行 docker build 所在的目录无关。

构建完成后,我们可以通过 Docker images 查看我们构建的镜像

$ docker images
docker images
REPOSITORY              TAG                 IMAGE ID            CREATED              SIZE
nginx                   v2                  5d1e253d361c        About a minute ago   126MB
nginx                   latest              f949e7d76d63        4 weeks ago          126MB

接下来用我们定制的镜像来启动一个容器看看,其中 5d1e253d361c 替换为你的镜像 id

$ docker run -it -p 80:80 5d1e253d361c

浏览器打开 http://localhost/ 可以看到页面显示的是 Hello, Docker!,说明我们的 Dockerfile 中的命令生效了。

指令详解

FROM 指定基础镜像

FROM 是用来指定基础镜像,这个命令是 Dockerfile 中必备的指令,并且必须是第一条指令。

假如不需要基础镜像,可以使用空白镜像 scratch 作为基础镜像。scratch 这个镜像是虚拟的,实际并不存在。

FROM scratch
...

RUN 执行命令

从上面的例子中可以看到 RUN 可以执行一个 shell 命令,除了此之外还有另一种格式。

exec 格式:RUN ["可执行文件", "参数"]

我们在编写 Dockerfile 的时候需要尽可能将指令链接起来,因为 Dockerfile 中的每一条指令都会建立一层,如果建立太多层,不仅会使得镜像非常臃肿,也会增加构建时间。

# 错误示范
FROM debian:stretchRUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

正确的写法如下,使用 && 将多条命令合并为一条,并且删除不必要的文件、清理 apt 缓存等,尽量保持容器干净。如果没有做清理工作的话,这些冗余的文件等将会带到下一层,并且会一直跟随镜像。

FROM debian:stretchRUN buildDeps='gcc libc6-dev make wget' && apt-get update && apt-get install -y $buildDeps && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" && mkdir -p /usr/src/redis && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 && make -C /usr/src/redis && make -C /usr/src/redis install && rm -rf /var/lib/apt/lists/* && rm redis.tar.gz && rm -r /usr/src/redis && apt-get purge -y --auto-remove $buildDeps

WORKDIR 指定工作目录

WORKDIR 的格式为 WORKDIR <工作目录路径>

当使用 WORKDIR 指定工作路径后,以后的每一层的当前目录都会被改为工作目录,如果目录不存在,WORKDIR 会帮助我们创建目录。

如果需要改变以后各层的工作目录的位置,只需要再使用 WORKDIR 指令即可。

COPY 复制文件

COPY 的格式为 COPY [--chown=<user>:<group>] <源路径>... <目标路径>

源路径可以是多个,也可以使用通配符,例如下面这样:

COPY hom* /mydir/
COPY hom?.txt /mydir/

目标路径可以是容器内的绝对路径,也可以相对工作目录的相对路径。目标路径不需要我们创建,如果目标路径不存在会在复制文件前先行创建缺失的目录。

使用 COPY 复制文件时,会保留文件的元数据,比如读写权限,文件变更的时间等。如果需要修改文件的所属用户及所属组,可以通过添加 --chown=<user>:<group> 选项进行修改。

CMD 容器启动命令

shell 格式为 CMD <命令>

exec 格式为 CND ["可执行文件", "参数1", "参数2"]

使用 shell 格式的话,实际的命令会被包装成 sh -c 的形式进行执行,比如:

CMD echo $HOME 在实际执行中,将会变成 CMD [ "sh", "-c", "echo $HOME" ]

所以在使用 CMD 的时候一般推荐使用 exec 的格式,需要注意的是 exec 的格式会被解析成 JSON 数组,所以只能够使用双引号,而不能使用单引号。


Dockerfile 的指令不止这么几个,感兴趣的小伙伴可以到 https://yeasy.gitbooks.io/docker_practice/image/dockerfile/ 自行查看。

示例

下面将通过我的 Python 项目来演示,怎么编写一个 Dockerfile,文件地址在 https://raw.githubusercontent.com/AD-feiben/qc-remind/master/Dockerfile

文件的内容如下:

# 指定基础镜像
FROM python:3.7.4# 设置镜像作者
MAINTAINER feiben <feiben.dev@gmail.com># 设置工作目录
WORKDIR /app# 复制上下文的文件到容器的 app 目录下
# 不需要复制到镜像的文件可以使用 .dockerignore 进行忽略
COPY . /app# 执行下面命令,同步时区,安装依赖
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone && pip install -r requirements.txt# 启动容器
CMD ["python", "main.py", "--log-file-prefix", "qc-remind.log"]

当我们的代码编写完成后,就可以执行 docker build -t <name>:<tag> . 将代码打包成一个 Docker 镜像,再 push 到镜像仓库中。

部署

按照传统的方式部署项目,通常需要在服务器安装一套运行环境,而且常常会遇到环境不一致导致本地开发没问题,一到线上部署就出现各种问题的情况。并且一旦服务器到期,迁移的工作量也是十分巨大。

而使用 Docker,我们只需要再服务器安装一个 Docker 环境即可,部署项目只需要执行 docker run xxx。不仅减少了安装环境的时间,也保证了环境的一致性。


如果你喜欢我的文章,希望可以关注一下我的公众号【前端develop】

61a377f66679ac7c0944606ca0ad6844.png
前端develop

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

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

相关文章

centos7.5部署ELk

第1章 环境规划 1.1 ELK介绍 ELK是ElasticSerach、Logstash、Kibana三款产品名称的首字母集合&#xff0c;用于日志的搜集和搜索。 Elasticsearch&#xff1a;是一个开源分布式搜索引擎&#xff0c;提供搜集、分析、存储三大功能&#xff0c;特点是分布式、零配置、自动发…

使用Google Test的一个简单例子

0. 引子 本例是从 gtest-1.5.0 自带的 sample 中的 sample1 改写而来&#xff0c;笔者只添加了一个求 n 的阶层的函数&#xff0c;如下。 void Factorial(int n, int & result ) { result 1; for (int i 1; i < n; i) result * i; } 目的是想测试像这样将返回值放在参…

Java静态方法与非静态方法的泛型

Java中&#xff0c;非静态方法可以使用类的泛型&#xff0c;也可以定义自己的泛型&#xff1b;静态方法由于随着类的加载而加载&#xff0c;不能访问类的泛型&#xff08;因为在创建对象的时候才确定&#xff09;&#xff0c;因此必须定义自己的泛型类型。 详细请参考&#xf…

Android Studio 日志工具

在项目中提供5个方法打印日志 Log.v() 最常见的日志信息 Log.d() 调试信息 Log.i() 用于打印用户操作行为 Log.w()警告潜在风险 Log.e()报错信息 TAG 填入类名就好 msg:要打印的信息 也可以对信息进行过滤 点他弹出自定义的日志过滤器 转载于:https://www.cnblogs.com/feizianq…

jpa加密_使用JPA侦听器的数据库加密

jpa加密最近&#xff0c;我不得不将数据库加密添加到一些字段中&#xff0c;并且发现了很多不好的建议。 建筑问题 最大的问题是建筑。 如果持久性管理器静静地处理您的加密&#xff0c;那么根据定义&#xff0c;您的体系结构将在持久性和安全性设计之间要求紧密而不必要的绑…

同一进程中的线程究竟共享哪些资源

线程共享的环境包括&#xff1a;进程代码段、进程的公有数据(利用这些共享的数据&#xff0c;线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这许多共性的同时&#xff0c;还拥有自己的个性。有了这些…

物联lot是什么意思_什么是物联网,物联网(lOT)简介

什么是物联网物联网(The Internet of Things&#xff0c;简称IOT)是指通过各种信息传感器、射频识别技术、全球定位系统、红外线感应器、激光扫描器等各种装置与技术&#xff0c;实时采集任何需要监控、 连接、互动的物体或过程&#xff0c;采集其声、光、热、电、力学、化 学、…

Python 位操作运算符

&按位与运算符&#xff1a;参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0(a & b) 输出结果 12 &#xff0c;二进制解释&#xff1a; 0000 1100|按位或运算符&#xff1a;只要对应的二个二进位有一个为1时&#xff0c;结果位就为1。(a | b) 输出结果 6…

JavaOne 2016后续活动

我很高兴今年参加了JavaOne&#xff0c;我可以用一个词概括一下这一经验&#xff1a;Brilliant。 对于我来说&#xff0c;今年与往年相比有很大不同&#xff0c;因为我在周日有一个演讲要共同演讲&#xff0c;而我剩下的一周时间都可以参加会议。 因此&#xff0c;我了解到在Ja…

python对初学者的看法_python学习之道(1)——新手小白对print()函数的理解,Python,之路,一,浅谈...

Python学习之路(一) ——浅谈新手小白对print()函数的理解写在前面笔者目前为在校大四学生(某末流211)&#xff0c;大学生活即将画上终点&#xff0c;然而却还没有真正精通一门语言&#xff0c;很是惭愧。在大学期间参加了各种文体活动&#xff0c;获得了很多次演讲比赛的奖项&…

理解Windows内核模式与用户模式

&#xfeff;&#xfeff;1、基础 运行 Windows 的计算机中的处理器有两个不同模式&#xff1a;“用户模式”和“内核模式”。根据处理器上运行的代码的类型&#xff0c;处理器在两个模式之间切换。应用程序在用户模式下运行&#xff0c;核心操作系统组件在内核模式下运行。多个…

判断使用设备是PC还是phone

<script type"text/javascript"> //如果是手机设备&#xff0c;则.. if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {window.location.href "http://www."; } </script><style type"text/css"> me…

求1+2+3+...+n

题目描述 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C&#xff09;。 1、根据基本公式展开&#xff0c;利用java的幂函数代替乘法&#xff0c;利用位移运算代替除法 public class Solution {pub…

1 京东_推荐好友拿好礼 | 每1积分可兑换30元京东电子卡

三季度转推介活动火热进行中该积分最终以被推荐客户9月30日金融资产余额为依据积分兑现时间为活动结束后15个工作日我行会将京东电子卡密码通过短信方式直接发送至推荐客户预留手机号码上(请推荐客户登记真实、准确的电话号码&#xff0c;否则无法兑现积分奖励)尊敬的客户&…

在cmd命令行下编译运行C/C++源文件

一直用java来写程序&#xff0c;java配置好jre路径之后&#xff0c;在cmd下编译运行&#xff0c;很方便。 刚好要给一个舍友改下C程序&#xff0c;想到可不可以像java一样在环境变量里配置好C的编译路径呢&#xff1f; 于是上网搜了一下&#xff0c;得到如下结果&#xff1a; 一…

制作程序化装饰花纹图案_用装饰器设计图案装饰

制作程序化装饰花纹图案装饰图案是广泛使用的结构图案之一。 此模式在运行时动态更改对象的功能&#xff0c;而不会影响对象的现有功能。 简而言之&#xff0c;此模式通过包装将附加功能添加到对象。 问题陈述&#xff1a; 想象一个场景&#xff0c;我们有一个比萨饼&#xff…

10停止nginx命令 win_windows版nginx快速操控神器(重启,关闭)

众所周知,Windows 版本的Nginx 是linux版本的阉割版,但是在开发或者个人测试的时候,还是非常好用的&#xff0c;但是nginx运行的命令自己敲打起来不是那么的方便,因此呢&#xff0c;我们就写了个Bat批处理小程序&#xff0c;封装了这些命令&#xff0c;2.1版本您只需要配置下 N…

学习vi和vim编辑器(8):全局替换(1)

本章学习vi编辑器中的全局替换命令。通过全局替换命令&#xff0c;可以自动替换文件中所有出现过的某个单词。全局替换一般会用到两个ex命令&#xff1a;":g"(global)&#xff0c;":s"(substitute)。 替换命令&#xff1a; 替换命令的语法如下&#xff1…

使用DynamoDBMapper查询DynamoDB项目

在上一篇文章中&#xff0c;我们使用底层Java api在DynamoDB数据库上发出了查询。 使用DynamoDBMapper进行查询非常简单。 使用哈希键发出查询非常简单。 这样的查询的最佳候选者是通过使用电子邮件哈希键进行搜索的Users表。 public User getUser(String email) {User user…

实训二—博客三

学期末总结 经过了一个学期的java学习&#xff0c;使我对java产生了很大的兴趣&#xff0c;虽然我学的并不怎么好&#xff0c;但是我喜欢程序可以成功运行时带来的成就感&#xff0c;我也享受排错的过程。学加练的上课模式我觉得也很棒&#xff0c;给了我们独立思考编程的时间&…