Docker 基础篇

1 Docker特点

  • Build, Ship and Run(搭建、运输、运行)

  • Build once,Run anywhere(一次搭建,到处运行)

  • 解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术

2 容器部署发展简史

互联网企业生产环境的应用部署所经历的过程,大致可分三个阶段:

  • 物理机部署
  • 虚拟机部署
  • 容器化部署

2.1 物理机部署

物理机部署

2.1.1 特点

一台服务器,部署多个应用进程。

2.1.2 痛点

资源共享问题:进程间资源抢占。如果某个进程耗用了100%的CPU资源,其他的进程就无法提供服务。又或者一个进程产生的日志把磁盘打满了,那所有的进程都会挂掉。

2.1.3 解决方式

进程间硬件资源隔离。

2.2 虚拟机部署

虚拟机部署

2.2.1 特点

虚拟机通过硬件虚拟化,即每台虚拟机事先从物理机分配好cpu核数,内存, 磁盘,每台虚拟机一般只部署一个应用。从而解决了进程间资源隔离的问题。

2.2.2 痛点

集群部署的情况下,软件的版本和配置文件容易碎片化:应用集群的虚拟机第一次安装时,由于操作系统镜像是一样的,所以刚开始,软件的版本和库依赖是统一的。但随着时间的推移,开源的软件(tomcat, jdk, nginx)需要逐步升级,于是运维同学开始批量升级集群的软件版本,批量升级可能有遗漏或升级失败。同时有些开发同学会自己登陆机器修改软件的版本或者配置,以满足自己的需求。长此以往,一个应用集群的虚拟机的软件版本和配置逐渐碎片化。当线上出现问题,需要排查到基础软件层面时,由于软件版本碎片化的问题,就会导致排查变得很棘手。

2.2.3 解决方式

容器技术

2.3 容器化部署

容器化部署

2.3.1 特点

容器技术不限于docker,但是docker目前最为流行,此处以docker为例。docker容器技术的核心之一在于镜像文件。

2.3.2 镜像文件

镜像文件:通俗的理解就是一个进程运行时依赖的软件文件的集装箱。
镜像文件的用处:应用集群部署时,每台机器首先会拉取指定版本的镜像文件。安装镜像后产生了docker容器。由于所有机器的镜像文件一样,容器的软件版本也一样。即使开发或运维中途修改了容器的软件版本,但是容器销毁时,软件的改动会随容器的销毁一起湮灭。当应用用已有的镜像文件重新部署时,生成的docker容器跟修改之前的容器完全一样。容器如果要升级软件版本,那就修改镜像文件。这样部署时集群内所有的机器重新拉取新的镜像,软件因此跟着一起升级。软件版本混乱的问题,到docker这里,也就得到了完美的解决。

2.3.3 一个小问题

  • 有了容器技术,生产环境为何还需要部署虚拟机?

因为虚拟机能做到硬件资源的彻底隔离,docker不行。

2.3.4 小总结

  • 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整的操作系统,在该系统上再运行所需的应用进程;

  • 容器内的应用进程直接运行于宿主的内核,容器没有自己的内核也没有进行硬件虚拟。因此要比传统虚拟机更为轻便,启动速度更快;

  • 每个容器之间相互隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。

3 Docker官网

4 Docker的基本组成

Docker的基本组成

4.1 镜像(image)

  • docker镜像(image)就是一个只读的模板,镜像可以用来创建docker容器,一个镜像可以创建很多容器。

  • 相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。

4.2 容器(container)

4.2.1 从面向对象角度理解

docker利用容器(container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是使用镜像创建的运行实例。

镜像是静态的定义,容器是镜像运行时的实体。

容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、停止、删除。每个容器都是相互隔离的,保证安全的平台。

4.2.2 从镜像容器角度理解

可以把容器看作是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

4.3 仓库(repository)

  • 仓库是集中存放镜像文件的场所。类似于存放jar包的maven仓库、存放git项目的github等等。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。

最大的公开仓库也是docker公司提供的官方仓库:Docker Hub,国内的公开仓库包括阿里云等。

5 Docker安装

5.1 注意事项

  • docker并非是一个通用的容器工具,它依赖于已存在并运行的Linux内核环境。

docker实质上是在已经运行的Linux下制造了一个隔离的文件环境,因此它的执行效率几乎等同于所部署的Linux主机。

因此,docker必须部署在Linux内核的系统上,如果其他系统想部署docker就必须安装一个虚拟Linux环境。

注:docker在Windows上依赖WSL(可以理解为一个Windows专用的Linux虚拟机)

5.2 前提条件

  • 目前,CentOS仅发行版本中的内核支持docker。

操作系统要求

1、CentOS 7或更高版本(存档或测试版本不支持)

2、必须启用CentOS Extras存储库。默认情况下,此存储库已启用,但如果已禁用,则需要 重新启用它。

3、建议使用存储驱动程序:overlay2

5.3 安装步骤

5.3.1 查看操作系统版本

  • 查看操作系统版本,确定是CentOS 7或更高版本
# 查看CentOS的操作系统版本
# CentOS Linux release 7.9.2009 (Core)
cat /etc/redhat-release

5.3.2 卸载旧版本

  • 如果安装了旧版本,先卸载它们以及关联的依赖项

旧版本的引擎包或依赖项:dockerdocker-engine

新版本的引擎包:docker-ce

sudo yum remove docker \
                docker-client \
                docker-client-latest \
                docker-common \
                docker-latest \
                docker-latest-logrotate \
                docker-logrotate \
                docker-engine
  • 上述操作只会删除docker本身,旧版本保存在/var/lib/docker/的内容,包括镜像、容器、卷和网络等会被保留。

5.3.3 安装GCC编译器相关

sudo yum -y install gcc
sudo yum -y install gcc-c++

5.3.4 设置stable镜像仓库

# 配置yum资源库
# 安装yum-config-manager
# yum-util提供yum-config-manager功能 
sudo yum install -y yum-utils

# 在yum资源库中添加docker资源库
# 官方地址(镜像在国外,下载比较慢,不推荐)
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 阿里云镜像(推荐)
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

5.3.5 更新yum软件包索引

# 重建软件包索引,建立缓存(可选操作,建议运行,据说后续安装会快一些)
yum makecache fast

5.3.6 安装Docker引擎

  • 默认安装最新版本
# docker-ce是Docker引擎,docker-ce-cli是客户端
# 默认安装的docker引擎、客户端都是最新版本
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 安装指定版本
# 在存储库中列出可用版本,然后选择安装
yum list docker-ce --showduplicates | sort -r

# 如下图,安装指定版本3:20.10.7-3.el7
# sudo yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io docker-compose-plugin
# VERSION_STRING:版本号,可用版本列表的第二列
sudo yum install docker-ce-17.09.0.ce docker-ce-cli-17.09.0.ce containerd.io docker-compose-plugin

请添加图片描述

5.3.7 启动Docker引擎

sudo systemctl start docker

# 启动后查看docker版本,可以看到Server: Docker Engine - Community(Docker守护进程)的版本号
docker version

请添加图片描述

5.3.8 运行hello-world测试

# 下载镜像hello-world:容器运行时,它会打印Hello from Docker!并退出
sudo docker run hello-world

请添加图片描述

5.3.9 卸载Docker步骤

1、关闭服务

systemctl stop docker

2、使用yum删除docker引擎

# 卸载 Docker 引擎、CLI、Containerd 和 Docker Compose 包
sudo yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin

3、删除镜像、容器、卷、自定义配置等文件

# 手动删除删除镜像、容器、卷、自定义配置等文件
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

6 配置镜像加速器(以阿里云为例)

6.1 镜像加速器的概念

由于docker的镜像需要从仓库拉取,这个仓库(dockerHub)在国内下载很慢,所以阿里云做了一个镜像加速功能,相当于把dockerHub的仓库拷贝了一份到国内,让国内用户方便下载。

6.2 配置步骤

  • 登录阿里云,进入 控制台 -> 容器镜像服务 -> 镜像工具 -> 镜像加速器
  • 里面提供了一个加速器地址:https://xxxxxxxx.mirror.aliyuncs.com
  • 将该地址配置到docker中:
# 通过修改daemon配置文件 /etc/docker/daemon.json 来使用加速器(初次使用是没有该文件的,直接新建文件即可)
vi /etc/docker/daemon.json

# daemon.json 文件内容
{
  "registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"]  
}
  • 重载 daemon 程序刷新配置,重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker

7 docker run的过程

开始
Docker在本机中寻找该镜像
本机是否有该镜像
以该镜像为模板生产容器实例运行
去Docker Hub上查找该镜像
Hub能否找到该镜像
下载该镜像到本地
报错: 查不到该镜像
以该镜像为模板生成容器实例运行

8 为什么Docker会比VM虚拟机快

8.1 docker有着比虚拟机更少的抽象层

由于docker不需要实现硬件资源虚拟化,运行在docker容器上的程序都是直接使用实际物理机的硬件资源。因此在CPU、内存利用率上docker的效率有明显优势。

8.2 docker利用的是宿主机的内核,而不需要加载操作系统内核

当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。避免了引导、寻址、加载操作系统等比较费时费资源的过程。

当新建一个虚拟机时,虚拟机软件需要加载OS,这个过程耗时是分钟级的;而docker由于直接利用宿主机的操作系统,新建一个docker容器耗时只需几秒钟。

8.3 虚拟机与Docker容器对比

Docker容器虚拟机(VM)
操作系统与宿主机共享OS宿主机OS上运行虚拟机OS
存储大小镜像小,便于存储和传输镜像庞大
运行性能几乎无额外性能损失操作系统额外的CPU、内存消耗
移植性轻便、灵活,适应于Linux笨重,与虚拟化技术耦合度高
硬件亲和性面向软件开发者面向硬件运维者
部署速度快速,秒级较慢,10s以上

9 Docker常用命令

9.1 Docker命令图

Docker命令图

9.2 帮助、启动类命令

# 启动docker
systemctl start docker
# 停止docker
systemctl stop docker
# 重启docker
systemctl restart docker
# 查看docker状态
systemctl status docker
# 设置开机启动
systemctl enable docker
# 查看docker版本信息
docker version
# 查看docker概要信息
docker info
# 查看docker总体帮助文档
docker --help
# 查看docker命令帮助文档
# 例:docker run --help
docker [COMMAND] --help

9.3 镜像命令

9.3.1 查看本地镜像列表

# 查看本地镜像列表
docker images
# 列出本地镜像中 REPOSITORY 为 ubuntu 的镜像列表
docker images ubuntu
# 列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层)
docker images -a
# 只显示镜像ID
docker images -q
# 显示完整的镜像描述
docker images --no-trunc


# 同一仓库源可以有多个 TAG 版本,我们使用 REPOSITORY:TAG 来定义不同的镜像
# 如果不指定镜像的版本标签,默认使用最新版本。例如使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像

请添加图片描述

  • 列说明
列说明
REPOSITORY镜像的仓库源
TAG镜像的版本标签
IMAGE ID镜像ID
CREATED镜像创建时间
SIZE镜像大小

9.3.2 查找镜像

# 查找所有包含 ubuntu 的镜像
docker search ubuntu
# 查找所有包含 ubuntu,且 stars 大于10的镜像
docker search -f stars=10 ubuntu
# 只列出前5个镜像
docker search --limit 5 ubuntu

请添加图片描述

  • 列说明
列说明
NAME镜像名称
DESCRIPTION镜像描述
OFFICIAL是否 docker 官方发布
STARS点赞数
AUTOMATED是否是自动构建的

9.3.3 拉取镜像

# docker pull 镜像名称[:tag]
# 不加tag时,默认下载最新的镜像(即tag为latest)
docker pull ubuntu

9.3.4 删除镜像

# docker rmi 镜像名称
docker rmi ubuntu
# docker rmi (IMAGE ID)
docker rmi ba6acccedd29
# 删除多个镜像,使用空格分隔:docker rmi 镜像1 镜像2 镜像3
docker rmi ubuntu redis
# 强制删除镜像(如果没有删除对应的容器,删除镜像会报错,此时是可以使用-f强制删除的)
docker rmi -f ubuntu
# 删除全部镜像
docker rmi -f $(docker images -qa)

9.3.5 虚悬镜像

  • 概念:仓库名、标签都是<none>的镜像,俗称虚悬镜像(dangling image)
  • 产生原因:这些镜像原本是有镜像名和标签的,随着镜像的维护,发布了新镜像后,由于新旧镜像同名(仓库名、标签均相同),旧镜像名称被取消,从而出现仓库名、标签均为的镜像。这类无标签镜像被称为虚悬镜像
# 查看所有的虚悬镜像
docker images -f dangling=true
# 一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的
# 删除虚悬镜像
docker rmi $(docker images -q -f dangling=true)

请添加图片描述

9.3.6 打包镜像为 tar 包

docker save -o redis.tar redis:latest

在这里插入图片描述

9.3.7 重新加载 tar 文件为镜像

docker load -i redis.tar

在这里插入图片描述

9.4 容器命令

9.4.1 新建启动容器

# 新建+启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

启动交互式容器

# 前台交互式启动
# 使用 ubuntu 镜像以交互模式启动一个容器。在容器内执行 /bin/bash(或者bash) 命令
docker run --it ubuntu /bin/bash
docker run --it ubuntu bash
  • 退出交互模式

方式一:在交互shell中输入 exit 即可退回宿主机(这种方式退出后,容器会停止运行)

方式二:使用快捷键 CTRL + P + Q (这种方式退出后容器仍然在运行)

启动守护式容器

# 后台守护式启动
# 大部分情况下,我们的docker服务是在后台运行的,可以通过 -d 指定容器的后台运行模式
# docker run -d 容器ID或容器名称
docker run -d redis

# docker容器后台运行,必须有一个前台进程,这个是docker的机制
# 容器运行的命令如果不是那些一直挂起的命令(如:top、tail等),这样的容器在后台启动后会立即自杀(因为它觉得没事可做了),例如:
docker run -d ubuntu
  • OPTIONS说明

--name:为容器指定一个名称(不指定的话系统会随机生成一个名称)
-d:后台运行容器并返回容器ID,也即启动守护式容器
-i:以交互模式(interactive)运行容器,通常与-t同时使用
-t:为容器重新分配一个伪输入终端(tty),通常与-i同时使用。也即启动交互式容器(前台有伪终端,等待交互)
-e:为容器添加环境变量
-P:随机端口映射。将容器内暴露的所有端口映射到宿主机随机端口
-p:指定端口映射

  • -p参数说明
参数说明举例
-p hostPort:containerPort端口映射-p 8080:80
-p ip:hostPort:containerPort配置监听地址-p 192.0.0.1:8080:80
-p ip::containerPort随机分配端口-p 192.0.0.1::80
-p hostPort1:containerPort1 -p hostPort2:containerPort2指定多个端口映射-p 6379:6379 -p 3306:3306

9.4.2 列出正在运行的容器

# docker ps [OPTIONS]
# 列出当前所有正在运行的容器
docker ps
# 列出当前所有正在运行的容器+历史上运行过的容器
docker ps -a
# 列出当前所有正在运行的容器+历史上运行过的容器的前2条记录
docker ps -n 2
# 列出当前所有正在运行的容器的容器编号
docker ps -q
  • OPTIONS说明

-a:列出当前所有正在运行的容器+历史上运行过的容器
-l:显示最新创建的容器
-n (num):显示最近创建的前num个容器
-q:只显示容器编号

9.4.3 容器其他启动停止命令

# 启动已经停止的容器
# docker start 容器ID或容器名称
docker start 9e7190eae5bd

# 重启容器
# docker restart 容器ID或容器名称
docker restart redis

# 停止容器
# docker stop 容器ID或容器名称
docker stop 9e7190eae5bd

# 强制停止容器
# docker kill 容器ID或容器名称
docker kill 9e7190eae5bd

# 删除已停止的容器
# docker rm 容器ID或容器名称
docker rm 9e7190eae5bd
# 强制删除正在运行的容器
# docker rm -f 容器ID或容器名称
docker rm -f 9e7190eae5bd
# 一次删除所有容器实例(谨慎操作)
docker rm -f $(docker ps -a -q)
docker ps -a -q | xargs docker rm -f

9.4.4 查看容器日志

# docker logs [OPTIONS] 容器ID或容器名称
docker logs 9e7190eae5bd
# 跟踪日志输出
docker logs -f 9e7190eae5bd
# 跟踪日志输出(带时间戳)
docker logs -tf 9e7190eae5bd
# 显示最后5行日志
docker logs -n 5 9e7190eae5bd
docker logs --tail 5 9e7190eae5bd

# 例
# 新建容器并以后台方式启动,执行每5秒打印日志的命令
# 注:sh -c 命令,它可以让 bash 将一个字串作为完整的命令来执行
docker run -d ubuntu /bin/sh -c "while true;do echo hi;sleep 5;done"
# 跟踪日志输出(-f和-tf的区别)
docker logs -f --tail 5 cd0a7ba8d0b5
docker logs -tf --tail 5 cd0a7ba8d0b5

请添加图片描述

9.4.5 查看容器内运行的进程

# docker top 容器ID或容器名称
docker top 9e7190eae5bd

9.4.6 查看容器内部细节(元数据)

# docker inspect 容器ID或容器名称
docker inspect 9e7190eae5bd

9.4.7 进入正在运行的容器并以命令行交互

# 第一种方式
# docker exec -it 容器ID bashShell
docker exec -it e863a5ed312a /bin/bash 

# 第二种方式
# docker attach 容器ID
# 如果有多个终端,都对同一个容器执行了 docker attach,就会出现类似投屏显示的效果。一个终端中输入输出的内容,在其他终端上也会同步的显示
docker attach e863a5ed312a
  • 上述两种方式的区别

exec 是在容器中打开新的终端,并且可以启动新的进程,此时用 exit 退出,不会导致容器的停止。

attach 直接进入容器启动命令的终端,不会启动新的进程,此时用 exit 退出,会导致容器的停止。

  • 推荐使用 docker exec 命令,因为退出容器终端,不会导致容器的停止

以redis为例(进入 redis 服务)

  • 一般先用 -d 后台启动程序,再用 exec 进入对应容器实例
# 方式一
# 先进入容器交互 shell
docker exec -it 7bba30997546 /bin/bash
# 再运行 redis-cli 进入 redis 服务
redis-cli

请添加图片描述

# 方式二
# 直接以命令 redis-cli 进入 redis 服务
docker exec -it 7bba30997546 redis-cli

请添加图片描述

9.4.8 容器与宿主机的文件拷贝

容器文件拷贝到宿主机

# docker cp 容器ID:容器内路径 宿主机路径
docker cp 7d13af0831da:/tmp/test.txt /root/test/

宿主机文件拷贝到容器

# docker cp 宿主机路径 容器ID:容器内路径
docker cp /root/test/test2.txt 7d13af0831da:/tmp/

请添加图片描述

9.4.9 导入和导出容器

export:导出容器的内容流作为一个tar归档文件(对应 import 命令)

import:从tar归档文件中创建一个新的文件系统再导入为镜像(对应 export 命令)

# 导出
# docker export 容器ID > 文件名.tar
docker export 7d13af0831da > test3.tar

# 导入
# cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
cat test3.tar | docker import - zhoulx/test3:1.0.1

请添加图片描述

9.5 Docker 磁盘空间相关命令

9.5.1 查看镜像、容器、数据卷所占空间

# 查看镜像(Images)、容器(Containers)、本地数据卷(Local Volumes)的空间占用情况
docker system df
# 通过-v参数进一步查看空间占用细节
docker system df -v

请添加图片描述

  • 列说明
列说明
TYPEImages - 镜像
Containers - 容器
Local Volumes - 本地数据卷
TOTAL总数
ACTIVEImages - 存在对应容器实例的镜像数量
Containers - 活跃的容器数量
Local Volumes - 被容器关联引用的卷的数量
SIZE占用空间大小
RECLAIMABLE可清理的空间

请添加图片描述

  • Image space usage 列说明
列说明
SHARED SIZE指的是当前镜像与另一个镜像的共享空间大小(例如图中的 myubuntu 是在 ubuntu 镜像基础上制作的,他们的共享数据就是 ubuntu 镜像的大小)
UNIQUE SIZE仅由当前镜像使用的空间大小
CONTAINERS当前镜像对应容器实例的数量
  • Local Volumes space usage 列说明
列说明
LINKS关联引用该卷的容器数量

9.5.2 清理磁盘空间

自动清理

# 清理磁盘,删除关闭的容器、无用的网络,以及虚悬镜像
docker system prune
# 更彻底地清理磁盘,会将没有容器使用的Docker镜像也一起删掉
docker system prune -a
# 忽略告警询问,直接删除
docker system prune -f

手动清理

  • 镜像清理
# 删除所有虚悬镜像,不会删除未使用的镜像
docker rmi $(docker images -q -f dangling=true)
# 删除所有未使用镜像
# 该命令轮询到在使用的镜像时,会有"container xxxx is using its referenced image xxxx"的报错信息,所以不会被删除
docker rmi $(docker images -q)
  • 容器清理
# 对于已停止或其它异常状态的容器,可以结合 -f 或 --filter 筛选器来处理
# rm -v 删除与该容器关联的匿名卷
# 删除所有已退出的容器
docker rm -v $(docker ps -aq -f status=exited)
# 删除所有状态为 dead 的容器
docker rm -v $(docker ps -aq -f status=dead)
  • 卷清理
# 删除所有未使用的本地卷
docker volume prune
# 删除所有未被任何容器关联引用的卷
docker volume rm $(docker volume ls -qf dangling=true)

10 Docker镜像

  • 概念:是一种轻量级、可执行的独立软件包,包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。

10.1 UnionFS(联合文件系统)

  • UnionFS,是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite serveral directories into a single virtual filesystem)

  • UnionFS 是 Docker 镜像的基础。镜像可以通过分层来进行集成,基于基础镜像可以制作具体的应用镜像。

  • 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

10.2 bootfs 和 rootfs

10.2.1 bootfs(boot file system)

bootfs 主要包含 bootloader(boot加载器)和 kernel(内核),bootloader 主要是引导加载 kernel,Linux 刚启动时会加载 bootfs。

在 Docker 镜像的最底层是 bootfs。这一层与我们典型的 Linux/Unix 系统是一样的。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已经由 bootfs 转交给内核,此时系统也会卸载 bootfs。

10.2.2 rootfs(root file system)

在 bootfs 之上,包含的就是典型 Linux 系统中的 /dev/proc/bin/etc 等标准目录和文件。rootfs 就是各种不同的操作系统发行版,比如 Ubuntu、CentOS 等。

docker镜像底层

  • 对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接使用宿主机的 Kernel,自己只需要提供 rootfs 就可以。

10.3 Docker 镜像分层

  • 镜像分层结构最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
# 查看镜像分层
# docker inspect 镜像名:镜像标签
docker inspect redis:latest

# 运行命令输出的是个 json,其中的 RootFS 就指示了分层信息
"RootFS": {
	"Type": "layers",
	"Layers": [
		"sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
		"sha256:9b24afeb7c2f21e50a686ead025823cd2c6e9730c013ca77ad5f115c079b57cb",
        "sha256:4b8e2801e0f956a4220c32e2c8b0a590e6f9bd2420ec65453685246b82766ea1",
        "sha256:529cdb636f61e95ab91a62a51526a84fd7314d6aab0d414040796150b4522372",
        "sha256:9975392591f2777d6bf4d9919ad1b2c9afa12f9a9b4d260f45025ec3cc9b18ed",
        "sha256:8e5669d8329116b8444b9bbb1663dda568ede12d3dbcce950199b582f6e94952"
	]
}
  • 容器层

当容器启动时,一个新的可写层将被加载到镜像的顶部,这一层通常被称为容器层,容器层之下都叫镜像层

只有容器层是可写的,容器层下面的所有镜像层都是只读的。

所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。

容器层

10.4 提交镜像

  • docker commit 提交容器副本使之成为一个新的镜像
# docker commit -m="提交的描述信息" -a="作者" 容器ID 创建的目标镜像名:[标签名]
docker commit -m="add vim" -a="zhoulx" 94f960de04a1 zhoulx/myubuntu:1.0.1

# 例:从 hub 上下载的 ubuntu 镜像是不包含 vim 工具的,我们自己安装并生成新的包含 vim 工具的 ubuntu 镜像
# 先以前台交互模式启动 ubuntu
[root@zhoulx ~]# docker run -it ubuntu /bin/bash
# 先更新 ubuntu 的包管理工具
root@94f960de04a1:~# apt-get update
# 安装 vim
root@94f960de04a1:~# apt-get -y install vim
# 回到容器外执行命令,commit 新镜像
[root@zhoulx ~]# docker commit -m="add vim" -a="zhoulx" 94f960de04a1 zhoulx/myubuntu:1.0.1

请添加图片描述

11 Registry 搭建 docker 私有仓库

11.1 拉取镜像 Docker Registry

# Docker Registry 是官方提供的工具,用于构建私有镜像仓库。
# Docker Registry 是 Docker Hub 提供的一个镜像,可以直接拉取运行。
docker pull registry

11.2 启动 Docker Registry

# -v 宿主机绝对路径:容器路径:将宿主机绝对路径与容器路径作映射,持久化数据
# --privileged=true:扩大容器的权限解决挂载目录没有权限的问题
docker run -d -p 5000:5000 -v /root/myregistry:/tmp/registry --privileged=true registry

11.3 curl查看私服中的所有镜像

# 查看私服中的所有镜像
# Registry 会返回json格式的所有镜像目录
curl http://192.168.198.131:5000/v2/_catalog

请添加图片描述

11.4 修改配置文件使之支持 http

  • docker 默认不允许 http 方式推送镜像,通过下面的配置来取消这个限制

  • 修改 /etc/docker/daemon.json,添加 insecure-registries 允许 http

{
  "registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"],
  "insecure-registries": ["192.168.198.131:5000"]
}
  • 据说新版本的 docker 会立即生效,没生效的话就重启一下 docker
# 重载 daemon 程序刷新配置,重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker

11.5 推送镜像到私仓

11.5.1 新镜像修改为符合私服规范的 Tag

# 添加一个对应私仓 tag 的镜像
docker tag zhoulx/myubuntu:1.0.1 192.168.198.131:5000/myubuntu:1.0.2

添加一个对应私仓 tag 的镜像

11.5.2 push 镜像到私仓

# 添加一个对应私仓 tag 的镜像
docker push 192.168.198.131:5000/myubuntu:1.0.2

11.5.3 查看私仓中镜像目录验证

# Registry 会返回json格式的所有镜像目录
curl http://192.168.198.131:5000/v2/_catalog

请添加图片描述

11.5.4 拉取镜像验证

# 拉取镜像验证
docker pull 192.168.198.131:5000/myubuntu:1.0.2

请添加图片描述

12 Docker 容器数据卷

12.1 挂载主机目录

# -v 宿主机绝对路径:容器路径:将宿主机绝对路径与容器路径作映射,持久化数据
# --privileged=true:扩大容器的权限解决挂载目录没有权限的问题
# docker run -it --privileged=true -v /宿主机绝对路径:/容器路径 镜像名
docker run -it --privileged=true -v /root/test:/tmp/test --name=ubuntu_test ubuntu
# 挂载多个目录
docker run -it --privileged=true -v /root/test:/tmp/test -v /root/test2:/tmp/test2 --name=ubuntu_test ubuntu
  • docker 挂载主机目录访问时如果出现cannot open directory: Permission denied

解决方法:在挂载目录后多加一个参数:--privileged=true

原因:目录挂载被 CentOS7 的安全模块默认视为不安全的行为,在 SELinux 里面挂载目录被禁止了。我们一般使用 --privileged=true 命令,扩大容器的权限。(使用该参数,容器内的 root 拥有真正的 root 权限,否则容器内的 root 只是外部的一个普通用户权限)

12.2 数据卷的概念及用处

将 docker 容器内的数据保存进宿主机的磁盘中(将宿主机绝对路径与容器路径作映射,完成容器内的数据备份+持久化到宿主机目录)

12.3 为什么使用数据卷

我们对数据的要求是希望持久化的。Docker 容器产生的数据,如果不进行备份,那么当容器实例被删除后,容器内的数据自然也就消失了。为了能保存数据在 docker 中我们使用卷。

12.4 数据卷的特点

  • 数据卷可在容器之间共享或重用数据
  • 数据卷中的更改可以直接实时生效
  • 数据卷中的更改不会包含在镜像中
  • 数据卷的生命周期一直持续到没有容器使用它为止

12.5 查看容器的数据卷挂载信息

# 查看容器的数据卷挂载信息
# docker inspect 容器ID
docker inspect fc2c4fbc6442

# 运行命令输出的是个 json,其中的 Mounts 就指示了挂载信息
"Mounts": [
    {
        "Type": "bind",
        "Source": "/root/test",
        "Destination": "/tmp/test",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    },
    {
        "Type": "bind",
        "Source": "/root/test2",
        "Destination": "/tmp/test2",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
]

12.6 添加数据卷的读写规则

# rw(可读可写,默认值)和 ro(read-only,只读)
docker run -it --privileged=true -v /root/test:/tmp/test --name=ubuntu_test ubuntu
# 默认容器对数据卷可读可写,等同于
docker run -it --privileged=true -v /root/test:/tmp/test:rw --name=ubuntu_test ubuntu
# 限制容器内对数据卷只读
docker run -it --privileged=true -v /root/test:/tmp/test:ro --name=ubuntu_test ubuntu

请添加图片描述

12.7 卷的继承和共享

# 容器1完成与宿主机的映射
docker run -it --privileged=true -v /root/test:/tmp/test:rw --name=ubuntu_test ubuntu

# 容器2继承容器1的卷规则
# docker run -it --privileged=true --volumes-from 父类容器名称 --name=ubuntu_test2 ubuntu
docker run -it --privileged=true --volumes-from ubuntu_test --name=ubuntu_test2 ubuntu
  • 注:上述例子容器2继承的是容器1与宿主机的数据卷映射规则,相当于容器1、容器2、宿主机都能操作同一个共享文件目录。此时停掉容器2也不会影响容器1与宿主机的数据卷映射。

13 Docker常规安装

13.1 常规安装步骤

13.1.1 搜索镜像

docker search 镜像名称

13.1.2 拉取镜像

docker pull 镜像名称:镜像标签

13.1.3 查看镜像

docker images 镜像名称

13.1.4 启动镜像

# -p 主机端口:容器端口:指定服务端口的映射
# -P:随机分配端口
# -i:启动前台交互式容器,通常与-t一起使用
# -t:为容器重新分配一个伪输入终端(tty),通常与-i一起使用
# -d:启动后台守护式容器
# --name:指定容器名称
docker run -d  -p 主机端口:容器端口 --name 容器名称 镜像名称:镜像标签

13.1.5 查看容器是否成功运行

docker ps

13.1.6 停止容器

docker stop 容器ID或容器名称

13.1.7 移除容器

docker rm 容器ID或容器名称

13.2 Docker 安装 tomcat

# 搜索tomcat镜像
docker search tomcat
# 拉取tomcat镜像
docker pull tomcat
# 查看镜像是否成功拉取
docker images tomcat
# 使用tomcat镜像创建启动容器
docker run -d -p 8080:8080 --name mytomcat tomcat
# 查看容器是否成功运行
docker ps 

注:tomcat新版本(10.0.14)启动容器后,访问首页tomcat时会报404

  • 原因:tomcat新版本默认webapps文件夹下是空的。
  • 解决方法1:需要先将/usr/local/tomcat下的webapps删掉,将webapps.dist重命名为webapps,才能正常访问tomcat首页。
# 进入容器
[root@zhoulx ~]# docker exec -it 016b2715a390 /bin/bash

# 容器内操作
root@016b2715a390:/usr/local/tomcat# rm -rf webapps
root@016b2715a390:/usr/local/tomcat# mv webapps.dist webapps
  • 解决方法2:使用旧版本的tomcat
# 拉取旧版本tomcat镜像(8.0.53版本)
docker pull billygoo/tomcat8-jdk8
# 创建启动容器
docker run -d -p 8080:8080 --name mytomcat2 billygoo/tomcat8-jdk8

13.3 Docker 安装 mysql

13.3.1 简单安装

# 拉取mysql 5.7的镜像
docker pull mysql:5.7
# 查看镜像是否成功拉取
docker images mysql:5.7
# 使用mysql 5.7镜像创建启动容器
# MYSQL_ROOT_PASSWORD:mysql的root账户密码
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
# 查看容器是否成功运行
docker ps 

# 进入容器
[root@zhoulx ~]# docker exec -it 5d6a618efa87 /bin/bash
# 进入mysql
root@5d6a618efa87:/# mysql -uroot -p

上述安装方式存在的问题

1、插入中文数据报错:Incorrect string value

  • 报错原因:docker默认的字符集的问题
-- 查看数据库字符集
show variables like 'character%';

-- 返回的字符集中,character_set_database、character_set_server等都为latin1字符集,所以插入中文会报错

请添加图片描述

2、没有配置容器卷映射

  • 启动容器时没有配置容器卷映射,当容器意外被删时,数据全部丢失且无法找回

13.3.2 实际应用安装方式

1、创建启动容器,配置数据卷映射

docker run -d -p 3306:3306 \
           --privileged=true \
           -v /app/mysql/log:/var/log/mysql \
           -v /app/mysql/data:/var/lib/mysql \
           -v /app/mysql/conf:/etc/mysql/conf.d \
           -e MYSQL_ROOT_PASSWORD=root \
           --name mysql2 \
           mysql:5.7

2、新建配置文件 my.cnf

# 进入配置文件目录
cd /app/mysql/conf
# 新建 my.cnf
vi my.cnf
  • my.cnf 内容
# 不要写错,写错的话会导致重启不了mysql
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8

3、重启 mysql 容器实例

# 重启 mysql
docker restart mysql2
# 查看容器是否成功运行
docker ps 

4、进入 mysql 查看字符编码

# 进入容器
[root@zhoulx ~]# docker exec -it mysql2 /bin/bash

# 进入mysql
root@5d6a618efa87:/# mysql -uroot -p

# 查看数据库字符集
mysql> show variables like 'character%';

请添加图片描述

5、容器意外被删时,重新启动容器实例即可

docker rm -f mysql2
# 重新运行启动容器实例
docker run -d -p 3306:3306 \
           --privileged=true \
           -v /app/mysql/log:/var/log/mysql \
           -v /app/mysql/data:/var/lib/mysql \
           -v /app/mysql/conf:/etc/mysql/conf.d \
           -e MYSQL_ROOT_PASSWORD=root \
           --name mysql2 \
           mysql:5.7

13.4 Docker 安装 redis

13.4.1 简单安装

# 拉取redis 6.0.8的镜像
docker pull redis:6.0.8
# 查看镜像是否成功拉取
docker images redis:6.0.8
# 创建启动容器
docker run -d -p 6379:6379 redis:6.0.8

上述安装方式同样存在问题

1、没有配置容器卷映射,当容器被删除时数据随之丢失,无法恢复。

2、配置文件redis.conf做一些特殊的配置要求

13.4.2 实际应用安装方式

1、新建redis目录存放redis.conf

# 递归创建redis文件夹
mkdir -p /app/redis
# 拷贝一份redis.conf到/app/redis目录下(准备一份redis的默认配置文件即可)

2、编辑redis.conf

vim /app/redis/redis.conf

# 开启redis验密(默认没有设置密码)
requirepass 123456

# 允许redis外地连接,需要注释掉绑定的IP(默认只允许本地访问)
# bind 127.0.0.1

# 注释掉daemonize yes,或者配置成 daemonize no。因为该配置和 docker run 中的 -d 参数冲突,会导致容器一直启动失败
daemonize no

# 开启redis数据持久化
appendonly yes

# 关闭保护模式
protected-mode no
# 开启保护模式时,如果想让外地连接redis,有两种方式:
# (1)通过bind绑定服务器IP
# (2)通过requirepass设置密码参数连接(推荐使用)

3、创建启动容器,配置数据卷映射,读取指定配置文件

docker run -d -p 6379:6379 \
           --privileged=true \
           -v /app/redis/redis.conf:/etc/redis/redis.conf \
           -v /app/redis/data:/data \
           --name redis \
           redis:6.0.8 \
           redis-server /etc/redis/redis.conf
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_秋牧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值