【容器应用系列教程】Docker镜像管理
一、关于镜像
1.镜像的基本概念
- 分层的文件系统
- 镜像是只读的
- 基于镜像创建容器时,镜像最上面会添加一个可写层,用户的所有操作都会存到这个可写层内
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
7.使用Dockerfle
构建Tomcat
镜像(基于Centos7)
准备Dockerfile
目录
[root@flannet ~]# mkdir /tomcat
下载jdk
和tomcat
[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
测试
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)]>