Docker超详解,包括Docker基本命令和Dockerfile

1 Docker简介

1.1 Docker是什么

有助于持续集成和部署的 容器虚拟化技术,运行环境和配置的标准化解决方案。

1.2 为什么需要Docker

解决环境配置的难题(软件带环境安装)。
常用的两种用于解决带环境安装技术,虚拟机技术容器虚拟化技术

  1. 虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。

    • 资源占用多
      虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。

    • 冗余步骤多
      虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。

    • 启动慢
      启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。

  2. 容器虚拟化不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。由于容器是进程级别的,相比虚拟机有很多优势。

    • 启动快
      容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。

    • 资源占用少
      容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所
      有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。

    • 体积小
      容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。

  3. 虚拟机和容器虚拟化比较

image.png
虚拟化的封装是系统级的封装,docker 或者其他容器是进程级的封装。

Docker容器技术与传统虚拟机技术的比较
特性容器虚拟机
启动速度秒级分钟级
性能接近原生较弱
内存代价很小较多
硬盘使用一般为MB一般为GB
运行密度单机支持上千个容器一般几十个
隔离性安全隔离安全隔离
迁移性优秀一般

1.3 Docker组成

1.3.1 docker的基本组成

  • 镜像(image):**Docker 把应用程序及其依赖,打包在 image 文件里面。**只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。
  • 容器(container):**image 文件生成的容器实例,本身也是一个文件,称为容器文件。**也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。
  • 仓库(Repository):仓库是集中存放镜像文件的场所。仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub(https://hub.docker.com/),国内的公开仓库包括阿里云 、网易云 等。

1.3.2 docker架构图

在这里插入图片描述
docker run 具有自动抓取 Image 文件的功能。如果发现本地没有指定的 Image 文件,就会从仓库自动抓取。

1.4 docker基础命令

1.4.1 docker基础命令

# 1.启动docker
systemctl start docker 或 service docker start
# 2.设置开机启动docker服务:
systemctl enable docker
# 3.关闭docker
systemctl stop docker 或 service docker stop
# 4.重启docker
systemctl restart docker 或 service docker restart
# 5.查看docker 版本号和详细信息
docker version
docker info
# 6.docker 帮助命令
docker --help # 忘记了docker有哪些命令,便可使用此进行查看与回顾
docker pull --help # 拉取命令 不知道可以带哪些参数,可以这样使用

1.4.2 docker镜像命令

# 1.查看服务器中docker镜像列表
docker images
# 2.搜索镜像
docker search 镜像名
docker search --filter=STARS=9000 mysql # 搜索 STARS >9000的 mysql 镜像
# 3.拉取镜像
docker pull 镜像名 # 不加tag(版本号) 即拉取docker仓库中该镜像的最新版本latest
docker pull 镜像名:tag # 加:tag 则是拉取指定版本
# 4.删除镜像 ------当前镜像没有被任何容器使用才可以删除
docker rmi -f 镜像名/镜像ID # 删除一个
docker rmi -f 镜像名/镜像ID 镜像名/镜像ID 镜像名/镜像ID # 删除多个,镜像ID或镜像名用空格隔开即可 
docker rmi -f $(docker images -aq) # 删除全部镜像  -a 意思为显示全部, -q 意思为只显示ID
# 5.强制删除镜像
docker image rm -f 镜像名称/镜像ID
# 6.保存镜像
docker save 镜像名/镜像ID -o 镜像保存的位置与名字 # docker save tomcat -o haha/myTomcat.tar
# 7.加载镜像
docker load -i 镜像保存文件位置
# 8.给镜像打标签
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
docker tag 源镜像名:TAG 想要生成新的镜像名:新的TAG
# 8.1 如果省略TAG 则会为镜像默认打上latest TAG
docker tag aaa bbb # 等于 docker tag aaa:latest bbb:test
# 9.上传镜像到docker hub仓库
docker push<hub-user>/<repo-name>:<tag> # docker push pikaiqu/myTomcat:0001
# 10.查看指定镜像的创建历史。
docker history pikaqiu/ubuntu:v3		
# 11.从容器创建一个新的镜像
docker commit -a "pikaqiu.com" -m "my apache" a404c6c174a2  mymysql:v1 # 将容器a404c6c174a2 保存为新的镜像,并添加提交人信息和说明信息。

1.4.3 docker容器命令

# 1.查看正在运行容器列表
docker ps
# 2.查看所有容器 -----包含正在运行 和已停止的
docker ps -a
# 3. 创建容器但不运行
docker create -p 3000:80 --name exampleApp pikaqiu/exampleapp
# 4.运行一个容器
docker run -it -d --name 要取的别名 镜像名:Tag /bin/bash # -it 表示 与容器进行交互式启动 -d 表示可后台运行容器 (守护式运行)  --name 给要运行的容器 起的名字  /bin/bash  交互路径
# 5.删除容器 
docker rm -f 容器名/容器ID # 删除一个容器
docker rm -f 容器名/容器ID 容器名/容器ID # 删除多个容器,空格隔开要删除的容器名或容器ID
docker rm -f $(docker ps -aq) # 删除全部容器
# 6.容器端口与服务器端口映射
docker run -itd --name redis001 -p 8888:6379 redis:5.0.5 /bin/bash
# 7.进入容器
# 7.1 方式一
docker exec -it 容器名/容器ID /bin/bash # docker exec -it redis001 /bin/bash
# 7.2 方式二
docker attach 容器名/容器ID
# 8.从容器内 退出到自己服务器中 
exit # 直接退出  未添加 -d(持久化运行容器) 时 执行此参数 容器会被关闭  
Ctrl + p + q # 优雅退出 --- 无论是否添加-d 参数 执行此命令容器都不会被关闭
# 9.停止容器
docker stop 容器ID/容器名
# 10.重启容器
docker restart 容器ID/容器名
# 11.启动容器
docker start 容器ID/容器名
# 12.强制停止容器
docker kill 容器ID/容器名
# 13.容器文件拷贝 --- 无论容器是否开启 都可以进行拷贝,docker cp 容器ID/名称:文件路径  要拷贝到外部的路径  或  要拷贝到外部的路径  容器ID/名称:文件路径
# 13.1 从容器内拷出
docker cp 容器ID/名称: 容器内路径  容器外路径
# 13.2 从外部 拷贝文件到容器内
docker  cp 容器外路径 容器ID/名称: 容器内路径
# 14.查看容器日志
docker logs -f --tail=要查看末尾多少行 默认all 容器ID
# 15.目录挂载
# -v 宿主机文件存储位置:容器内文件位置
# 运行一个docker redis 容器 进行 端口映射 两个数据卷挂载 设置开机自启动
docker run -d -p 6379:6379 --name redis001 --restart=always  -v /var/lib/redis/data/:/data -v /var/lib/redis/conf/:/usr/local/etc/redis/redis.conf  redis:5.0.5 --requirepass "password"
# 16.更换容器名
docker rename 容器ID/容器名 新容器名

1.4.4 docker运维命令

# 1.查看镜像、容器、数据卷所占的空间大小
docker system df 
# 2.删除异常停止的容器
docker rm `docker ps -a | grep Exited | awk '{print $1}'` 
# 3.删除名称或标签为none的镜像
docker rmi -f  `docker images | grep '<none>' | awk '{print $3}'`
# 4.查找大文件
find / -type f -size +100M -print0 | xargs -0 du -h | sort -nr
# 5.查找指定docker使用目录下大于指定大小文件
find / -type f -size +100M -print0 | xargs -0 du -h | sort -nr |grep '/var/lib/docker/overlay2/*'

1.4.5 容器互联

# 1.创建一个新的 Docker 网络
# -d 参数指定 Docker 网络类型,有 bridge overlay。其中 overlay 网络类型用于 Swarm mode
docker network create -d bridge my-net
# 2.连接容器
# 2.1 运行一个容器并连接到新建的 my-net 网络
docker run -it --rm --name busybox1 --network my-net busybox sh
# 2.2 打开新的终端,再运行一个容器并加入到 my-net 网络
docker run -it --rm --name busybox2 --network my-net busybox sh
# 3.通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系
# 3.1 在busybox1 中ping busybox2
ping busybox2
# 3.2 在busybox2中 ping busybox1
ping busybox1

2 Dockerfile详解

2.1 什么是Dockerfile

Dockerfile仅仅是用来制作镜像的源码文件,是构建容器过程中的指令,docker能够读取dockerfile的指定进行自动构建容器,基于dockerfile制作镜像,每一个指令都会创建一个镜像层,即镜像都是多层叠加而成(如图所示),因此,层越多,效率越低,创建镜像,层越少越好。因此能在一个指令完成的动作尽量通过一个指令定义。

Docker镜像都是只读的,当容器启动时,一个新的可写层镜像加载到镜像顶部,这一层就是我们通常说的容器层,容器之下的都叫镜像层。 分层 :现在构建一个镜像,第一层需要一个Linux内核 比如是centos 6.8、第二层需要安装nginx、第三层安装php、第四层安装mysql5.0版本、如果有一天需要一个mysql5.5版本,可以直接把第四层替换掉,给它换成mysql5.5版本。这样的话一个镜像看起来是一个文件,其实它并不是一个文件,而是由很多很多个子文件结合起来,但也是有数目限制的,限制池为128,也就是不能够超过128层。如果新建一个有很多层级的新镜像,其中某一层和之前的镜像某一层是一样的话,则会跳过这一层,直接下载别的,这样就大大的减少了存储量(共享资源,有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享。)

2.2 使用Dockerfile的目的

实现制作镜像脚本化,同时用户可以根据自己的需要对官方镜像做扩展,或者将自己的应用打包成镜像,实现容器化部署。

2.3 基于Dockerfile实现image生成、保存,容器运行的完整过程

1、编写一个Dockerfile 文件
2、docker build构建成为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(Docker Hub 、阿里云镜像仓库)
image.png

2.4 Dockerfile语法格式

FROM #基础镜像,一切从这里开始构建
MAINTAINER #镜像是谁写的,名字+邮箱(新版即将废弃,被LABEL替代)
LABEL #附加到Ilmage之上的元数据,键值格式
RUN #镜像构建的时候需要运行的命令
ADD #将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
WORKDIR #镜像的工作目录(为RUN、CMD、ENTRYPOINT、COPY和ADD等指令设定工作目录)
VOLUME #指定基于新生成的Image运行Container时期望作为Volume使用的目录
EXPOSE #指定基于新生成的Image运行Container时期望暴露的端口,但实际暴露与否取决于docker run命令的选项,支持TCP和UDP协议
CMD #指定这个容器启动的时候要运行的命令(只有最后一个会生效,可被替代)
ENTRYPOINT #类似于CMD指令的功能,指定这个容器启动的时候要运行的命令,可以追加命令,于CMD共存时,CMD的内容将作为指令中定义的程序的参数
COPY #功能类似ADD,但是不会自动解压文件,也不能访问网络资源,可复制主机上或者前一阶段构建结果中(需要使用--from选项)文件或目录生成新的镜像层
ARG #定义专用于build过程中的变量,但仅对该指标之后的调用生效,其值可由命令行选项"--build-arg"进行传递
ENV #构建的时候以键值格式设置环境变量,可被其后的指令所调用,且基于新生成的lmage运行的Container中也会存在这些变量

Dockerfile 分为四部分基础镜像信息(FROM)、维护者信息(MAINTAINER、LABEL)、镜像操作指令(RUN、ADD、WORKDIR、VOLUME、EXPOSE、COPY、ARG、ENV)和 容器启动时执行指令CMD、ENTRYPOINT)。

2.4.1 FROM

指定基础镜像,必须为第一个命令

格式:
  FROM <image>
  FROM <image>:<tag> #不填tag默认为latest
  FROM <image>@<digest> #digest可用于验证下载的镜像是否保证完整性,FROM node:12.18.4-alpine@sha256:757574c5a2102627de54971a0083d4ecd24eb48fdf06b234d063f19f7bbc22fb
示例:  
	FROM mysql:5.6
注:
   tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像

2.4.2 MAINTAINER(新版即将废弃)

维护者信息

格式:
    MAINTAINER <name>
示例:
    MAINTAINER pikaqiu
    MAINTAINER xxx@163.com
    MAINTAINER pikaqiu <xxx@163.com>

2.4.3 LABEL

用于为镜像添加元数据

格式:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
  LABEL version="1.0" description="这是一个Web服务器" by="pikaqiu"
注:
  使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据
  之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像(因为每一个指令都会创建一个镜像层)。

2.4.4 EXPOSE

指定于外界交互的端口

格式:
    EXPOSE <port> [<port>...]
示例:
    EXPOSE 80 443
    EXPOSE 8080    
    EXPOSE 11211/tcp 11211/udp
注:EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
如果没有暴露端口,后期也可以通过-p 8080:80方式映射端口,但是不能通过-P形式映射

2.4.5 VOLUME

容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。
为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
docker容器数据卷更详细的可参考 https://www.cnblogs.com/sucretan2010/p/11014957.html

  1. 匿名卷
VOLUME /data

这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无a状态化。
在容器中会自动创建/data目录
image.png
使用docker inspect 容器名可以看到/data目录挂载到了本地机器上的 /var/lib/docker/volumes/***中
image.png

  1. 命名卷

运行时可以覆盖这个挂载设置,比如:

docker run -d -v mydata:/data 镜像名
# 使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置
VOLUME /var/data /var/log
# 指定容器中的/var/log挂载到宿主机的/var/data目录,等同于-v /var/data:/var/log

2.4.6 RUN

每条 RUN 指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行,多条命令用&&来连接,避免执行多个RUN,使得镜像层数变多,最好只保留一个RUN。

RUN tar xf nginx-${nginx_ver}.tar.gz && \
        yum -y install gcc pcre-devel openssl-devel make &&  \
        cd nginx-${nginx_ver} && \
        ./configure && make && make install
RUN用于在构建镜像时执行命令,其有以下两种命令执行方式:
shell执行
格式:
    RUN <command>
exec执行
格式:
    RUN ["executable", "param1", "param2"]
示例:
    RUN apk update
    RUN ["/etc/execfile", "arg1", "arg1"]
注:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,
可以在构建时指定--no-cache参数,如:docker build --no-cache

2.4.7 WORKDIR

镜像的工作目录(为RUN、CMD、ENTRYPOINT、COPY和ADD等指令设定工作目录),类似于cd命令。

格式:
    WORKDIR /path/to/workdir
示例:
    WORKDIR /a  (这时工作目录为/a)
    WORKDIR b  (这时工作目录为/a/b)
    WORKDIR c  (这时工作目录为/a/b/c)
注: 
  通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY
  等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。

2.4.8 ADD

将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget

格式:
    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
    ADD hom* /mydir/          # 添加所有以"hom"开头的文件
    ADD hom?.txt /mydir/      # ? 替代一个单字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/
注意:尽量别用,会增加镜像的大小,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

2.4.9 COPY

与ADD类似,对于压缩文件,不会自动解压
注意:不能直接拷贝目录,但可以拷贝目录下的内容,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。

COPY config/ /opt/config/	把当前config目录下所有文件拷贝到/opt/config/下,如果/opt/config不存在,会创建

2.4.10 ARG(给dockerfile传参)

用于指定传递给构建运行时的变量(给dockerfile传参),相当于构建镜像时可以在外部为里面传参

格式:
    ARG <name>[=<default value>]
示例:
    ARG site
    ARG build_user=www

From centos:7
ARG parameter
VOLUME /usr/share/nginx
RUN yum -y install $parameter
EXPOSE 80 443
CMD nginx -g "daemon off;"

# 可以如下这样灵活传参
docker build --build-arg=parameter=net-tools -t nginx:01 . 

2.4.11 ENV

设置环境变量

格式:
#一次设置一个变量,#<key>之后的所有内容均会被视为其<value>的组成部分
ENV <key> <value>    
#设置多个环境变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
ENV <key1>=<value1> 	<key2>=<value2> \
 <key3>=<value3>   

示例:
    ENV myName John Doe
    ENV myDog Rex The Dog	
    ENV myCat=fluffy	myName=zhangsan
ENV  DOC_ROOt=/data/web/html/    单个文件 
ENV  DOC_ROOt=/data/web/html/ \     多个文件
     WEB_SERVER_PACKAGE="nginx-1.15.5"

COPY index.html ${DOC_ROOT:-/data/web/html/} # ${variable:-defaultValue} 表示如果变量值存在,就是用原来的值,否则使用默认值
COPY yum.repos.d /etc/yum.repos.d/
#ADD http://nginx.org/download/nginx-1.15.5.tar.gz /usr/local/src/
WORKDIR /usr/locl/
ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/

2.4.12 CMD

指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条 CMD 命令,只有
最后一条会被执行。如果用户在启动容器时指定了要运行的命令,则会覆盖掉 CMD 指定的命令。
覆盖的原因:CMD给出的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行命令。重点就是这个“默认”。意味着,如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT,那么,就会使用CMD指定的默认的执行命令执行。同时也从侧面说明了ENTRYPOINT的含义,它才是真正的容器启动以后要执行命令。

格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先)
    CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    CMD command param1 param2 (执行shell内部命令)
示例:
    CMD echo "This is a test." # 这种格式,在创建容器后会首先调用Shell,即自动在命令前面追加/bin/sh -c,即上述设置将执行如下命令:/bin/sh -c echo "This is a test."
    CMD ["/usr/bin/wc","--help"] # 如果你想在没有 shell 的情况下运行 <command> ,那么必须将命令表示为 JSON 数组并提供可执行文件的完整路径。

注:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

2.4.13 ENTRYPOINT

配置容器启动后执行的命令,并且不会被 docker run 提供的参数覆盖(但是,docker run的**–entrypoint**可以覆盖Dockerfile中ENTRYPOINT设置的命令)。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个 ENTRYPOINT 时,只有最后一个生效。
当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:<ENTRYPOINT> "<CMD>"

格式:
    ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先,这种格式可追加CMD参数)
    ENTRYPOINT command param1 param2 (shell内部命令,这种格式屏蔽追加任何参数)
示例:
    FROM ubuntu
    ENTRYPOINT ["ls", "/usr/local"]
    CMD ["/usr/local/tomcat"]
  之后,docker run 传递的参数,都会先覆盖cmd,然后由cmd 传递给entrypoint ,做到灵活应用

注:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,
 而docker run命令中指定的任何参数,都会被当做参数再次传递给CMD。
 Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,
 而只执行最后的ENTRYPOINT指令。
 通常情况下,ENTRYPOINT 与CMD一起使用,ENTRYPOINT 写默认命令,当需要参数时候 使用CMD传参。
CMD和ENTRYPOINT的区别可参考:https://docs.docker.com/engine/reference/builder/

2.4.14 CMD和ENTRYPOINT的比较

  1. Dockerfile 应至少指定 CMD 或 ENTRYPOINT 命令之一。
  2. ENTRYPOINT指令,往往用于设置容器启动后的第一个命令,这对一个容器来说往往是固定的。
  3. CMD指令,往往用于设置容器启动的第一个命令的默认参数,这对一个容器来说可以是变化的。
  4. docker run 往往用于给出替换CMD的临时参数

ENTRYPOINT&CMD

No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]
No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmd
CMD exec_cmd p1_cmd/bin/sh -c exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

3 Docker镜像制作

3.1 注意事项

  1. 减少镜像层
    • 一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。
    • 文件比较多时,放入到一个目录中,使用COPY拷贝整个目录
    • 不要多个 Label、ENV 等标签
  2. 避免使用ADD
    • 会增加镜像的大小
  3. 为了减少镜像的大小,应减少依赖,仅安装需要的软件包
  4. 如果有多个CMD,只有最后一个运行
  5. 如果有多个Entrypoint,只有最后一个运行
  6. 如果CMD和entrypoint共存,只有entrypoint运行,且最后的CMD会当做entrypoint的参数
  7. 多阶段构建镜像
# git clone https://github.com/lizhenliang/tomcat-java-demo
# cd tomcat-java-demo
# vi Dockerfile
FROM maven AS build
ADD ./pom.xml pom.xml
ADD ./src src/
RUN mvn clean package

FROM lizhenliang/tomcat
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY --from=build target/*.war /usr/local/tomcat/webapps/ROOT.war
# docker build -t demo:v1 .
# docker container run -d -v demo:v1
# 首先,第一个FROM 后边多了个 AS 关键字,可以给这个阶段起个名字。
# 然后,第二部分FROM用的我们上面构建的Tomcat镜像,COPY关键字增加了—from参数,用于拷贝某个阶段的文件到当前阶段。这样一个Dockerfile就都搞定了。

3.2 镜像制作

镜像制作分为两个阶段:
docker build阶段 基于dockerfile制作镜像 (RUN,用于此阶段的运行命令)
docker run阶段 基于镜像运行容器 (CMD,基于image run容器时候,需要运行的命令)

3.3 镜像制作案例

3.3.1 Dockerfile实例

# 指定基础镜像
FROM pikaqiu/ubuntu:14.04.20161014
 
# 维护者信息
MAINTAINER pikaqiu@163.com
 
# 设置环境
ENV RTMP_VERSION=1.1.10 \
    NPS_VERSION=1.11.33.4 \
    LIBAV_VERSION=11.8 \
    NGINX_VERSION=1.10.1 \
    NGINX_USER=www-data \
    NGINX_SITECONF_DIR=/etc/nginx/sites-enabled \
    NGINX_LOG_DIR=/var/log/nginx \
    NGINX_TEMP_DIR=/var/lib/nginx \
    NGINX_SETUP_DIR=/var/cache/nginx
 
# 设置构建时变量,镜像建立完成后就失效
ARG BUILD_LIBAV=false
ARG WITH_DEBUG=false
ARG WITH_PAGESPEED=true
ARG WITH_RTMP=true
 
# 复制本地文件到容器目录中
COPY setup/ ${NGINX_SETUP_DIR}/
RUN bash ${NGINX_SETUP_DIR}/install.sh
 
# 复制本地配置文件到容器目录中
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /sbin/entrypoint.sh
 
# 运行指令
RUN chmod 755 /sbin/entrypoint.sh
 
# 允许指定的端口
EXPOSE 80/tcp 443/tcp 1935/tcp
 
# 指定网站目录挂载点
VOLUME ["${NGINX_SITECONF_DIR}"]
 
ENTRYPOINT ["/sbin/entrypoint.sh"]
CMD ["/usr/sbin/nginx"]

3.3.2 构建镜像实战

  1. 环境准备

tomcat和jdk压缩包,创建一个txt,创建一个Dockerfile目录
image.png

  1. Dockerfile文件
FROM centos:7
MAINTAINER pikaqiu<pikaqiu@163.com>
 
COPY readme.txt /usr/local/readme.txt
 
ADD jdk-8u333-linux-x64.tar.gz /usr/local/  #add命令会自动解压,解压到/usr/local/
ADD apache-tomcat-9.0.64.tar.gz /usr/local/
 
RUN yum -y install vim
 
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 多个ENV最好合并为一个
ENV JAVA_HOME /usr/local/jdk1.8.0_333
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.64
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.64
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
 
EXPOSE 8080
 
CMD /usr/local/apache-tomcat-9.0.64/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.64/logs/catalina.out
  1. docker build构建成为一个镜像
docker build -t diytomcat:1.0 .

启动生成的镜像,构建Tomcat容器
这里设置了数据卷,宿主机的/home/wjc/build/tomcat/test对应该容器的/usr/local/apache-tomcat-9.0.64/webapps/test。这样关于test项目的修复只需要在宿主机上修改就可以了,不需要进入到容器中修改。

docker run -d -p 9090:8080 --name diytomcat -v /home/wjc/build/tomcat/test:/usr/local/apache-tomcat-9.0.64/webapps/test -v /home/wjc/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-9.0.64/logs diytomcat:1.0

image.png
image.png
挂载成功!
进入到容器中
image.png

3.4 Dokcer容器文件系统

2843746737-ec875617987376ae.png

4 参考文档

  1. https://blog.csdn.net/m0_46090675/article/details/121846718
  2. https://anqixiang.blog.csdn.net/article/details/113958341
  3. https://blog.csdn.net/m0_46845579/article/details/125533650
  4. https://huaweicloud.csdn.net/63311bd6d3efff3090b525b7.html
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值