可以看到刚才启动的 mycontainer 容器的状态(STATUS)为 Exited,这表示容器已经退出了,即没有在运行状态,那为什么容器启动后就会退出呢?前文已经提到过,Dockerfile 中 CMD 指令和 ENTRYPOINT 指令指定的是容器启动后的操作,这个操作必须要能够挂起一个进程,否则容器启动完成后就会退出。查看刚才编写的 Dockerfile 可以看到,CMD 指令指定的命令是 /bin/bash,这个命令并不会挂起进程。
这个问题可以通过增加 docker run 命令的参数来解决,如下面的命令:
docker run -d -i --name mycontainer2 myorg/centos:7.2命令执行完成后再次执行 docker ps 查看运行中的容器就能看到这个名为 mycontainer2 的容器了。其中 -d 参数表示让容器在后台运行,-i 参数表示保持标准输入打开,这样容器就不会在启动完成后立即退出了。
第二步,制作一个带有 openjdk 和 nginx 的镜像这一次的镜像构建使用我们第一步构建出的镜像作为基础镜像。
编写 Dockerfile FROM myorg/centos:7.2 RUN echo "[nginx]" >> /etc/yum.repos.d/nginx.repo \ && echo "name=nginx repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/centos/7/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && yum makecache \ && rpm --rebuilddb \ && yum install -y java-1.8.0-openjdk-devel.x86_64 nginx \ && yum clean all ENV JAVA_HOME /usr CMD ["/bin/bash"]这一份 Dockerfile 中的指令在上文中已经解释过了,这里不再赘述。注意 RUN 指令后 shell 命令多行排版的方式是以 \ 结尾,以 && 开头。
构建镜像这一次构建的镜像命名为 myorg/base:centos7.2.x64-ngx-java8。在为镜像命名时,应当在名称和版本两个部分充分描述这个镜像,这样便于快速了解镜像的功能,构建命令如下:
docker build -t myorg/base:centos7.2.x64-ngx-java8 . 第三步,制作可部署的应用系统镜像经过第二步的构建,我们已经拥有了一个带有 Java 运行环境和 Nginx 的镜像,这一步就是要将应用系统也放入镜像中,并通过指令让容器启动后就去执行应用系统启动操作。
编写 Dockerfile FROM myorg/base:centos7.2.x64-ngx-java8 COPY login-deploy-1.0 /home/admin/login/ COPY login-ui /home/admin/login-ui/ COPY nginx.conf /etc/nginx/nginx.conf COPY entrypoint.sh /home/admin/entrypoint.sh RUN chmod +x /home/admin/entrypoint.sh EXPOSE 80 VOLUME ["/home/admin/logs"] ENTRYPOINT ["sh", "/home/admin/entrypoint.sh"]COPY 指令用于将文件或目录拷贝到镜像中指定的位置。如果拷贝的是一个目录,指定镜像中的位置时通常建议在最后加上 /,以避免将目录拷贝成文件的情况。与 COPY 相似的指令是 ADD,后者可以将一个压缩文件拷贝到镜像中并自动解压。由于 ADD 的自动解压功能可能导致解压出来的文件的名称不可控,所以通常是推荐使用 COPY 命令来完成拷贝工作,压缩文件在拷贝前手动解压即可。
EXPOSE 指令用于指定使用这个镜像启动的容器可以通过哪个端口和外界进行通信。换言之,只有 EXPOSE 指令指定的端口才能够和宿主机上的端口做映射。比如这里 EXPOSE 了 80 端口,那么在启动容器的时候就可以将宿主机的 8888 端口映射到容器的 80 端口,这样外界访问宿主机的 8888 端口就相当于访问容器内部的 80 端口。
VOLUME 指定用于指定容器数据的挂载点。容器在运行时会产生各种数据,由于容器和宿主机天然是隔离的,所以在宿主机上并不能看到容器内的数据,当容器被销毁时,这些数据也会随之销毁,无法找回。为了将容器内产生的数据存放到宿主机上,我们可以在制作镜像时指定某些目录为挂载点,然后将容器运行时产生的数据指定输出到这些目录中。当容器启动时,Docker 就会自动在宿主机上创建数据卷来映射挂载点,这样容器中产生的数据就会保存在宿主机上的这个数据卷内。数据卷有自己独立的生命周期,即使删掉了容器,数据卷也还会存在。
Docker 会使用随机 ID 给数据卷命名,这非常不便于管理。在启动 Docker 容器时可以使用 -v 参数来指定数据卷的名称,如 -v myappdata:/home/admin/logs。这样当我们启动容器时,Docker 就会在宿主机上创建名为 myappdata 的数据卷。查看数据卷使用命令 docker volume ls。
ENTRYPOINT 指令的作用和前文介绍的 CMD 指令的作用是基本一致的。区别在于前者指定的命令不会被覆盖,而后者指定的命令会被启动容器时附带的命令所覆盖。对于应用程序镜像来说,通常建议使用 ENTRYPOINT 指令。在这份 Dockerfile 中,ENTRYPOINT 指令表示在容器启动后执行 /home/admin/entrypoint.sh 这份脚本。
构建镜像这一次构建的镜像命名为 myorg/login:20190108。
docker build -t myorg/login:20190108 . 使用镜像