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官网
- Docker官网:https://www.docker.com
- Docker Hub官网(安装docker镜像的仓库):https://hub.docker.com
4 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 安装步骤
- CentOS安装Docker引擎,官方文档:https://docs.docker.com/engine/install/centos/
5.3.1 查看操作系统版本
- 查看操作系统版本,确定是CentOS 7或更高版本
# 查看CentOS的操作系统版本
# CentOS Linux release 7.9.2009 (Core)
cat /etc/redhat-release
5.3.2 卸载旧版本
- 如果安装了旧版本,先卸载它们以及关联的依赖项
旧版本的引擎包或依赖项:
docker
、docker-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的过程
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命令图
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
- 列说明
列 | 列说明 |
---|---|
TYPE | Images - 镜像 Containers - 容器 Local Volumes - 本地数据卷 |
TOTAL | 总数 |
ACTIVE | Images - 存在对应容器实例的镜像数量 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 等。
- 对于一个精简的 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
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