Linux制作docker镜像

发布于:2024-04-25 ⋅ 阅读:(129) ⋅ 点赞:(0)

一、制作镜像

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:jessie

RUN 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:jessie

RUN 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 缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉