# Dockerfile笔记

# 制作镜像时注意事项

  1. RUN一条命令能解决的事,就不要多条,不然会导致制作的镜像包变大(因为多了一层)。

命令


######################### FROM ##########################
# 制作基准镜像
FROM 镜像
# 比如我们要发布一个应用到tomcat里,那么的第一步就是FROM tomcat
FROM tomcat<:tags>

######################### LABEL&MAINTAINER ##########################
# MAINTAINER,一般写个人id或组织id
# LABEL 就是注释,方便阅读的,纯注释说明。不会对Dockerfile造成任何影响
# 比如:
MAINTAINER baidu.com
LABEL version = "1.0.0"
LABEL description = "我们是大百度!"
# ...等等描述性信息,纯注释。

######################### WORKDIR ##########################
# 类似于Linux中的cd命令,但是他比cd高级的地方在于,我先cd,发现没有这个目录,我就自动创建出来,然后在cd进去
WORKDIR /usr/local/testdir

######################### COPY ##########################
# 将1.txt拷贝到根目录下。它不仅仅能拷贝单个文件,还支持Go语言风格的通配符,比如如下:
COPY 1.txt /
# 拷贝所有 abc 开头的文件到testdir目录下
COPY abc* /testdir/
# ? 是单个字符的占位符,比如匹配文件 abc1.log
COPY abc?.log /testdir/

######################### ADD ##########################
# 将1.txt拷贝到根目录的abc目录下。若/abc不存在,则会自动创建
ADD 1.txt /abc
# 将test.tar.gz解压缩然后将解压缩的内容拷贝到/home/work/test
ADD test.tar.gz /home/work/test

# docker官方建议当要从远程复制文件时,尽量用curl/wget命令来代替ADD。因为用ADD的时候会创建更多的镜像层。镜像层的size也大。
#
# 对比:二者都是只复制目录中的文件,而不包含目录本身。COPY能干的事ADD都能干,甚至还有附加功能。
# ADD可以支持拷贝的时候顺带解压缩文件,以及添加远程文件(不在本宿主机上的文件)。只是文件拷贝的话可以用COPY,有额外操作可以用ADD代替。

######################### ENV ##########################
# 设置环境常量,方便下文引用,比如:
ENV JAVA_HOME /usr/local/jdk1.8
# 引用上面的常量,下面的RUN指令可以先不管啥意思,目的是想说明下文可以通过${xxx}的方式引用
RUN ${JAVA_HOME}/bin/java -jar xxx.jar
# ENV设置的常量,其他地方都可以用${xxx}来引用,将来改的时候只改ENV的变量内容就行

######################### RUN ##########################
# 执行时机:RUN指令是在构建镜像时运行,在构建时能修改镜像内部的文件。命令格式不光是RUN独有,而是下面的CMD和ENTRYPOINT都通用。
# SHELL命令格式
RUN yum -y install vim
# EXEC命令格式
RUN ["yum","-y","install","vim"]
# 二者对比,SHELL:当前shell是父进程,生成一个子shell进程去执行脚本,脚本执行完后退出子shell进程,回到当前父shell进程。
# EXEC:用EXEC进程替换当前进程,并且保持PID不变,执行完毕后直接退出,不会退回原来的进程。
# 总结:也就是说shell会创建子进程执行,EXEC不会创建子进程。
# 推荐EXEC命令格式
# 举个最简单的例子,构建镜像时输出一句话,那么在Dockerfile里写如下即可:
RUN ["echo", "image is building!!!"]
# 再比如我们要下载vim,那么在Dockerfile里写如下即可:
RUN ["yum","-y","install","vim"]

######################### CMD ##########################
# 执行时机:容器启动时执行,而不是镜像构建时执行。
# 在容器启动的时候执行此命令,且Dockerfile中只有最后一个ENTRYPOINT会被执行,推荐用EXEC格式。重点在于如果容器启动的时候
# 有其他额外的附加指令,则CMD指令不生效。举例:
CMD ["echo", "container starting..."] 

######################### ENTRYPOINT ##########################
# 执行时机:容器创建时执行,而不是镜像构建时执行。
# 在容器启动的时候执行此命令,且Dockerfile中只有最后一个ENTRYPOINT会被执行,推荐用EXEC格式。举例:
ENTRYPOINT ["ps","-ef"]

# 执行时机演示
FROM centos
RUN ["echo", "image building!!!"]
CMD ["echo", "container starting..."]
docker build -t chentongwei.com/test-docker-run .
# 构建镜像的过程中发现我们RUN的image building!!! 输出了,所以RUN命令是在镜像构建时执行。而并没有container starting…的输出。
docker run chentongwei.com/test-docker-run
# 结果:container starting...,足以发现CMD命令是在容器启动的时候执行。

# CMD和ENTRYPOINT演示
# ENTRYPOINT和CMD可以共用,若共用则他会一起合并执行。如下Demo:
FROM centos
RUN ["echo", "image building!!!"]
ENTRYPOINT ["ps"]
CMD ["-ef"]

# 构建镜像
docker build -t chentongwei.com/docker-run .
# 启动容器
docker run chentongwei.com/docker-run

# 他给我们合并执行了:ps -ef,这么做的好处在于如果容器启动的时候添加额外指令,CMD会失效,可以理解成我们可以动态的改变CMD内容而
# 不需要重新构建镜像等操作。比如
docker run chentongwei.com/docker-run -aux
# 结果直接变成了 ps -aux,CMD命令不执行了。但是ENTRYPOINT一定执行,这也是CMD和ENTRYPOINT的区别之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  1. Redis
# 将Redis运行在centos上
FROM centos
# 安装Redis所需要的基础库
RUN ["yum", "install", "-y", "gcc", "gcc-c++", "net-tools", "make"]
# 将Redis目录放到/usr/local
WORKDIR /usr/local
# 别忘了ADD命令自带解压缩的功能
ADD redis-4.0.14.tag.gz .
WORKDIR /usr/local/redis-4.0.14/src
# 编译安装Redis
RUN make && make install
WORKDIR /usr/local/redis-4.0.14
# 将配置文件仍到Redis根目录
ADD redis-6379.conf .
# 声明容器中Redis的端口为6379
EXPOSE 6379
# 启动Redis  redis-server redis-6379.conf
CMD ["redis-server", "redis-6379.conf"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

制作镜像&&启动容器

# 制作镜像
docker build -t chentongwei.com/docker-redis .
# 查看
docker images
# 启动容器
docker run -p 6379:6379 chentongwei.com/docker-redis
1
2
3
4
5
6

基础jdk1.8镜像

frolvlad/alpine-oraclejre8	# 镜像内sh命令,不能执行脚本
funteam/jdk1.8-mini		# 镜像内sh命令,
openjdk:8-jre-alpine
# 制作镜像
docker build -f  xxx.dockerfile -t dkgee/app:v1

示例一

# 指明当前镜像继承的基镜像,编译当前镜像时候会自动下载基镜像
FROM frolvlad/alpine-oraclejre8
# 当前镜像的作者和邮箱,使用空格隔开
MAINTAINER  dkgee dk_gee@163.com
# 挂载目录(在宿主机可以共享访问)
VOLUME /root
# 从当前工作目录复制文件到镜像目录中并重新命名
ADD demo-0.0.1.jar demo.jar     
# 在当前镜像上执行Linux命令
RUN sh -c 'touch /demo.jar'
#对外暴露端口
EXPOSE 8080
# 让容器像一个可执行程序一样运行,entrypoint才是正统地用于定义容器启动以后的执行体
ENTRYPOINT ["java", "-jar", "demo.jar"] 

示例二(基于ubuntu制作)

# Version: 1.0.1
FROM ubuntu:latest
MAINTAINER xxh "xxh@qq.com"
#设置root用户为后续命令的执行者
USER root
#执行操作
RUN apt-get update
RUN apt-get install -y nginx
#使用&&拼接命令
RUN touch test.txt && echo "abc" >> abc.txt
EXPOSE 80 8080 1038
#添加文件
ADD abc.txt /opt/
#添加文件夹
ADD /webapp /opt/webapp
#添加网络文件
ADD https://www.baidu.com/img/bd_logo1.png /opt/
#设置环境变量
ENV WEBAPP_PORT=9090
#设置工作目录
WORKDIR /opt/
#设置启动命令
ENTRYPOINT ["ls"]
#设置启动参数
CMD ["-a", "-l" ]
#设置卷
VOLUME ["/data", "/var/www"]
#设置子镜像的触发操作
ONBUILD ADD . /app/src
ONBUILD RUN echo "on build excuted" >> onbuild.txt

示例三(基于centos制作)

# 表示从docker官方仓库中获取centos基础镜像
FROM centos
# 将当前目录下(与Dockerfile同一级目录)的jdk添加到镜像的/usr/local/中
ADD jdk-8u161-linux-x64.tar.gz  /usr/local/
ADD apache-tomcat-8.5.29.tar.gz  /usr/local/
# 设置Java的环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_161
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.29
ENV CATALINA_BASE /usr/local/apache-tomcat-8.5.29
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
ADD ./TRMS_HK.war /usr/local/apache-tomcat-8.5.29/webapps
# 对外暴露的端口,便于外部访问
EXPOSE 8080

# CMD主要作用是默认的容器启动执行命令,容器启动以后,默认的执行的命令;
# 大多数网上博客论坛说的“cmd会被覆盖”,其实为什么会覆盖?因为cmd的角色定位就是默认,如果你不额外指定,
# 那么就执行cmd的命令,否则呢?只要你指定了,那么就不会执行cmd,也就是cmd会被覆盖
# 一个dockerfile至多只能有一个cmd,如果有多个,只有最后一个生效。
CMD /usr/local/apache-tomcat-8.5.29/bin/catalina.sh run

示例四(基于JDK制作)

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD kitty-monitor-1.0.0.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

示例五(基于JDK制作)

FROM java:8
RUN mkdir -p /usr/src/myapp
COPY target/gs-rest-service-0.1.0.jar /usr/src/myapp/
WORKDIR /usr/src/myapp
EXPOSE 8080
RUN java -jar gs-rest-service-0.1.0.jar

示例六(基于JDK制作)

FROM frolvlad/alpine-oraclejre8
MAINTAINER dkgee dk_gee@163.com
ADD cms-tsp-web-1.1.3.40-bin.zip /cms-tsp-web-1.1.3.40-bin.zip
RUN sh -c 'unzip /cms-tsp-web-1.1.3.40-bin.zip'
EXPOSE 19090
# CMD /cms-tsp-web-1.1.3.40/start.sh start dev

示例七(基于JDK制作)

FROM funteam/jdk1.8-mini
MAINTAINER dkgee dk_gee@163.com
ADD cms-tsp-web-1.1.3.40-bin.zip /cms-tsp-web-1.1.3.40-bin.zip
RUN sh -c 'unzip /cms-tsp-web-1.1.3.40-bin.zip'
EXPOSE 19090
#【提示】start.sh脚本中不能以后台模式(nohup)运行,否则启动时会自动退出
ENTRYPOINT ["/cms-tsp-web-1.1.3.40/start.sh", "start", "dev"]

示例八(基于Node制作)

# Create image based on the official Node 6 image from dockerhub
FROM node:6-alpine
LABEL author="Vijayendra Mudigal"
MAINTAINER vijayendrap@gmail.com

# Create a directory where our app will be placed
RUN mkdir -p /usr/src/app

# Change directory so that our commands run inside this new directory
WORKDIR /usr/src/app

# Copy dependency definitions
COPY package.json /usr/src/app

# Install dependecies
RUN npm install

# Get all the code needed to run the app
COPY . /usr/src/app

# Expose the port the app runs in
EXPOSE 4200

# Serve the app
CMD ["npm", "start"]
  1. 扩展Logstash镜像插件方式,重新编写一个Dockerfile,基于之前的镜像,使用logstash-plugin命令添加
FROM registry.cn-beijing.aliyuncs.com/dkgee/logstash:6.7.0
RUN logstash-plugin install logstash-input-nsq
1
2
上次更新: 2020-05-26 09:08:37