Docker之镜像管理及Dockerfile

半城伤御伤魂 提交于 2019-12-07 14:39:28

目录

一、镜像工作原理

二、镜像管理

二、Dockerfile

三、构建部署Nginx

四、构建部署Java网站


镜像:

  1. 一个分层存储的文件:

    优点:易于扩展、优化存储空间

  2. 一个软件的环境

  3. 一个镜像可以用于创建多个容器

  4. 一种标准化的交付

一、镜像工作原理

镜像不是一个单一的文件,而是有多层构成。可以通过 docker history <ID/NAME> 查看镜像中各层内容及大小,每层对应着 Dockerfile中的一条指令。

$ docker history nginx:1.14
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
86898218889a        3 weeks ago         /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop)  STOPSIGNAL [SIGTERM]         0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop)  EXPOSE 80/tcp                0B                  
<missing>           3 weeks ago         /bin/sh -c ln -sf /dev/stdout /var/log/nginx…   22B                 
<missing>           3 weeks ago         /bin/sh -c set -x  && apt-get update  && apt…   53.7MB              
<missing>           3 weeks ago         /bin/sh -c #(nop)  ENV NJS_VERSION=1.14.0.0.…   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop)  ENV NGINX_VERSION=1.14.0-…   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:e6ca98733431f75e9…   55.3MB              

容器其实是在镜像的最上面加了一层读写层,在运行的容器中有文件改动时,会先从镜像里把要写的文件复制到容器自己的文件系统中,都会写到这个读写层。如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高了磁盘利用率。

若想持久化这些改动,可以通过 docker commit 将容器保存成一个新的镜像。

二、镜像管理

常用选项:

$ docker image --help
OPTIONS DESCRIBE
ls/images 列出镜像
pull 从仓库拉取镜像到本地
push 从本地上传镜像到仓库
inspect 显示详情
history 镜像历史信息
import 导入tar归档的容器文件系统创建镜像
save 保存一个镜像到tar归档文件
load 从tar归档或标准输入导入镜像
rm 移除一个或多个镜像
build 从Dockerfile构建镜像
tag 创建一个引用源镜像标记目标镜像

Example:

从仓库拉取镜像

docker pull nginx:1.14

保存镜像到tar归档文件

$ docker image save nginx:1.14 > myweb.tar

从tar归档或标准输入导入镜像

$ docker image load < myweb.tar

引用源镜像标记目标镜像

$ docker image tag nginx:1.14 web:v1
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tomcat              latest              41a54fe1f79d        2 weeks ago         463MB
nginx               1.14                86898218889a        3 weeks ago         109MB
web                 v1                  86898218889a        3 weeks ago         109MB
centos              7                   5182e96772bf        7 weeks ago         200MB
centos              latest              5182e96772bf        7 weeks ago         200MB

二、Dockerfile

官方仓库虽然有数十万的镜像资源,但在绝大多数情况下都不符合我们的需求,通常我们都会自己构建镜像。Dockfile 是一种被 Docker 程序解释的脚本, Dockerfile 由一条一条的指令组成,每条指令对应 Linux 下面的一条命令。Docker 程序将这些 Dockerfile 指令翻译真正的Linux命令。Docker 程序将读取 Dockerfile,根据指令生成定制的 image。

*注意:每一条指令就相当于给镜像加了一层,一个镜像不能超过 127 层,请惜字如金!

官方文档:https://docs.docker.com/engine/reference/builder/

常用指令:

OPTIONS DESCRIBE
FROM 基于哪个镜像构建新镜像
MAINTAINER(弃用) 镜像维护者信息
LABEL 同上,但用法更加灵活
RUN 构建镜像时运行的Shell命令
COPY 拷贝文件或目录到镜像中
CMD 运行容器时执行,如果有多个CMD指令,最后一个生效
ENTRYPOINT 运行容器时执行,如果有多个CMD指令,最后一个生效。可单独使用,也可与CMD配合使用
USER 为RUN、CMD、ENTRYPOINT执行指令指定运行用户
EXPOSE 声明容器运行的服务端口
WORKDIR 为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录
VOLUME 指定挂载点,使容器中的一个目录具有持久化存储数据的功能
ENV 设置环境变量

ENTRYPOINT与CMD的区别在于ENTRYPOINT可以使用CMD作为参数,通常都是用作启动后台服务。

先来一个简单的 Dockerfile

创建一个工作目录,在工作目录下创建一个py脚本

FROM 指明以 centos:latest 作为基础镜像

COPY 指明复制源文件 test.py 到容器的 /tmp 目录下,test.py没指明路径,会运行 build 命令的当前目录下查找。

CMD 在容器启动时运行的命令

$ mkdir work
$ cd work/

$ cat test.py 
#!/usr/bin/env python
print 'hello,container!'

$ cat Dockerfile 
# Description: test image
FROM centos:latest
LABEL maintainer="Qukecheng <example@163.com>"
COPY test.py /tmp
CMD  python /tmp/test.py

 docker build 命令是根据上下文自动构建镜像。构建上下文指定位置PATH或文件集URL,PATH是本地文件系统上的目录,URL是一个Git仓库地址。

构建由 Docker 守护程序运行,而不是CLI。构建过程第一件事是将整个上下文(递归)发送到守护进程。建议空目录作为上下文,并将 Dockerfile 保存在该目录下,目录中仅包含构建 Dockerfile 所需的文件,比如刚刚创建的 work 目录。

$ docker build --help

$ docker build -t myimage:v1 ./
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM centos:latest
 ---> 5182e96772bf
Step 2/4 : LABEL maintainer="Qukecheng <example@163.com>"
 ---> Running in 804c23af5fb3
Removing intermediate container 804c23af5fb3
 ---> 2409cc31df3f
Step 3/4 : COPY test.py /tmp
 ---> 02f2546571b9
Step 4/4 : CMD  python /tmp/test.py
 ---> Running in f3ce25242fca
Removing intermediate container f3ce25242fca
 ---> 72ff3d4714ca
Successfully built 72ff3d4714ca
Successfully tagged myimage:v1

使用刚刚生成的镜像,启动一个容器

$ docker container run --rm  myimage:v1 
hello,container!

还需要注意的是:

1. 一次 RUN 指令形成新的一层,进程让shell命令都写在一行,减少镜像层,一个镜像是不能超过 127 层的,在使用 RUN 指令时,可以在每条 shell 命令的结尾用转义换行  "\"。

2. 一次 RUN 形成新的一层,如果没有在同一层删除,无论文件是否最后删除,都会带到下一层,所以要在每一层清理对应的残留数据,减少镜像大小。比如 yum 之后,清一下缓存。

三、构建部署Nginx

$ tree web/
web/
├── base
│?? └── Dockerfile_nginx
└── project
    ├── Dockerfile_nginx
    └── nginx.conf
$ mkdir -pv web/{base,project}
$ cd web/base/
$ touch Dockerfile_nginx

Nginx

$ cat Dockerfile_nginx 
FROM centos:latest
LABEL maintainer="Qukecheng <example@163.com>"
RUN yum install -y gcc gcc-c++ make \
    openssl-devel pcre-devel gd-devel libxslt-devel \
    iproute net-tools telnet wget curl && \
    yum clean all && \
    rm -rf /var/cache/yum/*

RUN wget http://nginx.org/download/nginx-1.14.0.tar.gz && \
    tar -zxf nginx-1.14.0.tar.gz && \
    cd nginx-1.14.0 && \
    ./configure --prefix=/usr/local/nginx \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_realip_module \
    --with-http_image_filter_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_secure_link_module \
    --with-http_stub_status_module \
    --with-stream \
    --with-stream_ssl_module && \
    make -j $(grep processor /proc/cpuinfo | wc -l) && make install && \
    cd / && rm -rf nginx-1.14.0*

ENV PATH $PATH:/usr/local/nginx/sbin
WORKDIR /usr/local/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

开始构建镜像

$ docker build -t nginx1.14 -f Dockerfile_nginx ./
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
nginx1.14           latest              2b3cd8303924        10 minutes ago       323MB
centos              latest              5182e96772bf        7 weeks ago          200MB

有了基础镜像,就可以基于这个镜像封装项目到镜像了

项目镜像

$ cd project/
$ touch Dockerfile_nginx nginx.conf
$ cat Dockerfile_nginx 
FROM nginx1.14
COPY nginx.conf /usr/local/nginx/conf/

$ cat nginx.conf 
user  nobody;
worker_processes  1;
error_log  logs/error.log  info;
events {
    worker_connections  4096;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        charset utf-8;
        access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }

    }
}
$ docker build -t nginx:v1 -f Dockerfile_nginx ./

部署网站

$ docker network create web
$ docker volume create wwwroot
$ docker container run -d --name web_nginx -p 88:80 --network lnmp -v wwwroot:/usr/local/nginx/html nginx:v1 

四、构建部署Java网站

Java 程序依赖于 JDK 环境,我们可以把 JDK 放在宿主机上,容器以挂载形式使用,减少镜像大小及提高性能。

$ tar -zxf jdk-8u91-linux-x64.tar.gz
$ sudo mv jdk1.8.0_91/ /usr/local/jdk1.8
$ tree java/
java/
├── apache-tomcat-8.5.16.tar.gz
└── Dockerfile

0 directories, 2 files
$ cd java/
$ cat Dockerfile 
FROM centos:latest
LABEL maintainer="Qukecheng <example@163.com>"

ENV VERSION=8.5.16
ENV JAVA_HOME=/usr/local/jdk

RUN yum install wget curl unzip iproute net-tools -y && \
    yum clean all && \
    rm -rf /var/cache/yum/*

COPY . /

RUN tar zxf apache-tomcat-${VERSION}.tar.gz && \
    mv apache-tomcat-${VERSION} /usr/local/tomcat && \
    rm -rf apache-tomcat-${VERSION}.tar.gz /usr/local/tomcat/webapps/* && \
    mkdir /usr/local/tomcat/webapps/ROOT && \
    echo '<h1>Hello,Tomcat!</h1>' > /usr/local/tomcat/webapps/ROOT/status.html && \
    sed -i '1a JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"' /usr/local/tomcat/bin/catalina.sh && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

ENV PATH $PATH:/usr/local/tomcat/bin
WORKDIR /usr/local/tomcat
EXPOSE 8080
CMD ["catalina.sh", "run"]
$ docker build -t tomcat8:latest ./
$ docker container run -d --name tomcat_srv -p 89:8080 -v /usr/local/jdk1.8/:/usr/local/jdk tomcat8:latest 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!