一、制作镜像
1.在/home/data/images目录下编写Dockerfile文件
Dockerfile:是制作镜像的文件
vi Dockerfile
FROM java:8
ENV JAVA_HOME=/usr/lib/jvm/jdk1.8.0_181
ENV PATH=$PATH:$JAVA_HOME/bin
ENV LC_ALL=en_US.utf8
ENV LANG=en_US.utf8
ENV LANGUAGE=en_US.utf8
MAINTAINER wx
ADD discipline-webapp-1.0.0-SNAPSHOT.jar app.jar
EXPOSE 7001
ENTRYPOINT ["java", "-Dfile.encoding=utf-8","-jar", "app.jar"]
PS:EXPOSE 7001: 暴露的端口号,即容器对外开放7001端口
2.通过当前目录下的Dockerfile创建一个名为discipline/discipline:1.1的镜像
docker build -t discipline/discipline:1.1
3.创建容器
docker run -p 7001:7001 --name discipline \
-e TZ="Asia/Shanghai" \
-v /etc/localtime:/etc/localtime \
-v /home/data/monitorlog/${app_name}/logs:/logs \
-d discipline/discipline:latest
或直接编写启动脚本(相当于步骤2,3)
app_name='discipline'
docker build -t discipline/${app_name} .
sleep 1
docker stop ${app_name}
echo '--------stop container-------------'
docker rm ${app_name}
echo '--------rm container---------------'
docker run -p 7001:7001 --name ${app_name} \
-e TZ="Asia/Shanghai" \
-v /etc/localtime:/etc/localtime \
-v /home/data/monitorlog/${app_name}/logs:/logs \
-d discipline/${app_name}:latest
echo '---------start container---------'
docker rmi `docker images|grep none |awk '{print $3}'`
echo '--------rm none images-------------'
4.其他
二、制作镜像的原理
1.Dockerfile说明
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile
。
Dockerfile
是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
以 nginx
镜像为例,这次我们使用 Dockerfile
来定制。
在一个空白目录中,建立一个文本文件,并命名为 Dockerfile
:
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
这个 Dockerfile
很简单,一共就两行。涉及到了两条指令,FROM
和 RUN
。
PS:镜像是打包好的软件,由程序代码、基础系统、依赖关系的软件包、系统库和工具组成 。
2. FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 nginx
镜像的容器,再进行修改一样,基础镜像是必须指定的。而 FROM
就是指定基础镜像,因此一个 Dockerfile
中 FROM
是必备的指令,并且必须是第一条指令。
scratch镜像是虚拟概念,并不实际存在,表示一个空白镜像
3. RUN 执行命令
RUN
指令是用来执行命令行命令的。由于命令行的强大能力,RUN
指令在定制镜像时是最常用的指令之一。其格式有两种:
shell 格式:RUN <命令>
,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile
中的 RUN
指令就是这种格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
exec 格式:RUN ["可执行文件", "参数1", "参数2"]
,这更像是函数调用中的格式。
既然 RUN
就像 Shell
脚本一样可以执行命令,那么我们是否就可以像 Shell
脚本一样把每个命令对应一个 RUN
呢?比如这样:
FROM debian:jessieRUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.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
之前说过,Dockerfile
中每一个指令都会建立一层,RUN
也不例外。每一个 RUN
的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit
这一层的修改,构成新的镜像。
而上面的这种写法,创建了 7 层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。这是很多初学 Docker
的人常犯的一个错误。
上面的 Dockerfile
正确的写法应该是这样:
FROM debian:jessieRUN buildDeps='gcc libc6-dev make' \&& apt-get update \&& apt-get install -y $buildDeps \&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.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
ps:在撰写 Dockerfile
的时候,要经常提醒自己,这并不是在写 Shell
脚本,而是在定义每一层该如何构建
可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的软件,清理了所有下载、展开的文件,并且还清理了 apt
缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。