【容器应用系列教程】Docker镜像管理

一、关于镜像

1.镜像的基本概念

docker_image01

  • 分层的文件系统
  • 镜像是只读的
  • 基于镜像创建容器时,镜像最上面会添加一个可写层,用户的所有操作都会存到这个可写层内

2.镜像的核心技术

  • COW机制
    • Copy On Write写时复制
      • 创建容器时,镜像会在最上层添加一个读写层,只有修改文件时,该才会被复制到读写层进行修改
      • 容器删除时,读写层会随之删除,所有容器对关键数据进行持久化存储
  • Union fs联合文件系统
    • 支持将多个不同的文件系统挂载到同一个虚拟文件系统中
      • overlay2文件系统,是Docker默认使用的
[root@flannet ~]# docker info
Client: Docker Engine - Community
 Version:    24.0.2
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.10.5
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.18.1
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 1
  Running: 1
  Paused: 0
  Stopped: 0
 Images: 11
 Server Version: 24.0.2
 Storage Driver: overlay2	#默认使用

二、镜像管理操作

1.镜像命名格式

  • 仓库名称/镜像名称:标签
    • 标记tag默认是latest >> 如果不写标签默认会使用latest标签
      • 几个镜像名的展示
        • test.linux.com/tomcat:8.9
        • polinux/stress
        • nginx
        • hub.docker.com/nginx:latest

2.下载镜像和查看镜像

[root@flannet ~]# docker pull nginx:latest
[root@flannet ~]# docker images
REPOSITORY     TAG       IMAGE ID       CREATED             SIZE
halohub/halo   2.6       da836bfd0ddc   5 days ago          367MB
haproxy        latest    95eb357b4726   5 days ago          108MB
nginx          latest    f9c14fe76d50   12 days ago         143MB
wordpress      latest    5174bdcbb532   13 days ago         616MB
redis          latest    0ec8ab59a35f   13 days ago         117MB
tomcat         8         b0d447aaf3db   2 weeks ago         475MB
busybox        latest    8135583d97fe   2 weeks ago         4.86MB
mysql          5.7       dd6675b5cfea   7 weeks ago         569MB
centos         7         eeb6ee3f44bd   20 months ago       204MB

3.导出镜像

docker save -o 要导出的tar包名 镜像名:标签
[root@flannet ~]# docker save -o busybox.tar busybox:latest

4.导入镜像

docker load -i tar包名
[root@flannet ~]# docker load -i busybox.tar

5.删除镜像

docker rmi 镜像名:标签
[root@flannet ~]# docker rmi halohub/halo:2.6

6.查看镜像的详细信息

[root@flannet ~]# docker image inspect nginx:latest

[
    {
        "Id": "sha256:f9c14fe76d502861ba0939bc3189e642c02e257f06f4c0214b1f8ca329326cda",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:af296b188c7b7df99ba960ca614439c99cb7cf252ed7bbc23e90cfda59092305"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2023-05-24T22:43:48.18207587Z",
        "Container": "23b0fce2f40be83daa129eacbf79b8a57c6524a7898bf3aba06e10c15b433d0d",
        "ContainerConfig": {
            "Hostname": "23b0fce2f40b",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.0",
                "NJS_VERSION=0.7.12",
                "PKG_RELEASE=1~bullseye"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
            ],
            "Image": "sha256:a14a5803cbf095a0268663fe3235681c2f7fd5d0b59c242d99e7b1ebb59284f3",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "DockerVersion": "20.10.23",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.0",
                "NJS_VERSION=0.7.12",
                "PKG_RELEASE=1~bullseye"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "sha256:a14a5803cbf095a0268663fe3235681c2f7fd5d0b59c242d99e7b1ebb59284f3",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 142560184,
        "VirtualSize": 142560184,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/2e6bb5febb75810654c0852225e655e8657d622b2c80c709e337eae4147cc8b9/diff:/var/lib/docker/overlay2/a05acf6a7360cd9eae05721a0ba74653a4ac44b03b47311771ad426e84b1a451/diff:/var/lib/docker/overlay2/d077b39b99d40c2061689e86bf9dab74f7e86616fc40bf546fd5184c44d5770f/diff:/var/lib/docker/overlay2/ea246994c98a9e5745f3b8c9f43dd930e16dcffdd2950aa88be853b80f2d0c4d/diff:/var/lib/docker/overlay2/5a6d22d946e4843397c18c2b2d4df28aa6b7e119733c8421ea2db86ed77495d8/diff",
                "MergedDir": "/var/lib/docker/overlay2/15e2f7bf56991df7a0c49aad6dfad5aa75eb0465b58d03c8103b780e222d3757/merged",
                "UpperDir": "/var/lib/docker/overlay2/15e2f7bf56991df7a0c49aad6dfad5aa75eb0465b58d03c8103b780e222d3757/diff",
                "WorkDir": "/var/lib/docker/overlay2/15e2f7bf56991df7a0c49aad6dfad5aa75eb0465b58d03c8103b780e222d3757/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:8cbe4b54fa88d8fc0198ea0cc3a5432aea41573e6a0ee26eca8c79f9fbfa40e3",
                "sha256:4b8862fe7056d8a3c2c0910eb38ebb8fc08785eaa1f9f53b2043bf7ca8adbafb",
                "sha256:e60266289ce4a890aaf52b93228090998e28220aef04f128704141864992dd15",
                "sha256:7daac92f43be84ad9675f94875c1a00357b975d6c58b11d17104e0a0e04da370",
                "sha256:5e099cf3f3c83c449b8c062f944ac025c9bf2dd7ec255837c53430021f5a1517",
                "sha256:4fd83434130318dede62defafcc5853d03dae8636eccfa1b9dcd385d92e3ff19"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

三、Dockerfile定制镜像

作用:基于已有的镜像,定制符合自身需求的镜像

1.规划目录

建议提前规划目录,一个Dockerfile对应一个镜像

[root@flannet ~]# mkdir /centos

2.编写Dockerfile

注意Dockerfile的大小写

[root@flannet ~]# vim /centos/Dockerfile

FROM centos:7
#配置Centos的yum源为国内源
RUN yum install -y wget && wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo && yum clean all && yum makecache
#安装基本命令
RUN yum install -y vim && yum install -y net-tools
#创建一个名为wangshengjj的用户
RUN useradd wangshengjj

3.构建镜像

docker build -t 镜像名:标签 Dockerfile目录
[root@flannet ~]# docker build -t centos_wang:0.1 /centos/

验证镜像

[root@flannet ~]# docker run -itd --name centos centos_wang:0.1
[root@flannet ~]# docker exec -it centos /bin/bash
[root@935de887e27f /]# id wangshengjj
uid=1000(wangshengjj) gid=1000(wangshengjj) groups=1000(wangshengjj)
[root@935de887e27f /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1472
        inet 10.100.43.2  netmask 255.255.255.0  broadcast 10.100.43.255
        ether 02:42:0a:64:2b:02  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

4.Dockerfile常用指令

FROM

当本地不存在指定镜像,将会自动联网下载指定镜像

FROM 镜像名:标签

MAINTAINER

用于指定镜像作者信息

MAINTAINER <user> <email>

RUN

用于指定在构建镜像的时候,执行的操作
RUN指令后面的命令,必须在原镜像中存在命令

RUN cmd1 && cmd2 && cmd3

CMD

用于指定创建容器的时候,自动执行的命令

  • 一个Dockerfile中只能出现一个CMD
  • 一般都是写前台启动服务的指令
  • 创建容器时指定的命令会覆盖CMD指令的命令
CMD  /usr/sbin/httpd -D FOREGROUND	#前台启动httpd
CMD [ "/usr/sbin/httpd", "-D", "FOREGROUND" ]	#上面的命令另外一种写法

ENTRYPOINT

用于创建容器的时候,自动执行的命令
CMD的区别:当用户创建容器指定自定义命令的时候,不会被覆盖

ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
ENTRYPOINT [ "/usr/sbin/httpd", "-D", "FOREGROUND" ]

CMD指令可以作为ENTRYPOINT的参数用

CMD [ "-D", "FOREGROUND" ]
ENTRYPOINT /usr/sbin/httpd

COPY

拷贝本地文件、目录到镜像中
源文件以相对路径的方式写,一般源文件位于和Dockerfile同级目录

COPY <源文件> <目的文件>

ADD

拷贝文件、目录

  • COPY区别:
    • 源文件支持本地文件网络文件压缩包拷贝后自动解压

EXPOSE指令

说明容器要发布的端口
真正发布端口的时候,还是要靠docker run -p命令
使用docker image inspect命令可查看到信息

EXPOSE 80/tcp

VOLUME

指定并说明持久化存储的目录
一般用于用户在创建容器的时候,使用docker run -v的时候
使用docker image inspect命令可查看到信息

VOLUME 容器内目录

如果用户在创建容器的时候,未指定-v参数,那么Docker会默认生成一个隐藏卷,用于存放数据
一般位于目录/var/lib/docker/volumes/容器ID/_data/

ENV

在容器中定义环境变量

ENV 变量名称  值

WORKDIR

指定容器的当前目录/工作目录
用户创建完容器,进入容器后自动进入的目录

WORKDIR <目录名称>

USER

指定容器当前登录用户

USER <用户名>

6.使用Dockerfile构建Nginx镜像(基于Centos7)

准备Dockerfile目录

[root@flannet ~]# mkdir /nginx

准备Ningx安装包

[root@flannet ~]# wget http://nginx.org/download/nginx-1.20.2.tar.gz
[root@flannet ~]# cp nginx-1.20.2.tar.gz /nginx/

编写Dockerfile文件

[root@flannet ~]# vim /nginx/Dockerfile
FROM centos:7
#配置国内yum源
RUN yum install -y wget && wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo && yum clean all && yum makecache
#拷贝Nginx安装包
ADD nginx-1.20.2.tar.gz /tmp/
#安装Nginx需要的依赖
RUN yum install -y gcc openssl-devel pcre-devel zlib-devel make
#准备Nginx目录
RUN mkdir -p /var/tmp/nginx/{client,proxy,fastcgi,uwsgi,scgi} && useradd -s /sbin/nologin nginx
#编译Nginx
RUN cd /tmp/nginx-1.20.2 && ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-stream --with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-http_secure_link_module --with-threads --http-client-body-temp-path=/var/tmp/nginx/client/ --http-proxy-temp-path=/var/tmp/nginx/proxy/ --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi/ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi/ --http-scgi-temp-path=/var/tmp/nginx/scgi/ && make && make install
#指定端口为80
EXPOSE 80/tcp
#删除临时文件
RUN rm -rf /tmp/nginx*
#启动容器时执行的命令
CMD /usr/local/nginx/sbin/nginx -g "daemon off;"
[root@flannet ~]# docker build -t nginx:v1 /nginx/
[root@flannet ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        v1        a705ccd9164b   2 minutes ago   1.14GB
[root@flannet ~]# docker run -itd --name nginx -p 80:80 nginx:v1

docker_image02

7.使用Dockerfle构建Tomcat镜像(基于Centos7)

准备Dockerfile目录

[root@flannet ~]# mkdir /tomcat

下载jdktomcat

[root@flannet ~]# cd /tomcat
[root@flannet tomcat]# wget https://mirrors.huaweicloud.com/java/jdk/8u191-b12/jdk-8u191-linux-x64.tar.gz
[root@flannet tomcat]# wget --no-check-certificate https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.88/bin/apache-tomcat-8.5.88.tar.gz

编写Dockerfile

[root@flannet tomcat]# vim /tomcat/Dockerfile
FROM centos:7
#拷贝jdk17
ADD jdk-8u191-linux-x64.tar.gz /usr/local
#配置jdk17环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_191
#拷贝tomcat
ADD apache-tomcat-8.5.88.tar.gz /usr/local
#改目录名称
RUN mv /usr/local/apache-tomcat-8.5.88 /usr/local/tomcat85
#配置tomcat环境变量
ENV CATALINA_HOME /usr/local/tomcat85
#配置工作目录
WORKDIR /usr/local/tomcat85
#指定端口是8080
EXPOSE 8080/tcp
CMD /usr/local/tomcat85/bin/catalina.sh run

构建镜像

[root@flannet tomcat]# docker build -t tomcat:v1 /tomcat/
[root@flannet tomcat]# docker run -itd --name tomcat -p 8080:8080 tomcat:v1

测试

docker_image03

8.使用Dockerfile构建MariaDB镜像(Centos7)

创建Dockerfile目录

[root@flannet tomcat]# mkdir /mariadb/

准备改数据库root密码脚本

[root@flannet ~]# vim /mariadb/docker-entrypoint.sh
#!/bin/bash

/usr/bin/mysqld_safe --skip-grant-tables && /usr/bin/mysql --socket=/var/lib/mysql/mysql.sock -uroot -e "set password for 'root'@'localhost' = PASSWORD('$MYSQL_ROOT_PASSWORD')"

exec "$@"

准备Dockerfile

[root@flannet ~]# vim /mariadb/Dockerfile
FROM centos:7
#安装国内源
RUN yum install -y wget && wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
#安装MariaDB
RUN  yum install -y mariadb-server
#配置永久挂载
VOLUME /var/lib/mysql
#拷贝脚本到指定路径
COPY docker-entrypoint.sh /usr/local/bin
#给予脚本执行权限
RUN chmod a+x /usr/local/bin/docker-entrypoint.sh
#执行脚本
ENTRYPOINT docker-entrypoint.sh
#容器创建的时候执行的操作
CMD /usr/bin/mysqld_safe

构建镜像

[root@flannet ~]# docker build -t mariadb:v1 /mariadb/

测试镜像

[root@flannet mariadb]# docker run -itd --name mariadb01 -e MYSQL_ROOT_PASSWORD=WWW.1.com  mariadb:v1
[root@flannet mariadb]# docker exec -it mariadb01 /bin/bash

[root@85ab03eb1d92 /]# mysql -uroot -pWWW.1.com
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 1
Server version: 5.5.68-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>