四、docker镜像

镜像基本命令

查找镜像(仓库)

docker search 镜像名  

下载镜像

docker pull 镜像名:tag   (不指定tag,默认下载最新版)

查看本地已有镜像

docker image ls 

删除镜像

  • docker rmi 镜像id   (该镜像有关联的容器将不能删除)
  • docker rmi -f 镜像id   (强制删除)
  • docker rmi -f  ${docker image -qa}

commit制作镜像

注意: docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 docker commit 定制镜像,定制镜像应该使用 Dockerfile 来完成。
以定制Nginx镜像为例

1.下载nginx镜像

docker pull nginx

2.启动容器

docker run -d --name webserver -p 8080:80 nginx

3.浏览器访问主机ip:8080

4.进入webserver容器后台

docker exec -it webserver /bin/bash

5.修改/usr/share/nginx/html/index.html内容

echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html


6.再次浏览器访问主机ip:8080

7.docker diff可以查看容器发生了哪些变化

docker diff 容器名

8.将修改完的容器打包为镜像

命令格式:docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

docker commit --author "xuecan" --message "modify main page" webserver mynginx:1.0.0

查看创建成功的镜像mynginx

9.用mynginx运行容器

docker run -d --name webserver2 -p 8088:80 mynginx:1.0.0

10.浏览器访问主机ip:8088

说明

docker commit将容器制作为镜像,容器内部改变的内容不可追溯导致维护性查,而且容器运行时产生的垃圾数据、日志将导致镜像臃肿。故制作镜像需要使用下文介绍的Dockerfile方式。

Dockerfile制作镜像

镜像概念介绍

镜像相当于是应用程序、依赖库、运行环境的集合。基于Union FS联合文件系统,镜像有层级关系,一个镜像可以由基本镜像的基础上再包一层自己的业务资源制作出的新镜像。可以多层嵌套,Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过127 层。

scratch为空白镜像,如果以该镜像为基础镜像,说明不需要任何镜像为基础镜像。下文将介绍,我们定义的镜像,以centos为基础制作。在此之前先介绍下Dockerfile相关的指令。


Dockerfile 文件介绍

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
 

构建命令

docker build [OPTONS] <上下文路径/URL/->

例:docker build -t myimage:1.0.0  .
options:

  • -t 指定生成的镜像名:tag
  • -f Dockerfile文件名全路径(可以用主机相对位置)

镜像构建上下文(Context)

docker build -t myimage:1.0.0  .

上命令中的.即指定镜像构建上下文为主机的哪个目录。并不是指定Dockerfile文件的目录。只是在默认情况下,如果不额外指定 Dockerfile 的话,会将上下文目录下的名为 Dockerfile 的文件作为Dockerfile

而这个上下文是提供给Dockerfile中的ADD/COPY等命令使用,使其知道要操作的资源处于主机的哪个位置。

Dockerfile相关指令介绍

FROM 指定基础镜像

如:FROM scratch
如:FROM centos

MAINTAINER指定创建者信息

 

可以不用

RUN 执行命令

  • shell 格式: RUN <命令>
  • exec 格式: RUN ["可执行文件", "参数1", "参数2"]

注意:Dockerfile的每个指令都会创建一层镜像,所以如果有多个RUN命令需要合为一条:

RUN <命令1> && <命令2> &&  <命令3> &&  <命令n>

COPY 复制文件

格式:

  • COPY <源路径>  <目标路径>
  • COPY ["<源路径>",  "<目标路径>"]

其中源路径为构建命令指定的上下文路径开始,目标路径为docker镜像的目标路径。支持通配符

注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。

ADD 更高级的复制文件

格式:

  • ADD <源路径>  <目标路径>
  • ADD ["<源路径>",  "<目标路径>"]

ADD 指令和 COPY 的格式相同,功能是在COPY的基础上增强,如负责的文件为压缩包时会自动解压。这样就不用COPY后再执行RUN进行解压命令操作,减少了一层。缺点是ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

故建议文件复制均使用COPY 指令,仅在需要自动解压缩的场合使用 ADD
 

CMD 容器启动命令

CMD 指令的格式和 RUN 相似,也是两种格式:

  • shell 格式: CMD <命令>
  • exec 格式(推荐): CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式: CMD ["参数1", "参数2"...] 。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。 CMD 指令就是用于指定默认的容器主进程的启动命令的。
在创建容器运行时可以指定新的命令来替代镜像设置中的这个默认命令。


ENTRYPOINT 入口点

ENTRYPOINT 的格式和 CMD 指令格式一样,分为 exec 格式和 shell 格式。功能也类似。区别是CMD对用户创建容器运行时指定的命令将覆盖CMD指定的命令。而ENTRYPOINT 则对用户创建时指定的命令或参数进行追加。

与CMD的配置使用,Redis的官方镜像:

FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379
CMD [ "redis-server" ]

CMD用于接受参数,然后作为参数传递给ENTRYPOINT执行

ENV 设置环境变量

格式:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

ARG 构建参数

格式: ARG <参数名>[=<默认值>]
构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是, ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。
 

VOLUME 定义匿名卷

格式为:

  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>

容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷。卷即对应主机的存储磁盘上。

VOLUME /data
运行时容器的/data 目录就会在运行时自动挂载为主机的匿名卷,docker inspect 容器/id 可以查看到具体挂载的目录

docker run -d -v mydata:/data 镜像名/id 
mydata显示指定主机的mydata目录为挂载卷目录

EXPOSE 声明端口

格式为 EXPOSE <端口1> [<端口2>...]
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。配置的好处:

  • docker run -P 时,会自动随机主机端口映射容器的EXPOSE端口
  • docker run -p hostPort:containerPort 指定映射时方便找到配置的端口号
     

WORKDIR 指定工作目录

格式为 WORKDIR <工作目录路径>
指定的目录不存在将自动创建,指定工作目录后,以后的每一层制作镜像都将在该目录下。

USER 指定当前用户

格式: USER <用户名>
 

HEALTHCHECK 健康检查

格式:

  • HEALTHCHECK [OPTIONS] CMD <命令> :设置检查容器健康状况的命令
  • HEALTHCHECK NONE :如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
     

命令的返回值决定了该次健康检查的成功与否: 0 :成功; 1 :失败; 2 :保留,不要使用这个值

OPTIONS:

  • --interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
  • --timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
  • --retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3次。

和 CMD , ENTRYPOINT 一样, HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效。
例:

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1

每 5 秒检查一次,超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令
 

ONBUILD 为他人做嫁衣裳

格式: ONBUILD <其它指令> 。
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN , COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
 

Dockerfile示例

需求

制作一个镜像,该镜像启动的容器提供两个helloworld的服务

步骤

1.准备好jdk环境、可执行的两个helloworld的jar(用springboot简单写),其中helloworld8080.jar的端口号是8080,helloworld8081的端口号是8081

2.start.sh为启动这两个服务应用的脚本

#!/bin/bash

echo "start......"
# 后台运行
java -jar helloworld8080.jar &

# 前台运行阻塞
java -jar helloworld8081.jar

3.Dockerfile文件

FROM centos
#将两个jar包复制到根目录下
COPY hello* /
COPY start.sh /
#将java环境复制到/usr/local/下并解压
ADD jdk-8u181-linux-x64.tar.gz /usr/local/

#配置java环境
ENV JAVA_HOME /usr/local/jdk1.8.0_181
ENV CLASSPATH $JAVA_HOME/lib/*.jar
ENV PATH $PATH:$JAVA_HOME/bin

#设置工作目录
WORKDIR /

RUN chmod a+x start.sh

#声明暴露端口
EXPOSE 8080 8081

# 只会执行最后一个CMD
#CMD java -jar helloworld8080.jar &
#CMD java -jar helloworld8081.jar

CMD ["/start.sh"]

注意:多个CMD只对最后一个有效,之前的均不允许,所以不能简单的写两个CMD执行两个helloworld。此处利用一个脚本start.sh将两个启动命令包装起来。第一个服务启动必须后台运行,否则第二个服务启动将执行不到。而第二个服务启动,必须阻塞,否则start.sh任务完成后,容器就会退出。

4.生成镜像

docker build -t myhellocentos:1.0.0 .

由这边可以看出来,Dockerfile制作镜像每个指令都是一个层级

5.运行容器

docker run -d -p 8080:8080 -p 8081:8081 --name myhellocontainer myhellocentos:1.0.0

6.浏览器访问

http://192.168.31.200:8080/hello

显示:Hello World!8080

http://192.168.31.200:8081/hello

显示:Hello World!8081

192.168.31.200为主机ip

7.同时可以进入到容器

 docker exec -it myhellocontainer /bin/bash

执行top命令,即可看到容器内部服务执行情况

 

最后

  • 虽然容器内部看到有多个服务进程在执行,但是对于主机来看仅一个容器进程在执行
  • 不建议把两个应用服务放在同一个容器中,最好应该单独每个应用服务独立一个容器。本节为学习使用才这么做

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值