Docker 基础篇 1、Docker简介 是什么 问题:为什么会有docker出现 假定您在开发一个尚硅谷的谷粒商城,您使用的是一台笔记本电脑而且您的开发环境具有特定的配置 。其他开发人员身处的环境配置也各有不同 。您正在开发的应用依赖于您当前的配置且还要依赖于某些配置文件。此外,您的企业还拥有标准化的测试和生产环境 ,且具有自身的配置和一系列支持文件。您希望尽可能多在本地模拟这些环境而不产生重新创建服务器环境的开销 。请问?您要如何确保应用能够在这些环境中运行和通过质量检测?并且在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复?
答案就是使用容器。Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案——-系统平滑移植,容器虚拟化技术。
环境配置相当麻烦,换一台机器,就要重来一次,费力费时 。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。
docker理念 Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次镜像,处处运行”。
Linux容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。将应用打成镜像,通过镜像成为运行在Docker容器上面的实例,而 Docker容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。
现在我们的VMware就类似一个docker,centos7.iso就类似于一份镜像文件。
总结 以前是搬家,现在整个楼搬过去。类似于centos7.iso,镜像文件保证了环境迁移的一致。
解决运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
容器与虚拟机比较 容器发展简史
之前Spring容器,放的是Bean,
现在Docker放什么 用户数据库 队列 动态数据源 静态网站资源等等
传统虚拟机技术 虚拟机(virtual machine)就是带环境安装的一种解决方案 。 它可以在一种操作系统里面运行另一种操作系统,比如在Windows10系统里面运行Linux系统CentOS7。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。 Win10 VMWare Centos7 各种cpu、内存网络额配置+各种软件 虚拟机实例 虚拟出各种硬件,在虚拟机上安装从操作系统。
虚拟机的缺点: 1 资源占用多 2 冗余步骤多 3 启动慢
容器化虚拟化技术 如果可以复用一个centos7,然后跑三个服务。
由于前面虚拟机存在某些缺点,Linux发展出了另一种虚拟化技术: Linux容器(Linux Containers,缩写为 LXC),类似spring容器放bean,然后复用spring。 Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。
Linux 容器不是模拟一个完整的操作系统而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。
对比 比较了 Docker 和传统虚拟化方式的不同之处:传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。 * 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
能干嘛 一次构建随处运行,更快速的应用交付和部署,交个你镜像文件就行了。
更便捷的升级和扩缩容
更简单的系统运维
更高效的计算资源利用
去哪下 官网 docker官网:http://www.docker.com
仓库 Docker Hub官网:https://hub.docker.com 安装docker镜像的网站
2、Docker安装 前提
CentOS Docker 安装
前提条件 目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7 (64-bit)上, 要求系统为64位、Linux系统内核版本为 3.8以上,这里选用Centos7.x
查看自己的内核 uname命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。
1 2 cat /etc/redhat-release uname -r
Docker的基本组成 镜像 image Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。 它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。 相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
容器 container 1 从面向对象角度 Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台
2 从镜像容器角度 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库 repository 仓库(Repository)是集中存放镜像文件 的场所。
类似于 Maven仓库,存放各种jar包的地方; github仓库,存放各种git项目的地方; Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。 最大的公开仓库是 Docker Hub(https://hub.docker.com/), 存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等
小总结 1 2 3 4 java Book b1 = new Book(); docker Redis r1 = docker run镜像
需要正确的理解仓库/镜像/容器这几个概念: Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
image文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
镜像文件 * image 文件生成的容器实例,本身也是一个文件,称为镜像文件。 容器实例…
Docker工作原理理解基础版
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们前面说到的集装箱。可以对比mysql演示对比讲解
整体架构及底层通信原理简述
Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker 的运行的基本流程为
1、用户使用Docker Client 也就是命令与Docker Daemon守护进程进行通信,并发送请求给后者
2、Docker Daemon作为Docker架构中的主题部分,首先提供Docker Server 的功能使其可以接受Docker Client的请求
3、Docker Engine 执行Docekr内部的一系列工作,每一项工作都是以一个Job的形式的存在。
4、Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载进项,并通过镜像管理驱动 Grap driver将下载镜像以Graph的形式存储。
5、当需要为Docker创建网络环境时,通过网络管理驱动Network driver创建并配置Docker创建并配置Docker容器网络环境
6、当需要限制Docker容器运行资源或执行用户指令等操作时,则通过Exec driver来完成
7、Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
Centos7安装Docker 1、确定版本是centos7以上
2、卸载旧版本 1 2 3 4 5 6 7 8 sudo dnf remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
3、yum安装gcc相关 1 2 3 4 yum -y install gcc yum -y install gcc-c++ 或者一条 yum -y install gcc gcc-c++
4、安装需要的软件包 1 yum install -y yum-utils
5、设置stable镜像仓库 1 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
6、更新yum软件包索引
7、安装docker ce 1 yum -y install docker-ce docker-ce-cli containerd.io
8、启动docker
9、测试
10、卸载 1 2 3 4 systemctl stop docker yum remove docker-ce docker-ce-cli containerd.io rm -rf /var/lib/docker rm -rf /var/lib/containerd
阿里云镜像加速 网站 1 https://promotion.aliyun.com/ntms/act/kubernetes.html
自己上阿里云搜索容器镜像服务,然后创建镜像仓库个人版然后创建仓库,复制地址即可。
然后配置镜像加速器,跟着命令复制粘贴即可。
然后测试运行
然后记得在docker中登录实例。
阿里云镜像加速器目前仅限「阿里云 ECS 实例」在「同地域内网」环境下使用,且只支持拉取部分官方镜像。 如果你在 本地电脑、非阿里云服务器、或通过公网访问 ,即使配置了加速地址,也会被拒绝(返回 403 或超时) 。
所以换加速器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.1ms.run", "https://l3aesvg6.mirror.aliyuncs.com", "https://docker.xuanyuan.me", "https://docker.mirrors.ustc.edu.cn", "https://hub-mirror.c.163.com" ] } EOF sudo systemctl restart docker docker info | grep -A 2 "Registry Mirrors" #验证 # 测试中科大 curl -I https://docker.mirrors.ustc.edu.cn/v2/ # 测试网易 curl -I https://hub-mirror.c.163.com/v2/
(12 封私信 / 2 条消息) 2025 最新 Docker 国内镜像源加速列表(12月22日更新) - 知乎
底层原理 为什么Docker比虚拟机快
(1)docker有着比虚拟机更少的抽象层 由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。 (2)docker利用的是宿主机的内核,而不需要加载操作系统OS内核 当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
3、Docker常用命令 帮助启动类命令 1 2 3 4 5 6 7 8 启动docker: systemctl start docker 停止docker: systemctl stop docker 重启docker: systemctl restart docker 查看docker状态: systemctl status docker 开机启动: systemctl enable docker 查看docker概要信息: docker info 查看docker总体帮助文档: docker --help 查看docker命令帮助文档: docker 具体命令 --help
镜像命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 列出本地主机上的镜像:docker images [可选 -a] [可选 -q] -a :列出本地所有的镜像(含历史映像层) -q :只显示镜像ID。 各个选项说明: REPOSITORY:表示镜像的仓库源 TAG:镜像的标签版本号 IMAGE ID:镜像ID CREATED:镜像创建时间 SIZE:镜像大小 同一仓库源可以有多个TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。 如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像 docker search [可选 --limit] 某个XXX镜像名字 --limit 只列出N个镜像,默认25个。 docker pull 某个XXX镜像名字 docker pull 镜像名字[: TAG] 没有TAG就是最新版等价于docker pull 镜像名字:latest docker system df 查看镜像/容器/数据卷所占的空间 docker rmi 某个XXX镜像名字ID 删除镜像 删除单个 docker rmi -f 镜像ID 删除多个 docker rmi -f 镜像名1:TAG 镜像名2:TAG 删除全部 docker rmi -f $(docker images -qa)
面试题:谈谈docker虚悬镜像是什么?
仓库名、标签都是<none>的镜像,俗称虚悬镜像dangling image
后续Dockerfile章节再介绍
结合我们Git的学习心得,大家猜猜是否会有 docker commit /docker push??
容器命令 1、新建+启动容器 有镜像才能创建容器, 这是根本前提(下载一个CentOS或者ubuntu镜像演示)
我们可以把centos7当阿里云,然后我们在里面装了docker,然后在里面装ubuntu或者centos
启动容器
1 2 3 4 5 6 7 8 9 10 11 12 docker run [可选项] image [command] [arg...] 可选项OPTIONS说明(常用):有些是一个减号,有些是两个减号 --name="容器新名字" 为容器指定一个名称; -d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行); -i:以交互模式运行容器,通常与 -t 同时使用; -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用; 也即启动交互式容器(前台有伪终端,等待交互); docker run -it ubuntu -P: 随机端口映射,大写P... -p: 指定端口映射,小写p
这里的端口是什么。
现在全部上容器,首先找到docker的端口,然后假设redis在docker里面,然后又要在docker里面找到redis的端口映射,所以外面就需要-p 6379:6379这样就能找到指定的了。
启动交互式容器(前台命令行)
现在我们有ubuntu,然后启动交互式容器
1 docker run -it ubuntu bash #相当于启动ubuntu,并且打开Bash命令窗口 或者/bin/bash
2、列出当前所有正在运行的容器 1 2 3 4 5 6 docker ps [OPTIONS] OPTIONS说明(常用): -a :列出当前所有正在运行的容器+历史上运行过的 -l :显示最近创建的容器。 -n:显示最近n个创建的容器。 -q :静默模式,只显示容器编号。
3、退出容器 1 2 exit run进去的容器,exit退出,同期停止 ctrl+p+q run进去的容器,ctrl+p+q退出,容器不停止
4、启动已停止运行的容器
5、重启容器
6、停止容器
7、强制停止容器
8、删除已停止的容器 1 2 3 4 docker rm 容器ID 一次性删除多个容器实例 docker rm -f $(docker ps -a -q) docker ps -a -q | xargs docker rm
重要 如何重新进入还活着的容器?容器启动后是后端默认的启动守护式容器还是前台的交互式容器?
有镜像才能创建容器,这是根本前提(下载一个Redis6.0.8镜像演示)
启动守护式容器(后台服务器)
在大部分的场景下,我们希望 docker 的服务是在后台运行的, 我们可以过 -d 指定容器的后台运行模式。
docker run -d 容器名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #使用镜像centos:latest以后台模式启动一个容器 docker run -d centos 问题:然后docker ps -a 进行查看, 会发现容器已经退出 很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程. 容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。 这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下, 我们配置启动服务只需要启动响应的service即可。例如service nginx start 但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用, 这样的容器后台启动后,会立即自杀,因为他觉得他没事可做了。 因为centos是一个交互式 shell,需要 stdin 输入 后台模式下,没有终端连接 但是redis是一个 前台阻塞式服务程序启动后 不会 fork 到后台而是 直接在前台持续运行,监听端口、处理请求 所以,最佳的解决方式,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我们还有交互操作,别中断。
查看容器日志
查看容器内运行的进程
1 2 3 4 docker top 容器ID ps 显示 宿主机所有进程 docker top 只显示 属于该容器 Namespace 的进程
查看容器内部细节
进入正在运行的容器并以命令进行交互
1 2 3 4 5 6 7 8 9 10 docker exec -it 容器ID bashShell 重新进入docker attach 容器ID 上述两个区别: attach 直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止。 exec 是在容器中打开新的终端,并且可以启动新的进程用exit退出,不会导致容器的停止。 推荐大家使用docker exec 命令,因为退出容器,不会导致容器的停止。 docker exec -it 容器ID /bin/bash docker exec -it 容器ID redis-cli 这两条命令一个是操作Linux一个是操作redis
从容器拷贝文件到主机上
之前是gitlab或者github,然后要clone各种文件下载代码。
现在新技术,一切在云端,全部跑容器。
先下载docker,然后从容器中拷贝到主机中。获得一堆镜像文件,然后就环境相同的开发了。
1 2 容器 -> 主机 docker cp 容器ID:容器内路径 目的主机路径
导入和导出容器
之前只是把容器内的资料拷贝出来,现在是整个容器,整个镜像备份
1 2 3 4 5 export 导出容器的内容留作为一个tar归档文件[对应import命令] import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export] 案例: docker export 容器ID > 文件名.tar cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
小总结
命令
说明
attach
连接到一个正在运行的容器(共享其主进程终端,慎用 :退出可能终止容器)
build
根据 Dockerfile 构建一个新的镜像
commit
将容器的当前修改保存为一个新的镜像(不推荐用于生产,应优先使用 Dockerfile)
cp
在容器和宿主机之间复制文件或目录(格式:docker cp 容器ID:/路径/文件 ./本地路径)
create
创建一个新容器(但不启动 ,需配合 docker start 使用)
diff
检查容器文件系统相对于镜像的更改(新增/修改/删除的文件)
events
从服务器获取实时事件流(如容器启动、停止、销毁等)
exec
在运行中的容器内执行新命令(常用:docker exec -it 容器ID /bin/bash)
export
将容器的文件系统导出为 tar 归档文件(不包含历史层,仅当前状态)
history
显示镜像的构建历史(各层及大小)
images
列出本地所有镜像
import
从 tar 包导入创建新镜像(与 export 配对使用)
info
显示 Docker 系统信息(存储驱动、内核版本、容器/镜像数量等)
inspect
获取容器或镜像的详细元数据(JSON 格式,含 IP、挂载点、环境变量等)
kill
强制终止一个或多个运行中的容器(发送 SIGKILL)
load
从 tar 文件加载镜像(通常由 docker save 生成)
login
登录到 Docker Registry(如 Docker Hub)
logout
退出当前 Registry 登录
logs
获取容器的日志输出(加 -f 可实时跟踪)
pause
暂停容器内所有进程(使用 cgroups freezer)
port
列出容器的端口映射关系(如 0.0.0.0:32768->6379/tcp)
ps
列出容器(默认只显示运行中,加 -a 显示所有)
pull
从 Registry 下载镜像(如 docker pull nginx:alpine)
push
将本地镜像推送到 Registry
rename
重命名容器
restart
重启一个或多个容器
rm
删除一个或多个已停止 的容器(加 -f 可强制删除运行中容器)
rmi
删除一个或多个本地镜像(加 -f 强制删除)
run
创建并启动 一个新容器(最常用命令,相当于 create + start)
save
将一个或多个镜像保存为 tar 文件(保留完整历史层,可用于迁移)
search
在 Docker Hub 中搜索镜像(如 docker search redis)
start
启动一个或多个已创建但未运行 的容器
stats
实时显示容器的资源使用统计(CPU、内存、网络、IO)
stop
优雅停止容器(发送 SIGTERM,等待后发 SIGKILL)
tag
给镜像打标签(用于重命名或准备推送至不同仓库)
top
显示容器内运行的进程(类似宿主机的 ps)
unpause
恢复被 pause 的容器
update
动态更新容器的资源配置(如 CPU、内存限制)
version
显示 Docker 客户端和服务器版本信息
wait
阻塞直到指定容器停止,并打印其退出码
4、Docker镜像 是什么 镜像 是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
分层镜像 以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载
联合文件系统 UnionFS UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理 docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。 bootfs(boot file system)主要包含bootloader(根加载)和kernel(Linux内核)(之前讲过可以把容器看做是一个简易版的Linux环境)
, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??
虚拟机 = 完整操作系统(含内核)Docker 容器 = 只要文件系统(不含内核)
bootfs :在传统 Linux 中是启动用的临时文件系统,Docker 中已不需要 ,因为容器不经历“启动过程”,而是直接由 Docker 引擎拉起进程。
rootfs :就是操作系统所需的文件集合 (/bin, /lib, /etc…),Docker 镜像的本质就是这个 rootfs。
内核(Kernel) :Docker 容器完全共享宿主机的内核 ,自己不带
所有 Linux 发行版的 bootfs(内核)在 Docker 中都被省略了,统一用宿主机内核; 而 rootfs 是不同的——CentOS 的 rootfs ≠ Ubuntu 的 rootfs,但都只包含最小必要文件。
生活化例子
场景
虚拟机
Docker 容器
开一家餐厅
自己盖房子 + 装水电 + 买厨具 + 招厨师 + 办执照
只租厨房 + 带自己的菜谱和食材
操作系统
完整 OS(含内核)
只带应用和依赖(用房东的水电=宿主机内核)
启动速度
几十秒到几分钟
几百毫秒
磁盘占用
几 GB
几十~几百
因为我们只要rootfs和bootfs就好了,只需要包括最基本的命令、工具和程序就可以了,因为底层直接用Host的kernel,也就是说只用主机的内核,自己只需要提供rootfs就行了,由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
为什么Docker镜像要采用这种分层结构呢
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像; 同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
重点理解 Docker镜像层都是只读的,容器层是可写的 当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。 所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
Docker镜像commit操作案例 现在有Ubuntu但是ubuntu里面没有vim的能力,现在加上之后再更新版本
1 2 3 4 5 6 7 8 9 10 11 12 docker commit提交容器副本使之成为一个新的镜像 docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名] 案例演示ubuntu安装vim 1、从Hub上下载ubuntu镜像到本地并成功运行 2、原始的默认Ubuntu镜像是不带着Vim命令的 3、外网联通的情况下,安装vim 进入ubuntu然后docker容器内执行两条命令: apt-get update apt-get -y install vim 4、安装完成后,commit我们自己的新镜像 docker commit -m="vim cmd add ok" -a="oyy" 097e93f84a81 bitzh/myubuntu:1.3 5、启动我们的新镜像并和原来的对比
小总结 Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。 新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层
5、本地镜像发布到阿里云 发布流程
镜像的生成方法 第一种 docker comit 1 2 3 docker commit提交容器副本使之成为一个新的镜像 docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名] docker commit -m="vim cmd add ok" -a="oyy" 097e93f84a81 bitzh/myubuntu:1.3
第二种 后面的DockerFile讲解 进入阿里云平台镜像服务 创建仓库镜像 1、选择控制台进入镜像服务
2、选择个人实例
3、命名空间
4、仓库名称
5、进入管理界面获得脚本
将本地镜像推送到阿里云 根据管理界面脚本进行推送
将阿里云镜像下载到本地 根据管理界面脚本进行拉取
6、本地镜像发布到私有库 是什么 Docker Registry
官方、和阿里云公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库,给团队使用,Docker Registry 是官方提供的工具,可以用于构建私有镜像仓库
流程 1、下载镜像Docker Registry
运行私有库 运行私有库Registry,相当于本地有个私有Docker hub
1 2 docker run -d -p 5000:5000 -v /oyyuse/myregistry/:/tmp/registry --privileged=true registry 默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调
案例演示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ubuntu安装ifconfig 1、从Hub上下载ubuntu镜像到本地并成功运行 2、原始的ubuntu镜像是不带ifconfig命令的 3、外网联通的情况下安装ifconfig命令并测试通过 docker容器内执行上述两条命令: apt-get update apt-get install net-tools 4、然后commit自己的镜像 docker commit -m="vim cmd add ok" -a="oyy" 097e93f84a81 bitzh/myubuntu:1.3 5、curl验证私服库上有什么镜像 curl -XGET http://192.168.10.128:5000/v2/_catalog 可以看到,目前私服库没有任何镜像上传过。。。。。。 6、将新镜像修改符合私服规范的Tag 按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag 自己host主机IP地址,填写同学你们自己的,不要粘贴错误,O(∩_∩)O 使用命令 docker tag 将zzyyubuntu:1.2 这个镜像修改为192.168.111.162:5000/zzyyubuntu:1.2 docker tag bitzh/myubuntu:1.2 192.168.10.128:5000/oyyubuntu:1.2 7、修改配置文件使之支持http的推送 别无脑照着复制,registry-mirrors 配置的是国内阿里提供的镜像加速地址,不用加速的话访问官网的会很慢。 2个配置中间有个逗号 ','别漏了,这个配置是json格式的。 vim命令新增如下红色内容:vim /etc/docker/daemon.json { "registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"], "insecure-registries": ["192.168.10.128:5000"] } 改了配置后重启一下,systemctl restart docker 8、开始推送到私服库 docker push 192.168.10.128:5000/oyyubuntu:1.2 9、第二次验证有什么镜像 curl -XGET http://192.168.10.128:5000/v2/_catalog 10、pull到本地并运行 docker pull 192.168.10.128:5000/oyyubuntu:1.2 docker run -it 镜像ID /bin/bash
7、Docket容器数据卷 1 2 3 4 5 6 7 8 9 docker run -d -p 5000:5000 -v /oyyuse/myregistry/:/tmp/registry --privileged=true registry 上面容器卷记得加入 --privileged=true 为什么(挂载就类似于u盘插入主机上多个目录) Docker挂载主机目录访问如果出现cannot open directory .: Permission denied 解决办法:在挂载目录后多加一个--privileged=true参数即可 如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,禁止访问挂载内容 在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用--privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即 使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
参数 -v
一句话:有点类似我们Redis里面的rdb和aof文件
将docker容器内的数据保存进宿主机的磁盘中
运行一个带有容器卷存储功能的容器实例
1 2 docker run -d -p 5000:5000 -v /oyyuse/myregistry/:/tmp/registry --privileged=true registry docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
是什么 卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性: 卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
能干嘛 将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望 是持久化的
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。 为了能保存数据在docker中我们使用卷。
特点: 1:数据卷可在容器之间共享或重用数据 2:卷中的更改可以直接实时生效,爽 3:数据卷中的更改不会包含在镜像的更新中 4:数据卷的生命周期一直持续到没有容器使用它为止
数据卷案例 宿主vs容器之间映射添加容器卷 也就是说在容器内添加数据卷让容器挂载数据卷从而具有持久化的能力。
直接命令添加
1 2 3 4 5 6 7 8 docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名 公式:docker run -it -v /宿主机目录:/容器内目录 ubuntu /bin/bash docker run -it --name myu3 --privileged=true -v /tmp/myHostData:/tmp/myDockerData ubuntu /bin/bash 现在 在ubuntu里面就有数据卷了,那么现在如果数据卷里有数据那么会同步到主机上。主机里有的也会同步回去。 然后利用docker inspect 来返回json串来看容器内容 然后就能查看数据卷和容器挂载的位置,从而验证是否挂载成功 实现容器和宿主机之间数据共享 假设数据卷停了,然后容器写数据,然后这时候,数据卷也是有数据的。
读写规则映射添加说明 上一个知道我们通过命令让容器内数据同步到数据卷,数据卷也能同步到主机上。
其实在命令里面有个读写规则的添加
1 2 3 4 5 6 7 8 默认是读写的。 docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名 如果有诉求只读,容器只能读取,不能写数据 /容器目录:ro 镜像名 就能完成功能,此时容器自己只能读取不能写 ro = read only 此时如果宿主机写入内容,可以同步给容器内,容器可以读取到。 docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
卷的继承和共享 1、容器1完成和宿主机的映射
1 docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
2、容器2继承容器2的卷规则
1 2 3 docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu docker run -it --privileged=true --volumes-from u1 --name=u2 ubuntu 那如果u1挂了,u2完全没关系,依然能跟u1一样
8、Docket常规安装简介 总体步骤 1 2 3 4 5 6 1、搜索镜像 2、拉取镜像 3、查看镜像 4、启动镜像 服务端口映射 5、停止容器 6、移出容器
安装tomcat 1 2 3 4 5 6 7 8 9 10 docker hub上面查找tomcat镜像 docker search tomcat 从docker hub上拉取tomcat镜像到本地 docker pull tomcat docker images查看是否有拉取到的tomcat 使用tomcat镜像创建容器实例(也叫运行镜像) docker run -it -p 8080:8080 tomcat 访问猫首页 发现404报错了,因为tomcat最新版本对首页访问有改变 可能没有映射端口或者没有关闭防火墙 把webapps.dist目录换成webapps 免修改版本 docker pull billygoo/tomcat8-jdk8 docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
安装mysql 1 2 3 4 5 6 7 8 9 10 docker pull mysql docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql docker ps docker exec -it 容器ID /bin/bash mysql -uroot -p 外部Win10也来连接运行在dokcer上的mysql容器实例服务也是可以的 但是插入中文数据报错了?因为docker上默认字符集编码隐患 docker里面的mysql容器实例查看,内容如下: SHOW VARIABLES LIKE 'character%' 删除容器后,里面的mysql数据如何办?
实战版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 新建mysql容器实例,也就是说mysql这些要挂容器数据卷 docker run -d -p 3306:3306 --privileged=true -v /oyyuse/mysql/log:/var/log/mysql -v /oyyuse/mysql/data:/var/lib/mysql -v /oyyuse/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7 权限开启,挂了三个卷,日志卷,数据卷,配置卷 解决中文乱码: cd /oyyuse/mysql/conf 新建my.cnf,通过容器卷同步给mysql容器实例 [client] default_character_set=utf8 [mysqld] collation_server = utf8_general_ci character_set_server = utf8 重新启动mysql容器实例再重新进入并查看字符编码 再新建库新建表再插入中文测试 结论:docker安装完MySQL并run出容器后,建议请先修改完字符集编码后再新建mysql库-表-插数据 假如将当前容器实例删除,再重新来一次,之前建的db01实例还有吗?照样在。
安装redis 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1、在CentOS宿主机下新建目录 /app/redis mkdir -p /app/redis 将一个redis.conf文件模板拷贝进/app/redis目录下 cp /myredis/redis.conf /app/redis/ 修改的东西 1、开启redis验证requirepass 123 2、允许redis外地连接 必须 注释掉# bind 127.0.0.1 3、daemonize no ,yes改为no,因为该配置和docker run中-d参数冲突,会导致容器一直启动失败 4、开启redis数据持久化appendonly yes 可选 使用redis6.0.8镜像创建容器(也叫运行镜像) docker run -p 6379:6379 --name myr3 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf docker exec -it 运行着Rediis服务的容器ID redis-cli
安装nginx 类似的,可以见高级篇Portainer
Docker高阶篇 1、Docker复杂安装 mysql主从复制 首先原理:
1 2 3 4 5 6 7 8 9 [Master] │ ├── (1) 数据变更 → 写入 binlog │ └── (2) Binlog Dump 线程 ←→ I/O 线程 [Slave] │ ├── (3) 写入 Relay Log │ └── (4) SQL 线程重放 → 更新从库数据
主从搭建步骤 1、新建主服务器容器实例3307
1 2 3 4 5 6 7 docker run -p 3307:3306 --name mysql-master \ -v /mydata/mysql-master/log:/var/log/mysql \ -v /mydata/mysql-master/data:/var/lib/mysql \ -v /mydata/mysql-master/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7 docker ps
2、进入/mydata/mysql-master/conf目录下新建my.cnf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 vim my.cnf [mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=101 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能 log-bin=mall-mysql-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 自动清理超过指定天数的 binlog 文件,防止磁盘爆满 ## 此处设置保留最近 7 天的 binlog expire_logs_days=7 ## 当从库(Slave)在执行 relay log 时遇到指定错误码,自动跳过该错误继续同步 ## 1062 = 主键冲突,1032是主从数据库数据不一致 slave_skip_errors=1062
3、修改完配置后重启master实例
1 docker restart mysql-master
4、进入mysql-master容器
1 2 docker exec -it mysql-master /bin/bash mysql -uroot -proot
5、master容器实例内创建数据同步用户
1 2 CREATE USER 'slave'@'%' IDENTIFIED BY '123456'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
6、新建从服务器容器实例3308
1 2 3 4 5 6 7 docker run -p 3308:3306 --name mysql-slave \ -v /mydata/mysql-slave/log:/var/log/mysql \ -v /mydata/mysql-slave/data:/var/lib/mysql \ -v /mydata/mysql-slave/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7 docker ps
7、进入/mydata/mysql-slave/conf目录下新建my.cnf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 vim my.cnf [mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=102 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用 log-bin=mall-mysql-slave1-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 自动清理超过指定天数的 binlog 文件,防止磁盘爆满 ## 此处设置保留最近 7 天的 binlog expire_logs_days=7 ## 当从库(Slave)在执行 relay log 时遇到指定错误码,自动跳过该错误继续同步 ## 1062 = 主键冲突,1032是主从数据库数据不一致 slave_skip_errors=1062 ## relay_log配置中继日志 relay_log=mall-mysql-relay-bin log_slave_updates=1 read_only=1
8、修改完配置后重启slave实例
1 docker restart mysql-slave
9、在主数据库中查看主从同步状态
10、进入mysql-slave容器
1 2 docker exec -it mysql-slave /bin/bash mysql -uroot -proot
11、在从数据库中配置主从复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30; master_host:主数据库的IP地址; master_port:主数据库的运行端口; master_user:在主数据库创建的用于同步数据的用户账号; master_password:在主数据库创建的用于同步数据的用户密码; master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数; master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数; master_connect_retry:连接失败重试的时间间隔,单位为秒。
12、在从数据库中查看主从同步状态
13、在从数据库中开启主从同步
14、查看从数据库状态发现已经同步
15、主从复制测试
安装redis集群 cluster(集群)模式-docker版 哈希槽分区进行亿级数据存储
面试题 1~2亿条数据需要缓存,请问如何设计这个存储案例
回答 :单机单台100%不可能,肯定是分布式存储,用redis如何落地?
上述问题阿里P6~P7工程案例和场景设计类必考题目, 一般业界有3种解决方案
三种解决方案 哈希取余分区 就是记录来了,假设3台机器构成一个集群,用户每次读写操作都是根据公式取余确定写入和读取的机器。
缺点就是原来规划好的节点,进行扩容或者缩容就麻烦了,每次节点变动都要重新进行映射计算。
一致性哈希算法分区 理解起来就是分母不变,会利用算法构建哈希环,然后用户根据哈希算法,算出映射后,离哈希环节点最近的就是他的写入和读取数据的机器,如果机器进行扩缩容,也只用重新分配一小部分的,其他不在范围内的就不用重新分配。
缺点就节点少的时候是容易造成数据倾斜,也就是大量数据在一台服务器里执行,其他机器映射不到。
哈希槽分区 这个就是在数据和redis之间增加槽位这个概念,也就解决了一致性哈希节点少的问题了,首先槽位固定是16384个,然后从0开始,然后集群的机器都是主机,然后不会超过1000个,那么每当一个数据进来,先让key进槽位进行CRC16算法进行分配,分配好了之后,假设0-xxx是机器一负责,xxx-xxxx是机器2负责,剩下的机器三负责,这样就解决了数据倾斜问题。
3主3从redis集群扩缩容配置案例架构 第一步
3主3从配置步骤 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 1、关闭防火墙+启动docker后台服务 systemctl start docker 2、新建6个docker容器redis实例 创建并运行docker容器实例 docker run --name redis-node-6 # 容器名字 --net host # 使用宿主机的IP和端口,默认 --privileged=true # 获取宿主机root用户权限 -v /data/redis/share/redis-node-6:/data # 容器卷,宿主机地址:docker内部地址 redis:6.0.8 # redis镜像和版本号 --cluster-enabled yes # 开启redis集群 --appendonly yes # 开启持久化 --port 6386 # redis端口号 然后改名字1-6然后一路回车就行 3、进入容器redis-node-1并为6台机器构建集群关系 进入容器 docker exec -it redis-node-1 /bin/bash 构建主从关系 //注意,进入docker容器后才能执行一下命令,且注意自己的真实IP地址 redis-cli --cluster create 192.168.111.147:6381 192.168.111.147:6382 192.168.111.147:6383 192.168.111.147:6384 192.168.111.147:6385 192.168.111.147:6386 --cluster-replicas 1 --cluster-replicas 1 表示为每个master创建一个slave节点 前3个主,后3从 链接进入6381作为切入点,查看节点状态 redis-cli -p 6381 cluster info cluster nodes
主从容错切换迁移案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1、数据读写存储 启动6机构成的集群并通过exec进入 对6381新增两个key 防止路由失效加参数-c并新增两个key 加入参数-c,优化路由,因为假设在1号主机set k1 v1 但是k1路由其实是到机器2的所以就加入失败了,但是加了参数就能自动路由到机器2了 redis-cli -p 6381 -c 然后设置值的时候就跳转到对应的容器了 查看集群信息 redis-cli --cluster check 192.168.111.147:6381 2、容错切换迁移 主6381和从机切换,先停止主机6381 6381主机停了,对应的真实从机上位 6381作为1号主机分配的从机以实际情况为准,具体是几号机器就是几号 然后发现从机上位了 现在6381又回来了,也是变成从机 redis-cli --cluster check 自己IP:6381
主从扩容案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 1、新建6387、6388两个节点+新建后启动+查看是否8节点 docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387 docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388 docker ps 2、进入6387容器实例内部 docker exec -it redis-node-7 /bin/bash 3、将新增的6387节点(空槽号)作为master节点加入原集群 redis-cli --cluster add-node 自己实际IP地址:6387 自己实际IP地址:6381 6387 就是将要作为master新增节点 6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群 4、检查集群情况第1次 redis-cli --cluster check 真实ip地址:6381 5、重新分派槽号 命令:redis-cli --cluster reshard IP地址:端口号 redis-cli --cluster reshard 192.168.111.147:6381 6、检查集群情况第2次 redis-cli --cluster check 真实ip地址:6381 槽号分派说明 为什么6387是3个新的区间,以前的还是连续? 重新分配成本太高,所以前3家各自匀出来一部分,从6381/6382/6383三个旧节点分别匀出1364个坑位给新节点6387 7、为主节点6387分配从节点6388 命令:redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID redis-cli --cluster add-node 192.168.111.147:6388 192.168.111.147:6387 --cluster-slave --cluster-master-id e4781f644d4a4e4d4b4d107157b9ba8144631451-------这个是6387的编号,按照自己实际情况 8、检查集群情况第3次 redis-cli --cluster check 192.168.111.147:6382
主从缩容案例 目的:6387和6388下线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1、检查集群情况1获得6388的节点ID redis-cli --cluster check 192.168.111.147:6382 2、将6388删除从集群中将4号从节点6388删除 命令:redis-cli --cluster del-node ip:从机端口 从机6388节点ID redis-cli --cluster del-node 192.168.111.147:6388 5d149074b7e57b802287d1797a874ed7a1a284a8 redis-cli --cluster check 192.168.111.147:6382 检查一下发现,6388被删除了,只剩下7台机器了。 3、将6387的槽号清空,重新分配,本例将清出来的槽号都给6381 redis-cli --cluster reshard 192.168.111.147:6381 4、检查集群情况第二次 redis-cli --cluster check 192.168.111.147:6381 4096个槽位都指给6381,它变成了8192个槽位,相当于全部都给6381了,不然要输入3次,一锅端,也可以输入三次,但是这里一次性解决。 5、将6387删除 命令:redis-cli --cluster del-node ip:端口 6387节点ID redis-cli --cluster del-node 192.168.111.147:6387 e4781f644d4a4e4d4b4d107157b9ba8144631451 6、检查集群情况第三次 redis-cli --cluster check 192.168.111.147:6381
2、DockerFile解析 是什么 Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
举个例子:假设现在有ubuntu,然后,里面默认不含有vim/ifconfig。那么需要人工干预+加强功能
安装功能然后docker commit,然后利用新镜像。
但是对于后面随时变化,很麻烦,操作一次commit一次。一次性搞定?现在某种镜像增强,给list清单,直接在list里面写好,相当于多次提交。Dockerfile,本镜像需要一次添加 vim/ifconfig/java8等,一次成型。
官网:https://docs.docker.com/engine/reference/builder/
构建三部曲 1、编写Dockerfile文件
2、docker build 命令构建镜像
3、docker run依镜像运行容器实例
DockerFile构建过程解析 Dockerfile内容基础知识 1 2 3 4 1:每条保留字指令都必须为 大写字母 且后面要跟随至少一个参数 2:指令按照从上到下,顺序执行 3:#表示注释 4:每条指令都会创建一个新的镜像层并对镜像进行提交,一层层加上的。
Docker执行Dockerfile的大致流程 (1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
小总结
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段, * Dockerfile是软件的原材料 * Docker镜像是软件的交付品 * Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例 Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
1 Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2 Docker镜像 在Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行Docker金刚时会真正开始提供服务。
3 Docker容器,容器是直接提供服务的。
DockerFile常用保留字指令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 参考tomcat8的dockerfile入门 https://github.com/docker-library/tomcat 1、FROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from 2、MAINTAINER 镜像维护者的姓名和邮箱地址 3、RUN 容器构建时需要运行的命令 两种格式: shell格式 RUN yum -y install vim exec格式 RUN是在 docker build时运行 4、EXPOSE 当前容器对外暴露出的端口 5、WORKDIR 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点.也就是进入之后的目录 6、USER 指定该镜像以什么样的用户去执行,如果都不指定,默认是root 7、ENV 用来在构建镜像过程中设置环境变量 ENV MY_PATH /usr/mytest 这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样; 也可以在其它指令中直接使用这些环境变量, 比如:WORKDIR $MY_PATH 这样就能直接引用了。 8、ADD(常用 类似于COPY+解压) 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包,比如加jdk8.tar.gz包 9、COPY 类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置 COPY src dest COPY ["src", "dest"] <src源路径>:源文件或者源目录 <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。 10、VOLUME 容器数据卷,用于数据保存和持久化工作 就是我们的 -v 11、CMD 指定容器启动后的要干的事情 CMD命令格式和RUN相似也是两种格式。 shell 模式 CMD <命令> exec 格式 CMD ["可执行文件","参数1","参数2"...] 参数列表格式 CMD ["参数1","参数2..."]指定了ENTRYPOINT 指令后,用CMD制定具体的参数 注意 Dockerfile 中可以有多个CMD指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换 参考官网Tomcat的dockerfile演示讲解 EXPOSE 8080 CMD ["catalina.sh","run"] 这个命令相当于 docker run -it -p 8080:8080 tomcatID 这样是能启动的但是加上 bash就不行了 他和前面RUN命令的区别 CMD是在docker run 时运行。 RUN是在 docker build时运行。 12、ENTRYPOINT 也是用来指定一个容器启动时要运行的命令 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖, 而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序 案例: 命令格式:ENTRYPOINT ["<executable>","<param1>","<param2>"。。。] ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。 当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成 案例如下:假设已通过 Dockerfile 构建了 nginx:test 镜像: FROM nginx ENTRYPOINT ["nginx","-c"] #定参 CMD ["/etc/nginx/nginx.conf"] #变参 是否传参 按照dockerfile编写执行 传参运行 Docker命令 docker run nginx:test docker run nginx:test -c /etc/nginx/new.conf 衍生出的实际命令 nginx -c /etc/nginx/nginx.conf nginx -c /etc/nginx/new.conf
案例 自定义镜像mycentosjava8 要求 Centos7镜像具备vim+ifconfig+jdk8
编写Dockerfile文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 首先在jdk文件夹相同目录比如 /myfile文件夹 然后vim Dockerfile FROM centos MAINTAINER oyy<<oyy0v0@126.com> ENV MYPATH /usr/local WORKDIR $MYPATH #安装vim编辑器 RUN yum -y install vim #安装ifconfig命令查看网络IP RUN yum -y install net-tools #安装java8和lib库 RUN yum -y install glibc.i686 RUN mkdir /usr/local/java #ADD 是相对路径jar 把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须和Dockerfile文件在同一位置 ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/ #配置java环境变量 ENV JAVA_HOME /usr/local/java/jdk1.8.0_171 ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH ENV PATH $JAVA_HOME/bin:$PATH EXPOSE 80 CMD echo $MYPATH CMD echo "success........ok" CMD /bin/bash
构建 1 2 3 docker build -t 新镜像名字:TAG . docker build -t centosjava8:1.5 . 注意,上面TAG后面有个空格,有个点
运行 1 2 docker run -it 新镜像名字:TAG docker run -it centosjava8:1.5 /bin/bash
虚悬镜像 是什么 仓库名、标签都是<none>的镜像,俗称dangling image
Dockerfile写一个
1 2 3 4 5 1 vim Dockerfile FROM ubuntu CMD echo 'action is success' 2 docker build .
查看 1 docker image ls -f dangling=true
删除 1 2 docker image prune 虚悬镜像已经失去存在价值,可以删除
3、Docker微服务实战 我们要把我们SpringBoot编写的模块整合成镜像
通过IDEA新建一个普通微服务模块 建Module
改POM
写YML
主启动
1 2 3 4 5 6 @SpringBootApplication public class DockerBootApplication { public static void main (String[] args) { SpringBootApplication.run(DockerBootApplication.class,args); } }
业务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RestController public class OrderController { @Value("${server.port}") private String port; @RequestMapping("/order/docker") public String helloDocker () { return "hello docekr" +"\t" +port+"\t" +UUID.randomUUID().toString(); } @RequestMapping(value = "/order/index",method = RequestMethod.GET) public String index () { return "服务端口号" +"\t" +port+"\t" +UUID.randomUUID().toString(); } }
以前是打包成jar包,现在是部署到docker容器里面。
通过dockerfile发布微服务部署到docker容器 1、IDEA工具里面搞定微服务jar包
1 docker_boot-0.0.1-SNAPSHOT.jar
2、编写Dockerfile
Dockerfile内容
把jar包上传到指定目录比如 /mydocker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 基础镜像使用java FROM java:8 # 作者 MAINTAINER zzyy # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为zzyy_docker.jar ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar # 运行jar包 RUN bash -c 'touch /zzyy_docker.jar' ENTRYPOINT ["java","-jar","/zzyy_docker.jar"] #暴露6001端口作为微服务 EXPOSE 6001 将微服务jar包和Dockerfile文件上传到同一个目录下/mydocker
构建镜像 1 2 docker build -t zzyy_docker:1.6 . 打包成镜像文件
运行容器 1 docker run -d -p 6001:6001 zzyy_docker:1.6
访问测试
4、Docker网络 从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker 运行的基本流程为:
1 用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。 2 Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。 3 Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。 4 Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
5 当需要为Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境
6 当需要限制Docker 容器运行资源或执行用户指令等操作时,则通过Execdriver 来完成
7 Libcontainer 是一项独立的容器管理包,Network driver 以及Execdriver都是通过Libcontainer来实现具体对容器进行的操作
现在我们要理解5、6、7
是什么 docker不启动,默认网络情况
1 2 3 4 5 6 7 ens33 宿主机地址 lo local本地回环地址 virbr0 在CentOS7的安装过程中如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡:它还有一个固定的默认IP地址192.168.122.1),是做虚拟机网桥的使用的,其作用是为连接其上的虚机网卡提供(虚拟机之间联通) NAT访问外网的功能。 我们之前学习Linux安装,勾选安装系统的时候附带了libvirt服务才会生成的一个东西,如果不需要可以直接将libvirtd服务卸载, yum remove libvirt-libs.x86_64
docker启动后,网络情况
1 2 3 会产生一个名为 docker0 的虚拟网桥 查看docker网络模式命令 docker network ls 默认创建3大网络模式 bridge host none
常用基本命令 1 2 3 4 docker network ls 查看网络 docker network inspect XXX网络名字 查看网络源数据 docker network rm XXX网络名字 删除网络 docker network craete 网络名字 创建网络
能干嘛 同一个网段,docker不明显。那在工作的时候会在两个不同的docker会如何,IP变动又如何
容器间的互联和通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
网络模式 总体介绍 1 2 3 4 5 6 7 8 9 10 11 bridge模式:使用--network 为每一个容器分配,设置IP等,并将容器连接到一个docker0 虚拟网桥,默认为该模式 host模式:使用--network host指定 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口 none模式:使用--network none指定 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配 veth pair和网桥连接,IP等。 container模式:使用--network container:NAME或者容器ID指定 新创建的容器不会创建自己的网卡和设置自己的IP,而是和一个指定的容器共享IP,端口范围等。 案例 docker run -it --name u1 ubuntu bash docker run -it --name u2 ubuntu bash docker inspect u1|tail -n 20 docker inspect u2|tail -n 20 然后现在u2挂了新开了个u3发现原来u2的网址给了U3,所以docker容器内部的ip是有可能会发生改变的。这时候调用服务就乱套了!所以需要网络设计和规划。让网络IP的变化不影响我们的调用
案例说明 1、bridge 是什么 Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层 连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络 。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信 。
查看 bridge 网络的详细信息,并通过 grep 获取名称项
1 2 docker network inspect bridge | grep name ifconfig
网络模型说明 1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关 。因为在同一宿主机内的容器都接入同一个网桥 ,这样容器之间就能够通过容器的Container-IP直接通信。
2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3 网桥docker0创建一对 对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配
3.1、整个宿主机的网络模式都是docker0,类似有一个交换机有一堆借口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)
3.2、每个容器实例内部也有一块网卡,每个接口叫eth0
3.3、docker0上面的每个veth匹配某个容器实例内部的eth0,两两匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
大家仔细看会发现桥接连接的是容器和主机的网卡,而网卡内部是有ip地址,主机利用桥接提供的容器ip访问容器,容器利用桥接的主机ip访问主机,达到主机和容器的通信
案例 1 2 3 4 5 6 首先启动两台tomcat docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8 docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8 然后进入到tomcat里面docker exec -it tomcat81 bash 然后查看网络 ip addr 会发现里面有个27网卡对应外面docker0的eth0@if28 然后退出tomcat 在docker里面 ip addr|tail -n 8 会发现docker层有个28网卡对应vethxxx@if27
2、host 是什么 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
网络模型说明 容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
案例 1 2 警告写法 docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8 正确写法 docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
没有设置-p的端口映射了,如何访问启动的tomcat83??
1 2 3 4 http://宿主机IP:8080/ 在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的, 所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。
3、none 是什么 在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个 lo 需要我们自己为Docker容器添加网卡、配置IP等。
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
案例 1 2 3 4 docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8 进入容器内部查看 在容器外部查看
4、container 是什么 container⽹络模式 新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
网络模型说明
案例1 1 2 3 4 5 6 docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8 docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8 # 相当于tomcat86和tomcat85公用同一个ip同一个端口,导致端口冲突 本案例用tomcat演示不合适。。。演示坑。。。。。。o(╥﹏╥)o 换一个镜像给大家演示。
案例2 1 2 3 4 5 6 7 Alpine操作系统是一个面向安全的轻型 Linux发行版 Alpine Linux 是一款独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M的大小,所以特别适合容器打包。 docker run -it --name alpine1 alpine /bin/sh docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh 运行结果,验证共用搭桥 假如此时关闭alpine1,再看看alpine2 这种情况类似 蹭邻居的网结果邻居把路由器关了
5、自定义网络 docker link 过时所以不了解
那么自定义网络能解决网络ip更换访问不到的问题
案例 用之前
1 2 3 4 5 docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8 docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8 上述成功启动并用docker exec进入各自容器实例内部 按照IP地址ping是OK的 按照服务名ping结果???❌️
用之后
自定义桥接网络,自定义网络默认使用的是桥接网络bridge
1 2 3 4 5 6 7 新建自定义网络 docker network create oyy_network 新建容器加入上一步新建的自定义网络 docker run -d -p 8081:8080 --network oyy_network --name tomcat81 billygoo/tomcat8-jdk8 docker run -d -p 8082:8080 --network oyy_network --name tomcat82 billygoo/tomcat8-jdk8 互相ping测试 自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)✅️
docker整体架构图
5、Docker-compose容器编排 Docker-Compose是Docker官方的开源项目, 负责实现对Docker容器集群的快速编排。
是什么 Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系 。然后,只要一个命令,就能同时启动/关闭这些容器
能干嘛 docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。。。。。。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建,Docker-Compose解决了容器与容器之间如何管理编排的问题
去哪下 官网:https://docs.docker.com/compose/compose-file/compose-file-v3/
官网下载:https://docs.docker.com/compose/install/
安装步骤 1 2 3 4 5 6 7 8 9 10 11 # 1. 获取最新版本号 VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4) # 2. 下载并安装 (注意这里 URL 结构和 V1 略有不同) sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 3. 赋予执行权限 sudo chmod +x /usr/local/bin/docker-compose # 4. 验证版本 docker-compose --version
卸载步骤 1 sudo rm /usr/local/bin/docker-compose
手动下载 (curl 方式) :
位置 :通常在 /usr/local/bin/docker-compose。
更新 :需要你再次手动运行 curl 下载新版本并覆盖旧文件。
管理 :系统包管理器(yum/dnf)不知道它的存在。
插件版 (yum 方式) :
位置 :通常在 /usr/libexec/docker/cli-plugins/。
更新 :随系统更新。执行 sudo yum update docker-compose-plugin 即可自动升级,非常省心。
管理 :受系统的 RPM 包管理系统监控,安装更安全、更标准。
Compose核心理念 一个文件 docker-compose.yml
两个要素
1 2 3 4 服务(service) 一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器 工程(project) 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose使用的三个步骤 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
之前我们用idea + springboot写了微服务然后用package打包成Jar包,然后用Dockerfile打成镜像,然后用docker-compose.yml,最后执行,类似于一次性执行多个docker run 命令
Compose常用命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Compose常用命令 docker-compose -h # 查看帮助 docker-compose up # 启动所有docker-compose服务 docker-compose up -d # 启动所有docker-compose服务并后台运行 docker-compose down # 停止并删除容器、网络、卷、镜像。 docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash docker-compose ps # 展示当前docker-compose编排过的运行的所有容器 docker-compose top # 展示当前docker-compose编排过的容器进程 docker-compose logs yml里面的服务Id #查看容器输出日志 docker-compose config #检查配置 docker-compose config -q #检查配置,有问题才有输出 docker-compose restart #重启服务 docker-compose stop #停止服务
Compose编排微服务 以前的基础版 1、SQL建表建库 1 2 3 4 5 6 7 8 9 10 CREATE TABLE `t_user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名', `password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码', `sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ', `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY ("id") ) ENGINE=INNODB AUTO_INCREMENT=1114 DEFAULT CHARSET=utf-8 COMMENT='用户表'
2、编写config、controller、entites、mapper、service还有mapper.xml等做些基础的功能 3、mvn package命令将微服务形成新的jar包 并上传到Linux服务器/mydocker目录下 1 2 3 4 5 6 7 8 9 10 11 12 13 # 基础镜像使用java FROM java:8 # 作者 MAINTAINER oyy # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为zzyy_docker.jar ADD docker_boot-0.0.1-SNAPSHOT.jar oyy_docker.jar # 运行jar包 RUN bash -c 'touch /oyy_docker.jar' ENTRYPOINT ["java","-jar","/oyy_docker.jar"] #暴露6001端口作为微服务 EXPOSE 6001
4、构建镜像 1 docker build -t oyy_docker:1.6 .
5、不用Compose 单独的mysql容器实例 新建Mysql容器实例
1 2 3 4 5 6 7 docker run -p 3306:3306 --name mysql57 --privileged=true -v /oyyuse/mysql/conf:/etc/mysql/conf.d -v /oyyuse/mysql/logs:/logs -v /oyyuse/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
进入mysql容器实例并新建库db2021+新建表t_user
1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker exec -it mysql57 /bin/bash mysql -uroot -p create database db2021; use db2021; CREATE TABLE `t_user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名', `password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码', `sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ', `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY ("id") ) ENGINE=INNODB AUTO_INCREMENT=1114 DEFAULT CHARSET=utf-8 COMMENT='用户表'
单独的redis容器实例 1 2 3 4 5 docker run -p 6379:6379 --name redis608 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
微服务工程 1 docker run -d -p 6001:6001 oyy_docker:1.6
上面三个容器实例依次顺序启动成功
swagger测试 http://localhost:你的微服务端口/swagger-ui.html#/
上面成功了,有哪些问题? 先后顺序要求固定,先mysql+redis才能微服务访问成功
多个run命令……
容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错, 要么生产IP写死(可以但是不推荐),要么通过服务调用
使用Compose 编写docker-compose.yml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 version: "3" services: microService: image: oyy_docker:1.6 container_name: ms01 ports: - "6001:6001" volumes: - /app/microService:/data networks: - atguigu_net depends_on: - redis - mysql redis: images: redis:6.0.8 ports: - "6379:6379" volumes: - "/app/redis/redis.conf:/etc/redis/redis.conf" - "/app/redis/data:/data" networks: - atguigu_net command: redis-server /src/redis/redis.conf mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: '123456' MYSQL_ALLOW_EMPTY_PASSWORD: 'no' MYSQL_DATABASE: 'db2021' MYSQL_USER: 'oyy' MYSQL_PASSWORD: 'oyy123' ports: - "3306:3306" volumes: - /oyyuse/mysql/conf:/etc/mysql/conf.d - /oyyuse/mysql/logs:/logs - /oyyuse/mysql/data:/var/lib/mysql networks: - atguigu_net command: --default-authentication-plugin=mysql_native_passwprd networks: atguigu_net:
修改boot的yml文件,与IP无关服务名有关,把IP换成Mysql和redis
mvn package命令将微服务形成新的jar包 并上传到Linux服务器/mydocker目录下
编写Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 # 基础镜像使用java FROM java:8 # 作者 MAINTAINER oyy # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为zzyy_docker.jar ADD docker_boot-0.0.1-SNAPSHOT.jar oyy_docker.jar # 运行jar包 RUN bash -c 'touch /oyy_docker.jar' ENTRYPOINT ["java","-jar","/oyy_docker.jar"] #暴露6001端口作为微服务 EXPOSE 6001
构建镜像
1 docker build -t zzyy_docker:1.6 .
执行 docker-compose up 或者 执行 docker-compose up -d
进入mysql容器实例并新建库db2021+新建表t_user
测试通过
关停 docker-compose stop
6、Docker轻量级可视化工具Portainer 是什么 Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
安装 官网: https://www.portainer.io/
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
docker命令安装
1 2 docker pull docker.xuanyuan.run/portainer/portainer-ce:latest docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer
第一次登录需要创建admin,访问地址 ip地址:9000
设置admin用户和密码后首次登录
选择local选项卡后本地docker详细信息展示
上一步的图形展示,能想得起对应命令吗?
安装nginx 利用图形化界面安装
这样就好了。
7、Docker容器监控之CAdvisor+InfluxDB+Granfana 重量级Docker监控引擎。
原生命令 1 2 3 4 docker stats命令的结果 通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。 但是, docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能
是什么 容器监控3剑客
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
CAdvisor
InfluxDB
Granfana
compose容器编排,一套带走 新建目录
新建3件套组合的 docker-compose.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 docker-compose config -q #语法检查 version: '3.8' volumes: grafana_data: {} networks: monitoring: driver: bridge services: # ==================== InfluxDB (时间序列数据库) ==================== influxdb: image: influxdb:1.8 # 使用官方镜像,更稳定 container_name: influxdb restart: always environment: - PRE_CREATE_DB=cadvisor ports: - "8083:8083" - "8086:8086" volumes: - /data/influxdb:/data cadvisor: image:google/cadvisor links: - influxdb:influxsrv command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086 restart: always ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/rim:/var/run:rw - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro # ==================== Grafana (可视化仪表板) ==================== grafana: user: "104" image: grafana/grafana user: "104" restart: always links: -influxdb:influxsrv ports: - "3000:3000" volumes: -grafana_data:/var/lib/grafana environment: - HTTP_USER=admin - HTTP_PASS=admin - INFLUXDB_HOST=influxsrv - INFLUXDB_PORT=8086 - INFLUXDB_NAME=cadvisor - INFLUXDB_USER=root - INFLUXDB_PASS=root docker-compose -d up
测试 浏览cAdvisor收集服务,http://ip:8080/
浏览influxdb存储服务,http://ip:8083/
浏览grafana展现服务,http://ip:3000
访问grafana,账号密码默认admin,admin
然后进去添加数据库,添加URL需要配置http://influxDB:8086,然后配置文件里已经建立了一个数据表名cadvisor,然后User为root
然后到配置面板panel
1、创建观察页面dashboard
2、添加面板
3、选图形,都能选,通常用Graph
4、然后在下面会选择维度
到这里cAdvisor+InfluxDB+Grafana容器监控系统就部署完成了
8、终章总结 后续k8s替代了这一套。