技术标签: 云原生(Cloud Native)、云计算、虚拟化 # CI/DI dockerfile # 构建工具 docker
46 | 如何制作Docker镜像?
参考URL: https://time.geekbang.org/column/article/417216
要落地云原生架构,其中的一个核心点是通过容器来部署我们的应用。如果要使用容器来部署应用,那么制作应用的 Docker 镜像就是我们绕不开的关键一步。
构建一个 Docker 镜像,最常用的有两种:
上面这两种方法中,镜像构建的底层原理是相同的,都是通过下面 3 个步骤来构建镜像:
docker commit
这种镜像构建方式通常用在下面两个场景中:
除了这两种场景,我不建议你使用docker commit来构建生产现网环境的镜像。
原因如下:
docker image history [镜像名称]
查询,方便开发者查看变更记录。在实际开发中,使用Dockerfile来构建是最常用,也最标准的镜像构建方法.
使用 Dockerfile 构建镜像,本质上也是通过镜像创建容器,并在容器中执行相应的指令,然后停止容器,提交存储层的文件变更。和用docker commit构建镜像的方式相比,它有三个好处:
在实际生产环境中,标准的做法是通过 Dockerfile 来构建镜像。使用 Dockerfile 构建镜像,就需要你编写 Dockerfile 文件。
Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。
docker build
命令用于从Dockerfile
构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerfile。
docker build
命令会读取Dockerfile的内容,并将Dockerfile的内容发送给 Docker 引擎,最终 Docker 引擎会解析Dockerfile中的每一条指令,构建出需要的镜像。
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。
Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
FROM extras:${CODE_VERSION}
CMD /code/run-extras
LABEL 指令将元数据添加到镜像。LABEL 是键值对。要在 LABEL 值中包含空格,请像在命令行中一样使用引号和反斜杠。
用来指定当前工作目录(或者称为当前目录)
当使用相对目录的情况下,采用上一个WORKDIR指定的目录作为基准
相当与cd 命令,但不同的是指定了WORKDIR后,容器启动时执行的命令会在该目录下执行
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
RUN 主要用于在Image里执行指令,比如安装软件,下载文件等。
COPY指令从复制文件、目录到镜像文件系统的。
编写Dockerfile的时候copy宿主机文件到镜像中。
Dockerfile只允许使用一次CMD命令。使用多个CMD会抵消之前所有的命令,只有最后一个命令生效。一般来说,这是整个Dockerfile脚本的最后一个命令。
FROM ubuntu
CMD ["/usr/bin/wc","--help"]
CMD有三种形式:
EXPOSE指令通知容器在运行时监听某个端口,可以指定TCP或UDP,如果不指定协议,默认为TCP端口。但是为了安全,docker run命令如果没有带上相应的端口映射参数,Docker并不会将端口映射出去。
EXPOSE 80/tcp
EXPOSE 80/udp
指定映射端口方式:
docker run -P:将所有端口发布到主机接口,每个公开端口绑定到主机上的随机端口,端口范围在/proc/sys/net/ipv4/ip_local_port_range定义的临时端口范围内。
docker run -p :显式映射单个端口或端口范围。
ENTRYPOINT 指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有其他传入值作为该命令的参数。
一个Dockerfile中只能有一个ENTRYPOINT命令。如果有多条,只有最后一条有效。
无参的方式:
ENTRYPOINT [“/usr/sbin/nginx"]
指定参数的方式:
ENTRYPOINT [“/usr/sbin/nginx”, “-g”, “deamon off"]
docker run 的–entrypoint 标志可以覆盖原Dockerfile中的ENTRYPOINT 指令。
注意理解该命令, 该命令 是指定你每次 docker run启动容器的时候,都会自己执行的一个程序!!!。
CMD可以为ENTRYPOINT提供参数,ENTRYPOINT本身也可以包含参数,但是可以把需要变动的参数写到CMD里面,而不需要变动的参数写到ENTRYPOINT里面;
ENTRYPOINT使用第二种shell方式会屏蔽掉CMD里面的命令参数和docker run后面加的命令。
在Dockerfile中,ENTRYPOINT指定的参数比运行docker run时指定的参数更靠前。
ENTRYPOINT/CMD最后一条命令为无限运行的命令:
这句话才是使用ENTRYPOINT的精髓。
在Docker Daemon模式下,entrypoint、cmd命令的最后一个命令,一定是要当前容器需要一直运行的,才能防止容器退出。
当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令。换句话说实际执行时,会变成 “”
通过关键字ARG,ENV设置变量
ARG arg1=test
ENV env1=production
注意:
在RUN中设置变量
在RUN通过arg=someValue中设置变量,以下脚本先获取Debain的系统版本号,并设置到了os_release变量中,在后续的命令中可以通过${os_release}进行引用
RUN os_release="$(cat /etc/os-release | grep VERSION_CODENAME | awk -F '=' '{print $2}')" &&\
echo "deb http://mirrors.aliyun.com/debian/ ${os_release} main non-free contrib\n\
deb http://mirrors.aliyun.com/debian-security ${os_release}/updates main\n\
deb http://mirrors.aliyun.com/debian/ ${os_release}-updates main non-free contrib\n\
deb http://mirrors.aliyun.com/debian/ ${os_release}-backports main non-free contrib\n"\
> /etc/apt/sources.list
一个RUN命令,相当于新打开一个Shell。所以上一个RUN设置的变量无法在下一个RUN中使用。
因此如果你需要在build期间使用某些变量,那么ARG是最好的选择。如果你是想在运行期间使用,那么ENV是唯一的选择。
ENV主要是定义环境变量,在docker run的时候ENV的配置会加载到容易内部,但ARG的参数在内部是没法看到的。同时也可以通过下面命令更改ENV的默认值:
docker run -e var=yyy
ARG和ENV 两者结合使用
ARG var
ENV var=${
var}
在dockerfile内部可以这样控制命令的参数。
ARG protocal
ARG address
ARG port
ENV protocal=${
protocal} \
address=${
address} \
port=${
port}
CMD /usr/bin/lightweightservicediscovery --listen=${
PROTOCAL:-ipv4}:${
ADDRESS:-0.0.0.0}:${
port:-49188}
//如果读取环境变量失败再采用后面的默认值。
这样既可以在build的时候通过docker build --build-arg var=xxx 来传递参数,也可以通过在运行的时候通过docker run -e var=yyy来传递参数。
实战小demo:
docker build --build-arg INSTALL_ZIP=myinstall.zip -t centos-test:v4 .
ARG INSTALL_ZIP
COPY ./${
INSTALL_ZIP} /root/
RUN chmod 755 ${
INSTALL_ZIP}
RUN unzip ${
INSTALL_ZIP}
docker build 命令用于使用 Dockerfile 创建镜像。
docker build [OPTIONS] PATH | URL | -
OPTIONS说明:
使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1。
docker build -t runoob/ubuntu:v1 .
也可以通过 -f Dockerfile 文件的位置:
$ docker build -f /path/to/a/Dockerfile .
问题描述:
在参照这docker官网教程学习构建镜像的时候。提示错误:“docker build” requires exactly 1 argument.
问题分析:
原因是因为(少了一个 ‘.’ , ‘.’ 代表当前路径):
docker build --tag=xxx .
问题描述:
dockerfile中 执行copy 把主机上的文件往容器中copy时,报错file not found in build context or excluded by .dockerignore
问题分析:
我的dockerfile中 宿主机的文件,写的绝对路径。而 dockerfile 不能获取 父目录。
解决方案:
文件放置在当前路径下,dockerfile中 写成 ./文件名 即可(将文件copy到当前目录)。
构建 Go 应用 docker 镜像
https://zhuanlan.zhihu.com/p/476921483
之前我们的演示的是 centos:centos8
基础镜像,查看原文,作者使用了 golang:alpine
镜像,非常小。
原作者的 dockerfile demo:
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOPROXY https://goproxy.cn,direct
RUN apk update --no-cache && apk add --no-cache tzdata
WORKDIR /build
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
RUN go build -ldflags="-s -w" -o /app/hello ./hello.go
FROM alpine
RUN apk update --no-cache && apk add --no-cache ca-certificates
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/hello /app/hello
CMD ["./hello"]
Dockerfile 构建出的镜像大小和 v1 centos对比结果如下:
$ docker images | grep hello
hello v4 94ba3ece3071 4 hours ago 6.66MB
hello v3 f51e1116be11 8 hours ago 6.61MB
hello v2 0dd53f016c93 8 hours ago 6.61MB
hello v1 ac0e37173b85 9 hours ago 314MB
docker info | grep "Docker Root Dir"
root@cka-k8s-master:~/code/mygoapp# cd /data/docker
root@cka-k8s-master:/data/docker# ls
buildkit containers image network overlay2 plugins runtimes swarm tmp trust volumes
root@cka-k8s-master:/data/docker# du -sh * | sort -h
4.0K runtimes
4.0K swarm
4.0K tmp
4.0K trust
16K plugins
28K volumes
80K network
88K buildkit
4.6M image
8.1M containers
3.1G overlay2
root@cka-k8s-master:/data/docker#
原始镜像的选择?
centos:centos8作为基础镜像,是因为centos:centos8镜像中包含了基本的排障工具,例如vi、cat、curl、mkdir、cp等工具。
FROM centos:centos8
LABEL maintainer="<[email protected]>"
WORKDIR /opt/mygoapp
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
mkdir -p /var/log/mygoapp
COPY file-boom /opt/mygoapp/bin/
ENTRYPOINT ["/opt/mygoapp/bin/file-boom"]
CMD ["-c", "/etc/mygoapp/file-boom.yaml"]
文章浏览阅读1.4k次,点赞2次,收藏25次。arduino通过esp8266模块发送数据到云服务器我是代码小白,一个正在做毕设的秃头少年。鄙人拙作,有不当之处,还请指教。最近买了一套arduino设备,打算做一个物联网设备小玩意,可是怎么把数据上传到云服务器可愁坏我了。通过对比实验,我决定用esp8266wifi模块进行通信。云服务器的话,我现在还没写相应的代码,所以先用Onenet平台进行配置。Onenet平台进行配置1.进入Onenet..._esp8266 arduino wifi发送数据
文章浏览阅读1.4w次,点赞9次,收藏17次。常用选项[htbp]是浮动格式:『h』当前位置。将图形放置在正文文本中给出该图形环境的地方。如果本页所剩的页面不够,这一参数将不起作用。『t』顶部。将图形放置在页面的顶部。『b』底部。将图形放置在页面的底部。『p』浮动页。将图形放置在一只允许有浮动对象的页面上。在table或者figure 后加 [!htb] 是系统忽略“美学”标准,把表格和图片插入到你的代码中,是动的,但是不加感叹号,它就是按顺序选择h(此处),t(上方),b(下方),所以为了让图片随着你的代码移动,最好加一个[!htb]_latex htpb
文章浏览阅读67次。1 linux下的usb抓包方法1、配置内核使能usb monitor:make menuconfigDevice Drivers --> USB Support --> USB Monitor --> Sel..._linux安装tcpdump 查看usb
文章浏览阅读164次。计算机组成 课程设计报告计算机组成原理课程设计报告姓 名:班 级:学 号:指导老师:2016年 6月31日目 录第一章 背景知识与课设任务概述11.1课设目的11.2课设任务11.2111.2211.2321.2421.252第二章 课设内容32.1指令的执行流程32.1.132.1.242.1.352.2存储器62.2.162.3运算器72.3.172.4硬件系统组成122.4..._计算机组成课程设计报告
文章浏览阅读1.3k次。最近一学期一次的抢课大戏又来了,几家欢乐几家愁。O(∩_∩)O哈哈~(l我每次一选就过了hah,我还是有欧的时候滴)。看着他们盯着教务系统就着急,何况我们那教务系统,不想说什么。emmm 想周围的朋友,正好下午利用扩容前一段时间写了个小脚本帮助朋友抢课。(当然抢到了啦,^_^)私信小编001即可获取大量Python学习资料,名额有限因为时间不够,来不及仔细琢磨,我第一想法就是直接提交选课的数据包(..._青果教务系统抢课
文章浏览阅读4.6k次。很简单,下载证书后导入到受信任根目录证书下载,直接在代理状态浏览器访问burp点击CA就可以下载了 设置该证书全部信任,,switchyomega 设置如下即可 就可以抓https的包了 ...
文章浏览阅读43次。从零开始实现简易版本SpringIoC&DI&MVCSpring源码进修中,实现一个简易版本的Spring,包含以下主要内容:IoC,DI,MVC,已完成基本的功能。代码量还算一般,特此记录以共勉。首先是整个项目的基本思路。项目实现的功能就是从前端发一个请求,后端根据请求解析到后端的相应方法进行处理,完成后将结果进行返回。代码需要完成请求路径和类+方法的对应。配置阶段配置web.xml:DispatcherServlet设定init-param:contextConfigL
文章浏览阅读542次。只有在单系统自动化的基础上,通过高速网络接入各单系统,充分数据融合,建立合理的联动机制才能完成从单系统自动化到综合自动化的转变,该部分的转变从投入的资金和实现的容易度相对来讲可实现性和可控性都比较容易,但是从综合自动化向数字化矿山发展,涉及的面比较广,必须由多方共同来推进,一般涉及到“综合自动化”、“空间数字化”及“管理信息化”三大方面,三者缺一不可,通过三者的有机融合,再通过合适的平台例如三维可视化平台进行展示,同时通过科学合理的管理制度和流程加以应用才是真正意义上有血有肉的数字化矿山。_18万字应急管理局智慧矿山煤矿数字化矿山技术解决方案word
文章浏览阅读1.4w次,点赞8次,收藏7次。Tomcat官网地址_tomcat官网
文章浏览阅读5.1k次,点赞11次,收藏58次。指令长度与寻址方式有关系,规律或原则如下:一、没有操作数的指令,指令长度为1字节。如es:ds:cbwxlat等。二、操作数只涉及寄存器的指令,指令长度为2字节。如mov al,[si]mov ax,[bx+si]mov ds,ax等。三、操作数涉及内存地址的指令,指令长度为3字节。如mov al,[bx+1]mov ax,[bx+si+3]lea di,[1234]mov [2345],ax等。四、操作数涉及立即数的指令,指令长度为:寄存器类型+2。8位寄存器,寄存器_汇编指令占多少字节
文章浏览阅读3.4k次。CTF中的RSA及攻击方法笔记1 数论基础1.1 模运算规则2 RSA相关题目2.1 已知 n,e,c 求 m2.2 已知 p,q,e 求 d2.3 已知dp,dq,c,p,q 求m2.4 仅已知c,c特别大 【c = m^e mod n】2.5 已知n1,n2,c1,c2,n 求 m2.6 已知n1,n2,e,c2 求m2.7 已知e,d,N 求p,q1 数论基础参考链接:https://www.freebuf.com/articles/web/257835.html1.1 模运算规则模运算与基_ctf rsa 多个n和多个c
文章浏览阅读2w次,点赞4次,收藏15次。数据库中时间类型是这样的,13位bigInt类型的数据select date_format(FROM_UNIXTIME(列名/1000),'%Y%m%d') from xx表原理就是把13位的时间格式/1000等于时间戳,使用FROM_UNIXTIME把时间戳转换成具体的日期ps:将时间转换为时间戳select unix_timestamp('2018-08-30..._bigint转日期