Docker-高级篇(1)-Dockerfile(核心&构建Redis&构建JDK8)

4,108 阅读7分钟

一、基本介绍

  1. Dockerfile用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
  2. 构建的三个步骤
    • 编写Dockerfile
    • docker build  -f -t [:tag] .
      • -f :指定Dockerfile位置,如果文件在当前目录且名字叫 Dockerfile 则不用指定
      • docker build之后将会生成一个新镜像
    • docker run <新镜像id>
  3. Dockerfile在官网镜像中都有对应的DockerFile可以参考

image.png

  1. Dockerfile基础知识
    • 每条保留字指令都必须大写且后面至少有一个参数,使用空格分隔
    • 指令按照从上到下,依次顺序执行
    • # 表示注释
    • 每条指令都会创建一个新的镜像层,并对镜像进行提交
  2. Docker执行Dockerfile的大致流程
    • docker从基础镜像运行一个容器
    • 执行一条指令并对容器做出更改
    • 执行类似Docker commit的操作提交一个新的镜像层
    • docker再基于刚提交的镜像运行一个新容器
    • 执行dockerf中的下一条指令直到所有指令都执行完成
  3. 从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段
    • Dockerfile是软件的原材料
    • Docker镜像是软件的交付品
    • Docker容器则可以认为是软件的运行态
  4. Dockerfile面向开发,Docker镜像称为交付标准,Docker容器则设计部署与运维,三者缺一不可

Dockerfile

  1. 需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西
  2. Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等

image.png

Docker镜像

  1. 在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行Docker镜像时,会真正开始提供服务

Docker容器

  1. 容器直接提供服务,为最终提供服务的运行态

Docker整体结构图

image.png

二、体系结构

2.1 Docker保留字

  1. FROM
    • 基础镜像,新镜像的基础镜像
  2. MAINTAINER
    • 镜像维护者姓名和邮箱地址
  3. RUN
    • 容器构建时需要运行的命令
    • 两种格式
      • shell格式:RUN yum -y install vim
      • exec格式:RUN ["yum", "-y", "install", "vim"]
    • RUN是在 docker build时运行
  4. EXPOSE
    • 当前镜像对外暴露的端口
  5. WORKDIR
    • 指定创建容器后,终端默认登录进来的工作目录
  6. ENV
    • 用来构建镜像过程中设置环境变量
    • ENV MY_PATH /usr/mytest:这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样
    • WORKDIR $MY_PATH:指令中直接使用这些环境变量
  7. ADD
    • 将宿主机目录下的文件拷贝到镜像且ADD会自动处理URL和解压缩tar包,相当于 COPY + 解压
  8. COPY
    • 将宿主机目录下的文件拷贝到镜像
    • 拷贝有以下两种方式
      • COPY src dest
      • COPY ["src", "dest"]
  9. VOLUME
    • 容器数据卷,用于数据保存和持久化工作
  10. CMD
  • 指定一个容器启动时要运行的命令
  • Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效
  • CMD会被 docker run 之后的参数替换
  • 指令格式:CMD 命令 | CMD ["可执行文件","参数1", "参数n"]
  • 参数列表:CMD ["参数1","参数n"],在指定ENTRYPOINT指令后,用CMD指定具体参数
  • CMD是在docker run 时运行
  1. ENTRYPOINT
  • 指定一个容器启动时要运行的命令
  • 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
  • 多个ENTRYPOINT不会覆盖,而是追加
  • 指令格式:ENTRYPOINT ["可执行文件","参数1", "参数n"]
  • ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参
  • 当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变:ENTRYPOINT CMD
  • 优点:在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数
  • 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效
  1. ONBUILD
  • 触发器,当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
  1. USER
  • 指定该镜像以什么样的用户去执行,如果都不指定,默认是root

image.png

2.2 案例解释

  1. scratch:相当于java中的Object,是镜像的基础镜像
  2. Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的
  3. 下载的centos只有200M左右,因为其很多指令被舍弃,只有精简内核
  4. 现在自定义 centos 镜像,具备以下功能
    • 登陆后的默认路径载/opt下
    • 支持vim编辑器
    • 查看网络配置的ifconfig支持
  5. 编写Dockerfile
FROM centos:7
MAINTAINER tianxincoord@163.com
ENV WORK /opt

RUN yum -y install vim
CMD echo "vim编辑器安装完成"
RUN yum -y install net-tools
CMD echo "网络工具安装完成"

WORKDIR $WORK
CMD echo "工具目录设置完成"

EXPOSE 80
CMD /bin/bash
  1. 构建Dockerfile,生成镜像
    • docker build -f /root/workspace/docker/Dockerfile -t tianxin/centos:1.0 .
      • -f:指定全路径
      • 注意尾部有个.
    • docker build -t tianxin/centos:1.0 .
      • 当前目录下标准文件名可以不指定路径

......
# 构建成功消息
Successfully built a1467c43b30c
Successfully tagged tianxin/centos:1.0
# 构建成功后查看镜像
[root@localhost docker]# docker images
REPOSITORY       TAG       IMAGE ID       CREATED         SIZE
tianxin/centos   1.0       a1467c43b30c   9 seconds ago   515MB
redis            latest    aa4d65e670d6   2 weeks ago     105MB
mysql            5.7       8cf625070931   2 weeks ago     448MB
centos           7         8652b9f0cb4c   8 months ago    204MB
  1. 运行新镜像
    • docker run -it --name tianxin-centos tianxin/centos:1.0
    • 可以成功看到镜像当前工作目录为/opt,包含网络命令
[root@localhost docker]# docker run -it --name tianxin-centos tianxin/centos:1.0
[root@3e307a37f9ac opt]# pwd
/opt
[root@3e307a37f9ac opt]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.4  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:04  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  1. 查看镜像历史
    • docker history imagesID
[root@localhost redis]# docker history a1467c43b30c
IMAGE          CREATED          CREATED BY                                      SIZE
a1467c43b30c   14 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
fac2dd7bdf3c   14 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
6ed0b3d96497   14 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
6279934b0024   14 minutes ago   /bin/sh -c #(nop) WORKDIR /opt                  0B        
ed95908c5c7b   14 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
abd1744d570e   14 minutes ago   /bin/sh -c yum -y install net-tools             128MB     
4a7efc540d58   14 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
d9ce990fb919   14 minutes ago   /bin/sh -c yum -y install vim                   183MB     
42b4307fde4f   15 minutes ago   /bin/sh -c #(nop)  ENV WORK=/opt                0B        
54a76e7e02be   15 minutes ago   /bin/sh -c #(nop)  MAINTAINER tianxincoord@1…   0B        
8652b9f0cb4c   8 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      8 months ago     /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      8 months ago     /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB 

三、构建Redis

  • 工作目录:/root/workspace/redis
  1. 准备Dockerfile文件和redis安装包、已经关闭端口绑定的redis.conf配置文件
[root@localhost redis]# ll
total 2472
-rw-r--r--. 1 root root       0 Aug  7 07:50 Dockerfile
-rw-r--r--. 1 root root 2465302 Jul 21 18:51 redis-6.2.5.tar.gz
-rw-r--r--. 1 root root   62186 Aug  7 08:02 redis.conf
  1. 编写Dockerfle文件
# 设置基础信息
FROM centos:7

# 拷贝安装文件(先确保Dockerfile同级目录含有安装文件)
ADD redis-6.2.5.tar.gz /opt/
# 进入工作目录
WORKDIR /opt/redis-6.2.5/src/

# 安装redis所需依赖
RUN yum -y install gcc gcc-c++ tcl automake autoconf libtool make
# 编译和安装
RUN make
RUN make install
# 清除中间文件
RUN make distclean
# 切换工作目录
WORKDIR /opt/redis-6.2.5/
# 删除原始配置文件
RUN rm -f redis.conf
# 拷贝新redis文件
COPY redis.conf /opt/redis-6.2.5/

WORKDIR /opt/redis-6.2.5/src/
# 暴露端口
EXPOSE 6379
# 默认启动服务,可以启动容器时覆盖命令
CMD ["redis-server"]
  1. 构建DockerFile
docker build -t tianxin/redis .
  1. 构建完成后运行容器
docker run -d --name redis02 -p 6380:6379 tianxin/redis

四、构建java8

  1. 下载jdk8 linux版本,此处使用的版本为jdk-8u251-linux-x64.tar.gz
  2. 将jdk上传到/root/docker/jdk,选择任意路径均可
  3. 拉取centos:7镜像
docker pull centos:7
  1. 编写Dockerfile,和jdk-8u251-linux-x64.tar.gz在同一个文件夹下,内容如下
FROM centos:7
MAINTAINER tianxincoord@163.com
RUN mkdir /usr/local/jdk
WORKDIR /usr/local/jdk
ADD jdk-8u251-linux-x64.tar.gz /usr/local/jdk

ENV JAVA_HOME /usr/local/jdk/jdk1.8.0_251
ENV JRE_HOME /usr/local/jdk/jdk1.8.0_251/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80
  1. 构建镜像
# docker build -t java:8 .
Sending build context to Docker daemon  195.1MB
Step 1/10 : FROM centos:7
---> eeb6ee3f44bd
Step 2/10 : MAINTAINER tianxincoord@163.com
---> Running in 045e51b633e2
Removing intermediate container 045e51b633e2
---> aaa06e3b387b
Step 3/10 : RUN mkdir /usr/local/jdk
---> Running in 138074b4eec0
Removing intermediate container 138074b4eec0
---> bf5cdee73362
Step 4/10 : WORKDIR /usr/local/jdk
---> Running in 251e26d7be7f
Removing intermediate container 251e26d7be7f
---> 3324c3cc346c
Step 5/10 : ADD jdk-8u251-linux-x64.tar.gz /usr/local/jdk
---> d82f82248fc6
Step 6/10 : ENV JAVA_HOME /usr/local/jdk/jdk1.8.0_251
---> Running in 81b46ea286be
Removing intermediate container 81b46ea286be
---> ba1f722dd501
Step 7/10 : ENV JRE_HOME /usr/local/jdk/jdk1.8.0_251/jre
---> Running in 2905af64f88c
Removing intermediate container 2905af64f88c
---> c4f00b71b7f1
Step 8/10 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
---> Running in 9e27b3d384d1
Removing intermediate container 9e27b3d384d1
---> 768a812042b2
Step 9/10 : ENV PATH $JAVA_HOME/bin:$PATH
---> Running in b33cbb2e1213
Removing intermediate container b33cbb2e1213
---> 75325c4bd9f2
Step 10/10 : EXPOSE 80
---> Running in c55b08485621
Removing intermediate container c55b08485621
---> 95064f52c03b
Successfully built 95064f52c03b
Successfully tagged java:8
See 'docker --help'
[root@server01 jdk]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
# 完成的镜像
java         8         95064f52c03b   14 seconds ago   610MB
centos       7         eeb6ee3f44bd   6 months ago     204MB

  1. 运行容器并进入容器内部,查看jdk是否安装成功
# 进入容器内部
# docker run -it --name java8 java:8
# 查看java版本
[root@4fc4e341d672 jdk]# java -version
# jdk安装成功
java version "1.8.0_251"
Java(TM) SE Runtime Environment (build 1.8.0_251-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.251-b08, mixed mode)
[root@4fc4e341d672 jdk]# pwd
/usr/local/jdk