Docker镜像管理

Docker 镜像含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于创建并启动 docker 容器。

Docker 镜像含里面是一层层文件系统,叫做 Union FS(联合文件系统),联合文件系统,可以将几层目录挂载到一起,形成一个虚拟文件系统,虚拟文件系统的目录结构就像普通 linux 的目录结构一样,docker 通过这些文件再加上宿主机的内核提供了一个 linux 的虚拟环境。

每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker 镜像中每一层文件系统都是只读的。

构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样,当使用镜像的时候,我们只会看到一个完全的整体,不知道里面有几层也不需要知道里面有几层。

一个典型的 Linux 文件系统由 bootfs 和 rootfs 两部分组成,bootfs(boot file system) 主要包含 bootloader 和 kernel,bootloader 主要用于引导加载 kernel。

当 kernel 被加载到内存中后 bootfs 会被 umount 掉,rootfs (root file system) 包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc 等标准目录和文件

不同的 linux 发行版(如 ubuntu 和 CentOS ) 在 rootfs 这一层会有所区别。

但是对于 docker 镜像通常都比较小,官方提供的 centos 基础镜像在 200MB 左右,一些其他版本的镜像甚至只有几 MB,docker 镜像直接调用宿主机的内核,镜像中只提供 rootfs,也就是 只需要包括最基本的命令、工具和程序库就可以了,比如 alpine 镜像,在 5M 左右。

Docker常用命令

搜索镜像

在官方的 docker 仓库中搜索指定名称的 docker 镜像,也会有很多三方镜像。

docker search centos:7.2.1511 #带指定版本号
docker search centos #不带版本号默认 latest

下载镜像

命令格式:
docker pull 仓库服务器:端口/项目名称/镜像名称:tag(版本)号
下载完成的镜像比下载的大,因为下载完成后会解压

示例:

docker pull nginx

查看本地镜像

docker images

字段说明:
REPOSITORY #镜像所属的仓库名称
TAG #镜像版本号(标识符),默认为 latest
IMAGE ID #镜像唯一 ID 标示
CREATED #镜像创建时间
VIRTUAL SIZE #镜像的大小

镜像导出

可以将镜像从本地导出问为一个压缩文件,然后复制到其他服务器进行导入使用。

方法1:

docker save centos -o /opt/centos.tar.gz

方法2:

docker save centos > /opt/centos-1.tar.gz

查看镜像内容

tar xvf centos.tar.gz
cat manifest.json #包含了镜像的相关配置,配置文件、分层

分层为了方便文件的共用,即相同的文件可以共用

[{"Config":" 配置文件 .json","RepoTags":["docker.io/nginx:latest"],"Layers":["分层1/layer.tar","分层2/layer.tar","分层3/layer.tar"]}]

镜像导入

上传好文件之后

docker load < centos.tar.gz

删除镜像

删除指定 ID 的镜像,通过镜像启动容器的时候镜像不能被删除,除非将容器全部关闭
docker rmi 镜像 ID/镜像名称

示例:

docker rmi centos

获取运行参数帮助

docker daemon –help

删除容器

docker rm 容器 ID/容器名称
强制删除正在运行的容器
docker rm 容器 ID/容器名-f

启动和停止容器

docker start [容器ID]
docker stop[容器ID]

基础操作命令

命令格式

docker run [选项] [镜像名] [shell 命令] [参数]
docker run [参数选项] [镜像名称,必须在所有选项的后面] [/bin/echo ‘hello wold’] #单次执行,没有自定义容器名称

示例:

docker run centos /bin/echo 'hello wold' #启动的容器在执行完 shel 命令就退出了

从镜像启动一个容器

会直接进入到容器,并随机生成容器 ID 和名称

docker run -it docker.io/centos bash

退出容器不注销

按ctrl+p+q

显示正在运行的容器

docker ps
加-a显示所有容器
docker ps -a

删除正在运行的容器

先用docker ps找到需要删除的容器ID
docker rm -f 容器ID

随机映射端口

前台启动并随机映射本地端口到容器的 80

docker run -P docker.io/nginx

前台启动的会话窗口无法进行其他操作,除非退出,但是退出后容器也会退出,随机端口映射,其实是默认从 32768 开始

指定端口映射

本地端口 81 映射到容器 80 端口:

docker run -p 81:80 --name nginx-test-port1 nginx

本地 IP:本地 82 端口:容器 80 端口:

docker run -p 192.168.1.10:82:80 --name nginx-test-port2 docker.io/nginx

本地 IP:本地随机端口:容器端口:

docker run -p 192.168.1.10::80 --name nginx-test-port3 docker.io/nginx

本机 ip:本地端口:容器端口/协议,默认为 tcp 协议:

docker run -p 192.168.1.10:83:80/udp --name nginx-test-port4 docker.io/nginx

一次性映射多个端口+协议:

docker run -p 86:80/tcp -p 443:443/tcp -p 53:53/udp --name nginx-test-port5 docker.io/nginx

查看 Nginx 容器访问日志

docker logs nginx-test-port3 #一次查看
docker logs -f nginx-test-port3 #持续查看

查看容器已经映射的端口

docker port nginx-test-port5

自定义容器名称

docker run -it --name nginx-test nginx

后台启动容器

docker run -d -P --name nginx-test1 docker.io/nginx

创建并进入容器

docker run -ti --name test-centos2 docker.io/centos /bin/bash

退出后自动删除

docker run -it --rm --name nginx-delete-test docker.io/nginx

传递运行命令

容器需要有一个前台运行的进程才能保持容器的运行,通过传递运行参数是一
种方式,另外也可以在构建镜像的时候指定容器启动时运行的前台命令。

docker run -d centos /usr/bin/tail -f '/etc/hosts'

进入正在运行的容器

方法1:
使用 attach 命令
命令格式: docker attach 容器名
attach 类似于 vnc,操作会在各个容器界面显示,所有使用此方式进入容器的操作都是同步显示的且 exit 后容器将被关闭,且使用 exit 退出后容器关闭,不推荐使用,需要进入到有 shell 环境的容器。

示例:

运行一个容器
docker run -it centos bash

在另一个窗口进入容器
docker attach 73fdc5d5c3e5

方法2:
使用 exec 命令
执行单次命令与进入容器,不是很推荐此方式,虽然 exit 退出容器还在运行

示例:

docker exec -it centos-test/bin/bash

方法3:
使用 nsenter 命令
推荐使用此方式,nsenter 命令需要通过 PID 进入到容器内部,不过可以使用docker inspect 获取到容器的 PID

1.先安装 nsenter 命令

yum install util-linux

2.获取PID

docker inspect -f "{{.State.Pid}}" centos-test

3.使用 nsenter

nsenter -t 4855 -m -u -i -n -p

可以制作成脚本

vim docker-in.sh

#!/bin/bash
docker_in(){
  NAME_ID=$1
  PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID})
  nsenter -t ${PID} -m -u -i -n -p
}

测试脚本
./docker-in.sh centos-test

批量正常关闭正在运行的容器

docker stop $(docker ps -a -q)

批量强制关闭正在运行的容器

docker kill $(docker ps -a -q)

批量删除已退出容器

docker rm -f `docker ps -aq -f status=exited`

批量删除所有容器

docker rm -f $(docker ps -a -q)

指定容器 DNS

方法1:将 dns 地址配置在宿主机

方法2:将参数配置在 docker 启动脚本里面 –dns=1.1.1.1
示例:

docker run -it --rm --dns 8.8.8.8 centos bash



DockerFile制作镜像

DockerFile 可以说是一种可以被 Docker 程序解释的脚本,DockerFile 是由一条条的命令组成的,每条命令对应 linux 下面的一条命令,Docker 程序将这些DockerFile 指令再翻译成真正的 linux 命令,其有自己的书写方式和支持的命令,Docker 程序读取 DockerFile 并根据指令生成 Docker 镜像,相比手动制作镜像的方式,DockerFile 更能直观的展示镜像是怎么产生的,有了 DockerFile,当后期有额外的需求时,只要在之前的 DockerFile 添加或者修改响应的命令即可重新生成新的 Docke 镜像,避免了重复手动制作镜像的麻烦。

制作步骤示例

基于某个基础镜像之上重新制作,因此需要先有一个基础镜像,这里使用官方提供的 centos 镜像为基础制作编译nginx的镜像

注意:nginx要在容器中运行需要在配置中添加daemon off取消后台运行

1.下载镜像并初始化系统

docker pull centos

测试运行
docker run -it docker.io/centos /bin/bash

创建目录
cd /otp
mkdir dockerfile/nginx-test

2.编写Dockerfile文件
生成的镜像的时候会在执行命令的当前目录查找 Dockerfile 文件,所以名称不可写错,而且 D 必须大写
"#"为注释,等于 shell 脚本的中#
除了注释行之外的第一行,必须是 From xxx (xxx 是基础镜像)

Dockerfile文件介绍

注意:编写Dockerfile时应该把不容易变动的内容放在前面,经常需要变动的放在后面,打包的时候会从变动的地方开始打包,可以节约打包时间

第一行先定义基础镜像,后面的本地有效的镜像名,如果本地没有会从远程仓库下载,第一行很重要
From centos #centos是本地镜像名称

镜像维护者的信息
MAINTAINER test 123456@qq.com

其他可选参数
USER #指定该容器运行时的用户名和 UID,后续的 RUN 命令也会使用这面指定的用户执行

WORKDIR /a #指定工作目录
WORKDIR b #最终工作目录为/a/b

VOLUME ["/dir_1", "/dir_2" ..] #设置容器挂载主机目录
ENV name test #设置容器变量,常用于想容器内传递用户密码等

用RUN执行命令
RUN yum install -y vim wget tree nginx
RUN useradd test -s /sbin/nologin

解压压缩包
ADD nginx-1.10.3.tar.gz /usr/local/src/

向外开放的端口,多个端口用空格做间隔,启动容器时候-p 需要使用此端向外映射,如: -p 8081:80,则 80 就是这里的 80
EXPOSE 80 443

运行的命令,每个 Dockerfile 只能有一条,如果有多条则只有最后一条被执
CMD ["nginx"] #如果运行后台执行程序例如nginx需要在nginx.conf配置中取消后台运行
如果在从该镜像启动容器的时候也指定了命令,那么指定的命令会覆盖Dockerfile构建的镜像里面的 CMD 命令
即指定的命令优先级更高,Dockerfile 的优先级较低一些

编译nginx的Dockerfile

ADD nginx-1.20.0.tar.gz /app/source
  
RUN cd /app/source/nginx-1.20.0 && ./configure --prefix=/app/nginx \
--conf-path=/app/nginx/nginx.conf \
--error-log-path=/app/nginx/logs/error.log \
--http-log-path=/app/nginx/logs/access.log \
--pid-path=/app/nginx/run/nginx.pid \
--lock-path=/app/nginx/run/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_dav_module \
--with-http_stub_status_module \
--with-threads \
--with-file-aio && make -j 2 && make install && ln -s /app/nginx/sbin/nginx /usr/bin/nginx

RUN useradd -r -s /sbin/nologin nginx

COPY nginx.conf /app/nginx
ADD html.tar.gz /data/html #这里是提前打包好的网页代码

#设定时区
RUN rm-rf /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

EXPOSE 80 443

CMD ["nginx"]

nginx.conf内容

daemon off;
worker_processes  1;
error_log  /app/nginx/logs/error.log;
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"';
    access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    #gzip  on;
        #error_page  404              /404.html;
        error_page   500 502 503 504  /50x.html;

        server {
                listen       80;
                server_name  www.test.com;
                root   /data/html/;
                location / {
                        index  index.html index.htm index.php;
                }
        }
}

3.镜像构建
推荐使用打包脚本

build-cmd.sh

#!/bin/bash
TAG=$1
docker build -t nginx:$TAG .

此时/opt/dockerfile/nginx-test目录中的内容应该如下

.
├── build-cmd.sh
├── Dockerfile
├── html.tar.gz
├── index.html
├── nginx-1.20.0.tar.gz
└── nginx.conf

开始打包

bash build-cmd.sh test

查看镜像
docker images

查询结果
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
nginx        test      f7203f2a8a0d   1 minutes ago      576MB

在做实验中查看镜像时发现有很多none的镜像,可用命令批量删除

docker rmi -f `docker images | grep none | awk '{print $3}'`

4.尝试从镜像启动容器

docker run -d -p 80:80 text/nginx-1.10.3:v1