欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Docker 镜像

程序员文章站 2022-03-30 09:29:31
...

镜像是部署应用的基石

镜像是什么?

    1.一个分层存储的文件:优点 - 易于扩展、优化存储空间

    2.一个软件的环境

    3.一个镜像可以创建N个容器

    4.一种标准化的交付

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

[aaa@qq.com ~]#  docker history nginx
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
881bd08c0b08        47 hours ago        /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                  
<missing>           47 hours ago        /bin/sh -c #(nop)  STOPSIGNAL SIGTERM           0B                  
<missing>           47 hours ago        /bin/sh -c #(nop)  EXPOSE 80                    0B                  
<missing>           47 hours ago        /bin/sh -c ln -sf /dev/stdout /var/log/nginx…   22B                 
<missing>           47 hours ago        /bin/sh -c set -x  && apt-get update  && apt…   54MB                
<missing>           47 hours ago        /bin/sh -c #(nop)  ENV NJS_VERSION=1.15.9.0.…   0B                  
<missing>           47 hours ago        /bin/sh -c #(nop)  ENV NGINX_VERSION=1.15.9-…   0B                  
<missing>           47 hours ago        /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B                  
<missing>           2 days ago          /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
<missing>           2 days ago          /bin/sh -c #(nop) ADD file:5ea7dfe8c8bc87ebe…   55.3MB    

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

镜像管理常用命令

这个是我在生产环境中的

aaa@qq.com *node* @ntp_server:/root# docker image ls
REPOSITORY                                   TAG                 IMAGE ID            CREATED             SIZE
harbor:5000/skyform/admin                    v1                  c93560620a93        2 weeks ago         535 MB
harbor:5000/skyform/zabbixdataenhancer       v1                  2c6739c0cf27        2 weeks ago         184 MB
harbor:5000/skyform/zabbixcmdb               v1                  48a3488927ec        2 weeks ago         172 MB
harbor:5000/skyform/sys                      v1                  766323bdcfc3        3 months ago        171 MB
harbor:5000/skyform/opssync                  v1                  03bee45d59dc        3 months ago        149 MB
harbor:5000/skyform/project                  v1                  0f421139d3cf        3 months ago        172 MB
harbor:5000/skyform/monitorconfig            v1                  52b857337569        3 months ago        146 MB
harbor:5000/skyform/zabbixcollector          v1                  abb70d74539d        3 months ago        184 MB
harbor:5000/skyform/alarm                    v1                  6afdd9ab41ed        3 months ago        168 MB
harbor:5000/skyform/patrolmanagement         v1                  4b1f14799f6b        3 months ago        155 MB
harbor:5000/skyform/rms                      v1                  59facfc8aefa        3 months ago        176 MB
docker.io/grafana/grafana                    latest              7a7874a2caba        4 months ago        223 MB
docker.io/redis                              latest              0a153379a539        5 months ago        83.4 MB
musingtec/tomcat8/jdk8                       v7.0                521dc0ccb488        8 months ago        983 MB
harbor:5000/skyform/kafkaplugin              test                7fda08863238        10 months ago       162 MB
harbor:5000/skyform/sys                      test                bf1de5e30847        10 months ago       171 MB
harbor:5000/skyform/grafana                  test                45bef2df9ee6        11 months ago       301 MB
harbor:5000/skyform/cas                      test                c8c76fa8ec6f        11 months ago       193 MB
harbor:5000/skyform/kafka                    v1                  c74a25350302        13 months ago       270 MB
harbor:5000/skyform/elasticsearch            master              7c52ec727039        13 months ago       580 MB
harbor:5000/skyform/zabbix-server-mysql      test                fe5e21361029        15 months ago       107 MB
harbor:5000/skyform/zabbix-web-nginx-mysql   test                45e29c5dcfb8        17 months ago       176 MB
harbor:5000/skyform/mysql                    test                b4e78b89bcf3        17 months ago       412 MB
harbor:5000/skyform/zookeeper                test                f2249a75c5d0        17 months ago       143 MB
harbor:5000/skyform/elasticsearch            test                d1ac13423d3c        18 months ago       580 MB
docker.io/kibana                             5.5.2               70e73a80c440        18 months ago       382 MB
pull - 从镜像仓库拉取镜像
[aaa@qq.com ~]# docker image pull
"docker image pull" requires exactly 1 argument.
See 'docker image pull --help'.

Usage:  docker image pull [OPTIONS] NAME[:TAG|@DIGEST]

Pull an image or a repository from a registry

[aaa@qq.com ~]# docker image pull busybox
Using default tag: latest
latest: Pulling from library/busybox
697743189b6d: Pull complete 
Digest: sha256:061ca9704a714ee3e8b80523ec720c64f6209ad3f97c0ff7cb9ec7d19f15149f
Status: Downloaded newer image for busybox:latest
[aaa@qq.com ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              881bd08c0b08        47 hours ago        109MB
busybox             latest              d8233ab899d4        2 weeks ago         1.2MB

inspect - 显示一个或多个镜像详细信息
Usage: docker image inspect [OPTIONS] IMAGE [IMAGE...] [flags]
[aaa@qq.com ~]# docker inspect busybox
[
    {
        "Id": "sha256:d8233ab899d419c58cf3634c0df54ff5d8acc28f8173f09c21df4a07229e1205",
        "RepoTags": [
            "busybox:latest"
        ],
...

import    - 导入tag归档的容器文件系统创建镜像
Usage:  docker image import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] [flags]
docker import test.tar name:tag
[aaa@qq.com ~]# cat name.tar | docker image import – name:tag

save   - 保存一个或多个镜像到一个tar归档文件
Usage:  docker image save [OPTIONS] IMAGE [IMAGE...] [flags]
[aaa@qq.com ~]# docker image save name/id > name.tar

load - 从tar归档或标准输入导入镜像
Usage:  docker image load [OPTIONS]
docker load -i name.tar
docker load < name.tar
save,load命令用于将一个镜像从一台Docker主机到另一台Docker主机。

rm - 移除一个或多个镜像
Usage:  docker image rm [OPTIONS] IMAGE [IMAGE...] [flags]
[aaa@qq.com ~]# docker image rm busybox
Untagged: busybox:latest
Untagged: aaa@qq.com:061ca9704a714ee3e8b80523ec720c64f6209ad3f97c0ff7cb9ec7d19f15149f
Deleted: sha256:d8233ab899d419c58cf3634c0df54ff5d8acc28f8173f09c21df4a07229e1205
Deleted: sha256:adab5d09ba79ecf30d3a5af58394b23a447eda7ffffe16c500ddc5ccb4c0222f

build - 从Dockerfile构建镜像
tag  - 创建一个引用源镜像标记目标镜像
push - 推送一个镜像到镜像仓库

一个Dockerfile遵循特定的格式和指令集。常用指令如下表:

Docker 镜像

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

一个简单的Dockerfile是这样的:

FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py

FROM 从ubuntu:15.04镜像创建一个图层。
COPY  从Docker客户端的当前目录添加文件。
RUN make构建你的应用用你的应用程序。
CMD 在容器启动时运行的命令。

Docker镜像由只读层组成,每个层都代表一个Dockerfile指令。这些层是堆叠的,每一层都是前一层变化的增量。

Docker Build命令

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

示例:

Usage:  docker build [OPTIONS] PATH | URL | - [flags]
# docker build .  
# docker build -t shykes/myapp .
# docker build -t shykes/myapp -f /path/Dockerfile /path
# docker build -t shykes/myapp http://www.example.com/Dockerfile

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

构建PHP网站镜像并部署

建议大家不要直接就上手写Dockerfile,正确方式是先创建一个容器在里面将要做的操作先梳理下,再按照顺序复制到Dockerfile文件。根据我们之前所说的,先准备一个基础镜像,再构建项目镜像。部署过PHP网站的朋友知道,PHP是一个动态程序,负责解析的是一个叫PHP-FPM的服务,而这个服务不支持静态页面处理。一般结合Nginx解决这个问题。Nginx本身是一个静态Web服务器,并不支持解析PHP程序,但它支持了FastCGI接口来调用动态服务来解析PHP程序。

当客户端请求PHP页面时,Nginx通过fastcgi接口转发给本地9000端口的PHP-FPM子进程处理,处理完成后返回Nginx。所以,秉承着一个容器一个服务的原则,咱们要创建两个基础镜像:

Nginx和PHP基础镜像目录结构:

[aaa@qq.com lamp]# tree .
.
├── Dockerfile-nginx
└── Dockerfile-php

0 directories, 2 files

php

[aaa@qq.com lamp]# cat Dockerfile-php 
FROM centos:7
MAINTAINER mail.test.com
RUN yum install epel-release -y && \
    yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
    libcurl-devel libjpeg-devel libpng-devel openssl-devel \
    libmcrypt-devel libxslt-devel libtidy-devel autoconf \
    iproute net-tools telnet wget curl &&  \
    yum clean all && \
    rm -rf /var/cache/yum/*

RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \
    tar zxf php-5.6.36.tar.gz && \
    cd php-5.6.36 && \
    ./configure --prefix=/usr/local/php \
    --with-config-file-path=/usr/local/php/etc \
    --with-config-file-scan-dir=/usr/local/php/etc/php.d \
    --enable-fpm --enable-opcache --enable-static=no \
    --with-mysql --with-mysqli --with-pdo-mysql \
    --enable-phar --with-pear --enable-session \
    --enable-sysvshm --with-tidy --with-openssl \
    --with-zlib --with-curl --with-gd --enable-bcmath \
    --with-jpeg-dir --with-png-dir --with-freetype-dir \
    --with-iconv --enable-posix --enable-zip \
    --enable-mbstring --with-mhash --with-mcrypt --enable-hash \
    --enable-xml --enable-libxml --enable-debug=no && \
    make -j 4 &&  make install && \
    cp php.ini-production /usr/local/php/etc/php.ini && \
    cp sapi/fpm/php-fpm.conf /usr/local/php/etc/php-fpm.conf && \
    sed -i "90a \daemonize = no" /usr/local/php/etc/php-fpm.conf &&  \
    mkdir /usr/local/php/log && \
    cd / && rm -rf php*

ENV PATH $PATH:/usr/local/php/sbin
WORKDIR /usr/local/php
EXPOSE 9000
CMD ["php-fpm"]

nginx

[aaa@qq.com lamp]# cat Dockerfile-nginx 
FROM centos:7
MAINTAINER mail.test.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.12.2.tar.gz &&  \
tar zxf nginx-1.12.2.tar.gz && \
cd nginx-1.12.2 && \
./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 4 &&  make install && \
mkdir -p /usr/local/nginx/conf/vhost && \
rm -rf /usr/local/nginx/html/* && \
echo "ok" >> /usr/local/nginx/html/status.html && \
cd / && rm -rf nginx-1.12.2*
ENV PATH $PATH:/usr/local/nginx/sbin
WORKDIR /usr/local/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]


构建
[aaa@qq.com lamp]# docker build -t php56 -f Dockerfile-php .
[aaa@qq.com lamp]# docker build -t nginx112 -f Dockerfile-nginx .


有了基础镜像,就可以基于这个镜像封装项目到镜像了。
  项目镜像
cd project
# vi Dockerfile-php
FROM php56
COPY wwwroot /wwwroot
CMD ["php-fpm"]
# cat wwwroot/phpinfo.php 
<?php phpinfo();?>
docker build -t php56:v1 -f Dockerfile-php01 .

[aaa@qq.com lamp]# cat Dockerfile-nginx01 
FROM nginx112
COPY nginx.conf /usr/local/nginx/conf/

[aaa@qq.com lamp]# cat nginx.conf 
user  nobody;
worker_processes  1;
error_log  logs/error.log  info;
events {
    worker_connections  1024;
}
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;
        access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }
        location ~ \.php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
}

[aaa@qq.com lamp]# docker build -t nginx112:v1 -f Dockerfile-nginx01 .
以上nginx配置文件,只是在默认配置文件基础上增加了处理PHP的location:

[aaa@qq.com lamp]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx112            v1                  bc0cb0604cd6        59 seconds ago      364MB
php                 v1                  b78b979d24cb        3 minutes ago       520MB
nginx112            latest              c390f3e1a040        9 minutes ago       364MB
php56               latest              49d4d870a2cd        17 minutes ago      520MB
nginx               latest              881bd08c0b08        2 days ago          109MB
centos              7                   1e1148e4cc2c        3 months ago        202MB

部署LNMP网
[aaa@qq.com lamp]# docker network create lnmp
e735b1d4b2142f8c7328a899482e2bfbd4f39a023f07b791402ac84422167fa6
[aaa@qq.com lamp]# docker volume create wwwroot
wwwroot

[aaa@qq.com lamp]# docker container run -d --name lnmp_nginx -p 88:80 --net lnmp --mount src=wwwroot,dst=/usr/local/nginx/html nginx112:v1
06b1c36d91f5406d3dabb8ef97b781eea8c1847e2161cfc5abc0bf9ce94c5b25

[aaa@qq.com lamp]# docker container run -d --name lnmp_php --net container:lnmp_nginx --mount src=wwwroot,dst=/usr/local/nginx/html php:v1
db76cd1f5c079fa35da44b774ad187fca77d748fb92338b7c327ba53a7341274

创建PHP容器时指定与Nginx容器同一个网络,这样Nginx就可以代理127.0.0.1:9000到PHP-FPM了。

访问测试:http://192.168.43.199:88

构建JAVA网站镜像并部署

JAVA程序必须有JDK环境,咱们直接把JDK放到宿主机上,容器以挂载形式使用,减少镜像大小及提高性能。

[aaa@qq.com ~]# tar xf jdk-8u151-linux-x64.tar.gz 
[aaa@qq.com ~]# mv jdk1.8.0_151 /usr/local/jdk1.8

[aaa@qq.com tomcat]# cat Dockerfile 
FROM centos:7
MAINTAINER mail.test.com

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

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

RUN wget http://mirrors.shu.edu.cn/apache/tomcat/tomcat-8/v${VERSION}/bin/apache-tomcat-${VERSION}.tar.gz && \
    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 "ok" > /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"]

[aaa@qq.com tomcat]# docker build -t tomcat-85 -f Dockerfile .
[aaa@qq.com tomcat]# docker container run -d --name tomcat85test -v /usr/local/jdk1.8/:/usr/local/jdk -p 89:8080 tomcat-85

注意:VERSION=8.5.37 Tomcat版本号会更新,构建前需确保这个版本号可用,否则构建失败。

访问测试:http://192.168.43.199:89/status.html

减少镜像层 一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。

例如:

FROM centos:7
MAINTAINER mail.test.com
RUN yum install epel-release -y 
RUN yum install -y gcc gcc-c++ make -y
RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz
RUN tar zxf php-5.6.36.tar.gz
RUN cd php-5.6.36
RUN ./configure --prefix=/usr/local/php 
RUN make -j 4 
RUN make install
EXPOSE 9000
CMD ["php-fpm"]

应该写成:

FROM centos:7
MAINTAINER mail.163.com
RUN yum install epel-release -y && \
    yum install -y gcc gcc-c++ make

RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \
    tar zxf php-5.6.36.tar.gz && \
    cd php-5.6.36 && \
    ./configure --prefix=/usr/local/php \
    make -j 4 && make install
EXPOSE 9000
CMD ["php-fpm"]

优化镜像大小:清理无用数据

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

FROM centos:7
MAINTAINER mail.test.com
RUN yum install epel-release -y && \
    yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
    libcurl-devel libjpeg-devel libpng-devel openssl-devel \
    libmcrypt-devel libxslt-devel libtidy-devel autoconf \
    iproute net-tools telnet wget curl && \
    yum clean all && \
    rm -rf /var/cache/yum/*

RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \
    tar zxf php-5.6.36.tar.gz && \
    cd php-5.6.36 && \
    ./configure --prefix=/usr/local/php \
    make -j 4 && make install && \
    cd / && rm -rf php*

至少能节省几十M,甚至几百M。

减少网络传输时间

最好在内部有一个存放软件包的地方,类似于上述的PHP官方下载地址:http://docs.php.net/distributions/php-5.6.36.tar.gz 如果用到maven构建这样的操作,同时也更改为私有maven仓库,减少网络传输时间,提高镜像构建速度。

多阶段镜像构建

如果运行一个项目,根据咱们上面的做法,是直接把代码拷贝到基础镜像里,如果是一个需要预先代码编译的项目呢?例如JAVA语言,如何代码编译、部署在一起完成呢!

上面做法需要事先在一个Dockerfile构建一个基础镜像,包括项目运行时环境及依赖库,再写一个Dockerfile将项目拷贝到运行环境中,有点略显复杂了。

像JAVA这类语言如果代码编译是在Dockerfile里操作,还需要把源代码构建进去,但实际运行时只需要构建出的包,这种把源代码放进去有一定安全风险,并且也增加了镜像体积。

为了解决上述问题,Docker 17.05开始支持多阶段构建(multi-stage builds),可以简化Dockerfile,减少镜像大小。

例如,构建JAVA项目镜像:在github上找了一个JAVA博客项目作为演示:

[aaa@qq.com ~]# git clone https://github.com/b3log/solo.git
正克隆到 'solo'...
remote: Enumerating objects: 35, done.
remote: Counting objects: 100% (35/35), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 40664 (delta 9), reused 20 (delta 7), pack-reused 40629
接收对象中: 100% (40664/40664), 90.90 MiB | 226.00 KiB/s, done.
处理 delta 中: 100% (22324/22324), done.


# cd solo
# vi Dockerfile01
FROM maven AS build
ADD ./pom.xml pom.xml
ADD ./src src/
RUN mvn clean package

FROM tomcat-85
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY --from=build target/*.war /usr/local/tomcat/webapps/ROOT.war
CMD ["catalina.sh", "run"]

# docker build -t tomcat-85 -f Dockerfile01 .

# docker container run -d --name solotest -v /usr/local/jdk1.8:/usr/local/jdk solo:v1

首先,第一个FROM 后边多了个 AS 关键字,可以给这个阶段起个名字。然后,第二部分FROM用的我们上面构建的Tomcat镜像,COPY关键字增加了--from参数,用于拷贝某个阶段的文件到当前阶段。这样一个Dockerfile就都搞定了。小结:镜像小有很多好处,例如快速部署、快速回滚。减少服务中断时间,同时镜像仓库占用磁盘空间也少了。

转载于:https://my.oschina.net/kcw/blog/3019291