镜像生成途径

  • dockerfile
  • 基于容器制作

什么是dockerfile

dockerfile说白就是用来构建docker 镜像的源码,大家看到源码俩字不用惊慌,所为的dockerfile源码只是一些基础的指令并没有控制语句或条件判断等,仅仅是一些文本指令

dockerfile语法格式其实只有两类语法格式:

  1. 注释信息
  2. 指令和参数

注意:

  1. 默认dockerfile中的语法虽然不区分大小写,但是约定俗成一律用大写
  2. dockerfile在执行时,是自上而下去执行的
  3. dockerfile第一个非注释行必须是FROM指令,用来指定基础镜像

FROM指令

  • FROM指令是最重的一个且必须为Dockerfile文件开篇的第一行非注释,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境
  • 实践中,基准镜像可以使任何可用的镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件
  • 如果找不到指定的镜像文件,docker build会返回一个错误信息

MAINTAINER指令

  • 用于让Dockerfile制作者提供本人的详细信息
  • Dockerfile并不限制MAINTAINER指令出现在哪,但推荐将其放置于FROM之后
  • 语法格式为
    •   MAINTAINER<authro's detail>
    •   <author's detail>可是任何文本信息,但约定俗成地使用作者名称和邮件地址
    •   MAINTAINER "liwang<liwang@126.com>"

COPY指令

如果仅仅是把本地的文件拷贝到容器镜像中,COPY 命令是最合适不过的。其命令的格式为:

语法规则:

  • COPY <src> <dest>
  • COPY ["<src>",....,"<dest>"]
    • <src>:要复制的源文件或目录,支持使用通配符
    • <dest>:目标路径,建议使用绝对路径
  • note:在文件中如果有空格,通常使用第二种格式

复制法则:

  • 复制目标目录如果不存在会自动创建
  • 如果复制的是目录,那么dest必须要跟目录名称,而且必须以/结尾

ADD指令

ADD指令和COPY命令很类似,不同之处在于:

  • ADD指令可以将本地tar包在注入镜像后进行解压缩,如果是URL路径那么只能是将tar包打包进镜像而不会展开

WORKDIR指令

用于为Dockerfile中所有的RUN,CMD,ENTRYPOINT,COPY,ADD指定设定工作目录

语法格式为:

WORKDIR <dirpath>

VOLUME指令

用于在image中创建一个挂载点目录,以挂载docker上的卷或者其他容器上的卷

语法格式为:

  • VOLUME <mountpoint>
  • VOLUME [<mountpoint>]

如果挂载点目录路径下此前存在,docker run命令会在卷挂载完成以后将此前的所有文件复制到新挂载的卷中

EXPOSE指令

  • 用于为容器打开指定要监听的端口以实现与外部通信
  • 语法格式:
    • EXPOSE <port>/<protocol> <port>/<protocol> <port>/<protocol>
  • 一次可以指定多个暴露的端口
    • EXPOSE 80/tcp 11211/udp

ENV指令

用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如:ENV,ADD,COPY等)所调用

调用格式为$variable_name或${variable_name}

语法格式为:

  • ENV <key>:<value>
  • ENV <key>=<value>
  • 第一种格式中,<key>之后的所有内容均被视作<value>的组成部分,因此,一次只能设置一个变量
  • 第二种格式中,可以一次设置多个变量,每一个变量为一个“<key>=<value>”键值对,如果<value>包含空格,可以以反斜线\进行转义,也可以通过对<value>加引号进行标识,\进行续航
  • 定义多个变量时,建议使用第二种方式

RUN指令和CMD指令

RUN和CMD可以执行指定的shell命令;

区别:

  1. 运行的时间段不同;
  2. CMD可以有多个,但是只有最后一个CMD有效;
  3. RUN可以有多个,并且都可以生效

RUN指令主要是dockerfile创建为镜像时要执行的任务,而CMD主要作用在于创建为容器时指定默认要运行的程序,不过,CMD可以被docker run的命令行选项所覆盖

如下图所示:

CMD 语法格式

  • CMD <command> 或
  • CMD ["<excutable>","<param1>","<param2>"]
  • CMD["<param1>","<param2>"]

前两种语法格式与RUN意义相同

第三种语法格式主要用于为ENTRYPOINT指令提供默认参数

ENTRYPOINT指令

ENTRYPOINT指令和CMD指令很像,只不过ENTRYPOINT不能被覆盖(除非指定特殊选项),并且CMD命令会当做参数传递给ENTRYPOINT

使用ENTRYPOINT的意义在于我们可以给我们的应用配置文件制作一个配置文件模板,这样,我们就可以在容器外部注入变量生成新的配置文件

以nginx:1.14-alpine为例子,我们可以基于一个配置文件模板生成不同端口号的nginx,以下为例子:

Dockerfile文件内容

FROM nginx:1.14-alpine
LABEL maintainer="liwang<liwang@163.com>"
ENV HTML=/data/html/
ADD index.html ${HTML}
ADD entrypoint.sh /bin/
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]

entrypoint.sh脚本文件内容如下:

cat > /etc/nginx/conf.d/www.conf <<EOF
server {
server_name $HOSTNAME;
listen ${PORT:-};
root ${HTML:-/usr/share/nginx/html};
}
EOF exec "$@"

Dockerfile目录的文件结构如下:

[root@bogon Dockerfile]# ls
Dockerfile entrypoint.sh index.html

生成镜像

[root@bogon Dockerfile]# docker build -t mynginx ./

这时候我们运行容器的时候就可以在容器外部给予变量生成不同的nginx配置文件,如下:

我们想生成1000端口的nginx那么可以如下:

[root@bogon Dockerfile]# docker run --name myweb1 -itd -e "PORT=1000" mynginx
539896dad037ea6f3e804a281b46cce5eec21c96bcd331d0dc6ed8da1653c540
[root@bogon Dockerfile]# docker exec -it myweb1 /bin/sh
/ # netstat -tnpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0.0.0.0: 0.0.0.0:* LISTEN /nginx -g daemon o
tcp 0.0.0.0: 0.0.0.0:* LISTEN /nginx -g daemon o
/ # hostname
539896dad037
/ # wget -O - -q 539896dad037:
this is httpd box

我们想生成2000端口的nginx那么可以如下:

[root@bogon Dockerfile]# docker run --name myweb2 -itd -e "PORT=2000" mynginx
ce9b85e9a77b761bb832e2b29582093dd53bbcb9120bbf30fd4b69850874bc1a
[root@bogon Dockerfile]# docker exec -it myweb2 /bin/sh / # netstat -tnpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0.0.0.0: 0.0.0.0:* LISTEN /nginx -g daemon o
tcp 0.0.0.0: 0.0.0.0:* LISTEN /nginx -g daemon o

USER指令

  • 用于指定运行image时或Dockerfile中任何RUN,CMD,或ENTRYPOINT指令指定的程序时用户名或UID
  • 默认情况下container运行的用户为root
  • 语法格式
    • USER <UID> |<USERNAME>
    • 这里要注意的是UID可以是任意数字,但实践中必须为/etc/passwd中某用户的有效UID,否则,docker run命令将运行失败

HEALTHCHECK指令

有时候我们判断一个容器是否正常不能单一的只看容器当中的进程是否存在,比如,我们运行一个nginx,但是我们的document_root指错了,容器的进程一样会执行,但是这个服务已经不能够按照用户的需求正常访问了,因此我们用HEALTHCHECK去探测我们的服务是否正常

语法格式:

HEALTHCHECK [OPTIONS] CMD command

options选项有:

  • --interval=#(默认30s)
  • --timeout=#(默认30s)
  • --start-period=#(默认0秒)
  • --retries=#(默认为3次)

检测command指令发出后返回值有3种:

  • 0:健康
  • 1:不健康
  • 2:预留的,用户可以根据2返回值来做操作

for example:

HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1

案例:

dockerfile如下:

[root@jiaqi211 dockerfile]# cat Dockerfile
FROM busybox:latest
MAINTAINER "liwang<liwang@126.com>"
HEALTHCHECK --start-period=3s CMD wget -O - -q http://0.0.0.0:80 || exit 1
RUN mkdir -p /data/web/html/; \
cd /data/web/html && echo "welcome to busybox" > index.html
CMD ["-f","-h","/data/web/html/"]
ENTRYPOINT ["/bin/httpd"]
EXPOSE

等待片刻如下:

[root@jiaqi211 dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d4837b1dc5a9 busyweb "/bin/httpd -f -h /d…" minutes ago Up 2 minutes (healthy) 0.0.0.0:->/tcp myweb1

如果我们把红色字体中80端口改成一个不通的端口比如10080,结果如下:

[root@jiaqi211 dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bbaa030c1560 busyweb "/bin/httpd -f -h /d…" About a minute ago Up About a minute (unhealthy) 0.0.0.0:->/tcp myweb1

SHELL指令

在shell中默认一般使用["/bin/sh","-c"],我们可以修改默认的shell

语法格式如下:

  • SHELL ["excutable","parameters"]

不过改的情况不多见

ARG指令

ARG指令可以在docker build时传变量,而ENV是在docker run时给予变量

ARG用法如下:

[root@jiaqi211 dockerfile]# vim Dockerfile
FROM busybox:latest
ARG author="liwang<liwang@126.com>"
LABEL maintainer="${author}"
HEALTHCHECK --start-period=3s CMD wget -O - -q http://0.0.0.0:10080 || exit 1
RUN mkdir -p /data/web/html/; \
cd /data/web/html && echo "welcome to busybox" > index.html
CMD ["-f","-h","/data/web/html/"]
ENTRYPOINT ["/bin/httpd"]
EXPOSE

验证1:如果不传变量会用已经定义好的变量传入

[root@jiaqi211 dockerfile]# docker build -t myweb1 ./
[root@jiaqi211 dockerfile]# docker inspect myweb1
.....
"Labels": {
"maintainer": "liwang<liwang@126.com>"
}
.....

验证2:如果传入变量会按照用户传入的变量传入

[root@jiaqi211 dockerfile]# docker build -t myweb1 --build-arg author="fengzi<fengzi@126.com>" ./
[root@jiaqi211 dockerfile]# docker inspect myweb1
.....
"Labels": {
"maintainer": "fengzi<fengzi@126.com>"
}
.....

ONBUILD

  • 用于在Dockerfile中定义一个触发器
  • Dockerfile用于build映像文件,此映像文件可以被作为基础映像被另一个Dockerfile用做FROM指令参数,并构建新的映像文件,在后面docker build时会被触发
  • ONBUILD不能触发FROM 和 MAINTAINER指令

语法格式:

  • ONBUILD <INSTRUCTION>

示例

镜像目录的文件如下:

[root@localhost ~]# tree dockerfile/
dockerfile/
├── Dockerfile
├── index.html
└── nginx-1.16..tar.gz

Dockerfile文件内容如下:

[root@localhost dockerfile]# cat Dockerfile
FROM busybox:latest
MAINTAINER "liwang<liwang@126.com>"
WORKDIR /etc/
ENV DOCUMENT_ROOT="/data/web/html"
EXPOSE 80/tcp
ADD http://nginx.org/download/nginx-1.16.1.tar.gz /etc
RUN cd /etc/ && tar -zxvf nginx-1.16.1.tar.gz -C /tmp
RUN mkdir -p ${DOCUMENT_ROOT}
ADD index.html ${DOCUMENT_ROOT}
VOLUME ${DOCUMENT_ROOT}
CMD httpd -f -h ${DOCUMENT_ROOT}

运行Dockerfile命令如下:

[root@localhost dockerfile]# docker build -t myhttpd ./
Sending build context to Docker daemon .036MB
Step / : FROM busybox:latest
---> 020584afccce
Step / : MAINTAINER "liwang<liwang@126.com>"
---> Using cache
---> 3537a5a13f27
Step / : WORKDIR /etc/
---> Running in 6ffe9c85b719
Removing intermediate container 6ffe9c85b719
---> 434913bba9b0
Step / : ENV DOCUMENT_ROOT="/data/web/html"
---> Running in 04e7e3bae01a
Removing intermediate container 04e7e3bae01a
---> cc03fd190474
Step / : EXPOSE /tcp
---> Running in 44adb435af97
Removing intermediate container 44adb435af97
---> 54d69d81360d
Step / : ADD http://nginx.org/download/nginx-1.16.1.tar.gz /etc
Downloading [==================================================>] .033MB/.033MB
---> e3bf4b5c993e
Step / : RUN cd /etc/ && tar -zxvf nginx-1.16..tar.gz -C /tmp
---> Running in a00836e16083
nginx-1.16./
nginx-1.16./auto/
nginx-1.16./conf/
nginx-1.16./contrib/
nginx-1.16./src/
nginx-1.16./configure
.......
Removing intermediate container a00836e16083
---> effc55a2bd3a
Step / : RUN mkdir -p ${DOCUMENT_ROOT}
---> Running in 911d5b78d827
Removing intermediate container 911d5b78d827
---> c78b410fc588
Step / : ADD index.html ${DOCUMENT_ROOT}
---> fb7e61c9e4fe
Step / : VOLUME ${DOCUMENT_ROOT}
---> Running in d38bccb71ddc
Removing intermediate container d38bccb71ddc
---> 2ace0d71de1f
Step / : CMD httpd -f -h ${DOCUMENT_ROOT}
---> Running in 07b43b1c3162
Removing intermediate container 07b43b1c3162
---> 42006762e446
Successfully built 42006762e446
Successfully tagged myhttpd:latest

资源限制

启动memory压力测试镜像,给与容器分配最多占用256m内存-m 256m,并且在容器内部启用2个子进程--vm ,并且每个子进程所占用的内存资源时50m
[root@localhost yum.repos.d]# docker run --name stress -it -m 256m --rm lorel/docker-stress-ng:latest stress --vm --vm-bytes 50m
[root@localhost yum.repos.d]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
712765609df2 stress 200.38% .1MiB / 256MiB 40.28% 656B / 0B 0B / 0B 启用cpu压力测试,给与容器分配最多占用4个cpu,并且在容器内部启动8个子进程来对cpu做压测
[root@localhost yum.repos.d]# docker run --name stress -it -m 256m --cpus --rm lorel/docker-stress-ng:latest stress --vm --vm-bytes 50m --cpu
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
2bf33001b07c myos 0.00% 56KiB / .777GiB 0.00% 656B / 0B 0B / 0B
8d0912451e7f stress 400.98% .3MiB / 256MiB 48.93% 516B / 0B 0B / 0B 启动cpu压力测试,并且限制只能在0和2号cpu上运行
[root@localhost yum.repos.d]# docker run --name stress -it --cpuset-cpus , --rm lorel/docker-stress-ng:latest stress --cpu 启动cpu共享压力测试,2个容器共享cpu资源
[root@localhost yum.repos.d]# docker run --name stress -it --cpu-shares --rm lorel/docker-stress-ng:latest stress --cpu
[root@localhost yum.repos.d]# docker run --name stress -it --cpu-shares --rm lorel/docker-stress-ng:latest stress --cpu
[root@localhost yum.repos.d]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
c5ae34837074 stress 253.22% .81MiB / .777GiB 0.87% 656B / 0B 0B / 0B
207bcffb19dc stress2 125.53% .81MiB / .777GiB 0.87% 656B / 0B 0B / 0B

dockerfile和资源限制(五)的更多相关文章

  1. 深度学习笔记之关于总结、展望、参考文献和Deep Learning学习资源(五)

    不多说,直接上干货! 十.总结与展望 1)Deep learning总结 深度学习是关于自动学习要建模的数据的潜在(隐含)分布的多层(复杂)表达的算法.换句话来说,深度学习算法自动的提取分类需要的低层 ...

  2. k8s控制器资源(五)

    Pod pod在之前说过,pod是kubernetes集群中是最小的调度单元,pod中可以运行多个容器,而node又可以包含多个pod,关系如下图: 在对pod的用法进行说明之前,有必要先对docke ...

  3. JavaWeb学习笔记——开发动态WEB资源(五)servlet身份验证

    本工程的功能是实现Javaweb的servlet身份验证 一下是login.html文件中的代码 <!DOCTYPE html> <html> <head> < ...

  4. Spring Boot 中的静态资源到底要放在哪里?

    当我们使用 SpringMVC 框架时,静态资源会被拦截,需要添加额外配置,之前老有小伙伴在微信上问松哥Spring Boot 中的静态资源加载问题:"松哥,我的HTML页面好像没有样式?& ...

  5. 七、Dockerfile案例三(Mysql安装)

    七.Dockerfile案例三(Mysql安装) *特别提醒:新版的mysql:5.7数据库下的user表中已经没有Password字段了(5.5的user表还有) 一.查看docker hub上的版 ...

  6. kindle资源

    化繁为简!Kindle 漫画和电子书 资源汇总 & 用法 刚入Kindle那会,在网上翻看了不少文章,有的讲怎么下载电子书,有的讲怎么看漫画,有的讲怎么设置推送邮箱…… 好吧,我不想在用Kin ...

  7. k8s资源清单基础

    资源清单介绍 创建资源的方法  apiserver仅接收JSON格式的资源定义  yaml格式提供配置清单 apiserver可自动把yaml转换成json格式数据 资源清单五个一级字段   1.ap ...

  8. Docker 容器资源隔离 namespace(十)

    目录 一.简介 Linux Namespace的6大类型 二.Mount Namespace 三.IPC Namespace 四.Network Namespace 五.UTS Namespace 六 ...

  9. Spring Boot中的静态资源文件

    Spring Boot中的静态资源文件 1.SSM中的配置 2.Spring Boot 中的配置 2.1 整体规划 2.2 源码解读 2.3 自定义配置 2.3.1 application.prope ...

随机推荐

  1. Thymeleaf常用语法:自定义数据转换类

    在模板文件中,可以使用“${{...}}”表达式进行数据转换,Thymeleaf会使用配置好的数据转换类,来实现转换.例如一个User对象,简单起见假设有姓名和年龄两个字段,对象的toString() ...

  2. nginx 七层负载均衡

    [tcp] nginx 七层负载均衡 nginx负载均衡概述 当我们的Web服务器直接面向用户,往往要承载大量并发请求,单台服务器难以负荷,我使用多台Web服务器组成集群,前端使用Nginx负载均衡, ...

  3. 读书笔记_python网络编程3(5)

    5. 网络数据与网络错误 应该如何准备需要传输的数据? 应该如何对数据进行编码与格式化? Py程序需要提供哪些类型的错误? 5.1. 字节与字符串 PC与网卡都支持将字节作为通用传输单元.字节将8比特 ...

  4. Linux系统学习 五、网络基础—网络通信协议

    OSI/ISO七层模型和TCP/IP四层模型 网络层协议和IP划分 OSI的七层框架 物理层:设备之间的比特流的传输.物理接口.电气特性等. 数据链路层:成帧.用MAC地址访问媒介.错误检测与修正. ...

  5. CodeForces - 103B(思维+dfs找环)

    题意 https://vjudge.net/problem/CodeForces-103B 很久很久以前的一天,一位美男子来到海边,海上狂风大作.美男子希望在海中找到美人鱼 ,但是很不幸他只找到了章鱼 ...

  6. 201871010116-祁英红《面向对象程序设计(java)》第八周学习总结

    项目 内容 <面向对象程序设计(java)> https://home.cnblogs.com/u/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.c ...

  7. 201871010112-梁丽珍《面向对象程序设计(java)》第十二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  8. springmvc 什么时候 set applicationContext 到 ServletConfig 的?

    springmvc 什么时候 set applicationContext 到 ServletConfig 的? FrameworkServlet --> initWebApplicationC ...

  9. leetcode 5199. 交换字符串中的元素

    地址  https://leetcode-cn.com/contest/weekly-contest-155/problems/smallest-string-with-swaps/ 给你一个字符串  ...

  10. 大话设计模式Python实现-中介者模式

    中介者模式(Mediator Pattern):用一个对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使耦合松散,而且可以独立地改变它们之间的交互. 下面是一个中介者模式的demo ...