虚拟化相关
虚拟化相关
ZEROKO14包含虚拟机和docker相关知识点
虚拟化网络设置
docker网络
Docker网络剖析
官方文档给出了5种网络驱动模型,如下:
bridge:网桥类型网络;其实就是五大虚拟化网络模型中的NAT网络,只不过这里叫做bridge网桥类型.需要映射接口才能让外部访问到容器默认bridge不支持容器名dns
自定义bridge支持容器名dns
host:该模式仅在linux可用,理解成容器变成了宿主的一个应用了.其原理是容器使用宿主机的网络空间,因此会直接看到并使用宿主机所有网络功能None:啥网络都没有
虚拟机网络
(以virtualBox为例)
NAT模式相当于虚拟了一层NAT,但是各个虚拟机之间隔离NAT网络模式虚拟了一层NAT,各个虚拟机之间不隔离VMware等虚拟机的NAT模式不太一样 虚拟了一层NAT,各个虚拟机之间可以互相访问,虚拟机与宿主机之间也可以互访
桥接相当于虚拟机放到了宿主机局域网里(适配器选项需要和宿主当前联网使用的适配器一致).结果是虚拟机和宿主处于同一网段,由路由器统一分配ip内部网络模式相当于仅仅用交换机网线把虚拟机们连接起来了.(需要提前设置系统设置,防止虚拟机启动时一直卡在DHCP服务里,同时还需要给虚拟机手动设置ip),虚拟机间互通,但不能访问宿主,不能访问网络仅主机模式仅允许虚拟机之间以及与宿主的互访
docker
优势
- 应用隔离
- 环境配置
- 安装部署
- 持续集成
- 持续发布
- DevOps
docker和虚拟机的区别
特性 普通虚拟机 Docker 跨平台 通常只能在桌面级系统运行,例如 Windows/Mac,无法在不带图形界面的服务器上运行 支持的系统非常多,各类 windows 和 Linux 都支持 性能 性能损耗大,内存占用高,因为是把整个完整系统都虚拟出来了 性能好,只虚拟软件所需运行环境,最大化减少没用的配置 自动化 需要手动安装所有东西 一个命令就可以自动部署好所需环境 稳定性 稳定性不高,不同系统差异大 稳定性好,不同系统都一样部署方式 虚拟机使用Hypervisor虚拟化技术
Docker 通常用来做什么
- 应用分发、部署,方便传播给他人安装。特别是开源软件和提供私有部署的应用
- 快速安装测试/学习软件,用完就丢(类似小程序),不把时间浪费在安装软件上。例如 Redis / MongoDB / ElasticSearch / ELK
- 多个版本软件共存,不污染系统,例如 Python2、Python3,Redis4.0,Redis5.0
- Windows 上体验/学习各种 Linux 系统
概念理解
- 打包:就是把你软件运行所需的依赖、第三方库、软件打包到一起,变成一个安装包
- 分发:你可以把你打包好的“安装包”上传到一个镜像仓库,其他人可以非常方便的获取和安装
- 部署:拿着“安装包”就可以一个命令运行起来你的应用,自动模拟出一摸一样的运行环境,不管是在 Windows/Mac/Linux。
- 镜像:可以理解为软件安装包,可以方便的进行传播和安装。
- 容器:软件安装后的状态,每个软件运行环境都是独立的、隔离的,称之为容器。
安装
windows和mac需要安装Docker Desktop,在使用docker命令的时候要启动Docker Desktop
windows安装需要开启 Windows 虚拟化和 Linux 子系统(WSL2),如下图,不然启动会报错(新版本似乎不会报错了)
镜像加速源
6月6日大多数镜像源失效
| 镜像加速器 | 镜像加速器地址 |
|---|---|
| Docker 中国官方镜像 | https://registry.docker-cn.com |
| DaoCloud 镜像站 | http://f1361db2.m.daocloud.io |
| Azure 中国镜像 | https://dockerhub.azk8s.cn |
| 科大镜像站 | https://docker.mirrors.ustc.edu.cn |
| 阿里云 | https://ud6340vz.mirror.aliyuncs.com |
| 七牛云 | https://reg-mirror.qiniu.com |
| 网易云 | https://hub-mirror.c.163.com |
| 腾讯云 | https://mirror.ccs.tencentyun.com |
设置加速源
"registry-mirrors": ["https://registry.docker-cn.com","https://dockerhub.azk8s.cn"]
一览
基本知识
dockerhub找镜像相关
搜到一个docker镜像后
其中可能会有介绍或how to use的说明
还可能会罗列很多版本信息,可以根据版本进行下载
alpine 轻量级,瘦身版
镜像构建
Docker中包含Dockfile,镜像,容器三种概念.
其中镜像是用于构建容器的”菜谱”
镜像是按层次结构来构建的,每一层都是基于上一层的(底层是增量存储),通过编写Dockfile可以构建镜像.所以需要先指定一个基础镜像,然后在这个镜像的基础上添加其他我们需要的东西
使用
docker image history 镜像名/镜像id可以查看Dockerfile写的每一个指令(显示出来的需要从下往上看)
Dockerfile语法
FROM 基础镜像:表示新建的iamge(镜像)需要在node环境中进行,那么就需要node镜像。WORKDIR 工作目录:它可以指定容器启动后的默认工作目录,如声明了工作目录/app,即node代码在该目录下进行COPY 源路径 目标路径:作用是将当前目录的所有代码都复制到工作目录下(源路径为相对于Dockerfile文件的路径,目标路径为镜像内的路径)CMD:后面跟着一句shell 命令,该命令在容器运行的时候会得到执行,即当容器运行的时候,就会启动一个监听端口为3000的服务1
2
3
4
5
6#CMD命令后可接方括号
CMD ["node","/index.js"]
#第一个参数表示可执行程序的名字,其他参数表示该可执行程序需要的参数(注意一切路径基于镜像)
#CMD命令也可不接方括号
CMD node /index.js- CMD
-c追加命令会替换CMD指定的命令 - ENTRYPOINT
-c追加命令会追加到ENTRYPOINT指定的命令的后面(除此之外用法与CMD完全一样)
- CMD
ENV key value:设置环境变量key的值为value,如:ENV MY_NAME John Doe
依据Dockerfile构建新镜像使用命令:docker build -t my-docker-demo:1.0 . ,.表示dockerfile所在的目录
实例化该镜像,并运行
docker run -d -p 3000:3000 --name myContainerDemo my-docker-demo:1.0
进入容器shell命令行
docker exec -it myContainerDemo /bin/bash
操作完成后:可以将运行的容器提交为镜像
停止容器:
docker stop <container_name>提交容器为镜像
docker commit <container_name> <image_name>其中,
<container_name>是正在运行的容器的名称,<image_name>是要创建的新镜像的名称。创建一个新的容器,并使用
--entrypoint和--command选项来指定新的启动指令:如:
docker run -it --rm --entrypoint /bin/bash --command echo hello world <image_name>这将创建一个新的容器,该容器启动时将运行
/bin/bash程序,并执行echo hello world命令。
拉取命令: docker pull 镜像名 如果不指定架构,那么会默认拉取符合自身架构的镜像
arm架构的mac下使用
docker pull命令,如果需要拉amd64架构的镜像来通过Rosetta使用,需要使用命令docker pull --platform linux/amd64 镜像名
linux下,docker下的镜像,容器,虚拟网络,卷,插件都记录在/var/lib/docker下
目录挂载
现存问题
- 使用 Docker 运行后,我们改了项目代码不会立刻生效,需要重新
build和run,很是麻烦。 - 容器里面产生的数据,例如 log 文件,数据库备份文件,容器删除后就丢失了。
容器的特点:容器中的数据不会持久化,新建一个容器,它通常以一个干净的文件系统开始,我们可以创建文件,修改文件,但当我们停止容器时,容器中的所有数据都会丢失掉
想要持久化容器中的数据的话,需要通过目录挂载
几种挂载方式用于解决上述的问题
bind mount直接把宿主机目录映射到容器内,适合挂代码目录和配置文件。可挂到多个容器上用法:
-v 宿主机绝对路径:容器内绝对路径如:-v D:/code:/appvolume由容器创建和管理,创建在宿主机,所以删除容器不会丢失,官方推荐,更高效,Linux 文件系统,适合存储数据库数据。可挂到多个容器上用法
-v 逻辑卷名:容器内绝对路径(具名挂载) 如-v db-data:/app如果写成
-v 容器内绝对路径匿名挂载,会自动创建和容器id同名的逻辑卷tmpfs mount适合存储临时文件,存宿主机内存中。不可多容器共享。
docker命令
docker run [参数] 镜像名/镜像ID运行镜像中运行指令如
docker run -d --name container1 image-d表示后台启动--name 容器名表示给容器起名(不指定名字的话会随机起名)-p 宿主机端口:容器端口映射容器内端口到宿主机,如-p 9090:8080把容器内的8080端口暴露到宿主机的9090端口.默认映射针对的是tcp,如果要针对udp:-p 5000:5000/udp--network 虚拟网络名/网络模式指定容器所属的虚拟网络,也可以指定使用的网络模式--network-alias 容器在虚拟网络中的别名指定容器在虚拟网络中的别名(该别名在代码中可以直接作为ip地址来使用,能正确路由到对应容器)--rm代表在容器停止后自动删除容器--volumes-from 容器名指定容器名中所有的volumes都挂载过来准备启动的容器中-c 要执行的命令指定在容器启动时要执行的命令 (可以省略到-c,直接将要执行的命令接到镜像名后面),如果Dockerfile中有CMD命令带的指令,该-c指定的命令会替换CMD的命令,如果Dockerfile中有ENTRYPOINT,则-c指定的命令则会是追加执行命令docker build -t 镜像名:版本如:
docker build -t test:v1-t 镜像名:版本设置镜像名字和版本号-f Dockerfile文件可以指定不叫Dockerfile的Dockerfile文件docker network create 虚拟网络名创建虚拟网络docker exec -it 容器名/容器id /bin/bash使用/bin/bash与容器交互的方式进入容器
其他命令
docker ps 查看当前运行中的容器docker images 查看镜像列表docker rm container-id 删除指定 id 的容器docker stop/start container-id 停止/启动指定 id 的容器docker rmi image-id 删除指定 id 的镜像docker volume ls 查看 volume 列表docker network ls 查看网络列表
查看容器的ip地址,使用这句命令:docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名/容器id
多容器通信
创建虚拟网络
要想多容器之间互通,比如从 Web 容器访问 Redis 容器,我们只需要把他们放到同个网络中就可以了。
演示
创建一个名为
test-net的网络docker network create test-net运行 Redis 在
test-net网络中,别名redisdocker run -d --name redis --network test-net --network-alias redis redis:latest修改代码中通过别名redis来访问Redis容器
如js代码:
1
2
3
4const redis = require('redis');
let rds = redis.createClient({url: "redis://redis:6379"});
rds.on('connect', () => console.log('redis connect ok'));
rds.connect();运行 Web 项目,使用同个网络
docker run -p 8080:8080 --name test -v D:/test:/app --network test-net -d test:v1
这样两个容器之间就连接上了,但是如果管理的容器非常多呢,这时候就需要用到Docker-Compose
Docker-Compose
由Docker官方开源的项目
- 用于定义和运行多容器Docker应用程序的工具
- 使用YAML文件(
docker_compose.yaml)来配置应用程序的服务- 一条命令
docker compose up即可创建或启动所有服务服务之间的关联关系就是Docker Compose需要解决的问题
如果项目依赖更多的第三方软件,我们需要管理的容器就更多,每个都要单独配置运行,指定网络非常麻烦。
这里,我们使用 docker-compose 把项目的多个服务集合到一起,一键运行。
安装 Docker Compose
- 如果你是安装的桌面版 Docker,不需要额外安装,已经包含了。
- 如果是没图形界面的服务器版 Docker,你需要单独安装 安装文档
- 运行
docker-compose检查是否安装成功
编写脚本
要把项目依赖的多个服务集合到一起,我们需要编写一个docker-compose.yml文件,描述依赖哪些服务
[[数据序列化格式盘点#yaml|yaml格式参考]]
1 | version: "3.7" |
volumes部分定义了一个名为redis的volume。Volumes是用来在Docker容器之间共享数据的一种机制。在这个文件中,redis这个volume被用于存储Redis容器的数据,以便在容器重启或重新部署时保留数据
定义一个volume时,您可以选择使用具体的目录地址或者名称。在这种情况下,redis这个volume没有指定具体的目录地址,而是只给出了一个名称redis:/data。这意味着Docker会自动为这个volume创建一个挂载点,并将其用于存储容器中的数据。这种方式更加灵活,因为Docker会自动管理这个volume的位置和生命周期,而不需要您手动指定目录地址.若redis下的volumes下写为- ./redis_data:/data这就是手动指定目录地址的方式
容器默认时间不是背景时间,增加
TZ=Asia/Shanghai可以改为上海时区
在docker-compose.yml 文件所在目录,执行:docker-compose up就可以跑起来了。
相关命令
在后台运行只需要加一个 -d 参数docker-compose up -d
查看运行状态:docker-compose ps
停止运行:docker-compose stop
重启:docker-compose restart
重启单个服务:docker-compose restart service-name
进入容器命令行:docker-compose exec service-name sh
查看容器运行log:docker-compose logs [service-name]
发布和部署
镜像仓库介绍
镜像仓库用来存储我们 build 出来的“安装包”,Docker 官方提供了一个 镜像库,里面包含了大量镜像,基本各种软件所需依赖都有,要什么直接上去搜索。
我们也可以把自己 build 出来的镜像上传到 docker 提供的镜像库中,方便传播。
当然你也可以搭建自己的私有镜像库,或者使用国内各种大厂提供的镜像托管服务,例如:阿里云、腾讯云
首先你要先 打开官网,登录账号
创建一个镜像库
命令行登录账号: (下面的username均应填入实际的账号名)
docker login -u username新建一个tag(利于版本控制,便于回滚与追踪)
docker tag test:v1 username/test:v1推上去
docker push username/test:v1部署试下
docker run -dp 8080:8080 username/test:v1也可直接在docker-compose中直接使用这个镜像
username/test:v1了
阿里云容器托管: docker 官方的镜像托管有时候上传和下载都太慢了,如果你想要更快的速度,可以使用阿里云的免费镜像托管(镜像仓库100个 不限时长) 点击此处跳转阿里云容器镜像服务的镜像仓库
备份和迁移数据
容器中的数据,如果没有用挂载目录,删除容器后就会丢失数据。
参考如何挂载目录
如果你是用bind mount直接把宿主机的目录挂进去容器,那迁移数据很方便,直接复制目录就好了
如果你是用volume方式挂载的,由于数据是由容器创建和管理的,需要用特殊的方式把数据弄出来。
备份和导入Volume的流程
备份:
- 运行一个 ubuntu 的容器,挂载需要备份的 volume 到容器,并且挂载宿主机目录到容器里的备份目录。
- 运行 tar 命令把数据压缩为一个文件
- 把备份文件复制到需要导入的机器
导入:
- 运行 ubuntu 容器,挂载容器的 volume,并且挂载宿主机备份文件所在目录到容器里
- 运行 tar 命令解压备份文件到指定目录
备份 MongoDB 数据演示
运行一个 mongodb,创建一个名叫
mongo-data的 volume 指向容器的 /data 目录docker run -p 27018:27017 --name mongo -v mongo-data:/data -d mongo:4.4运行一个 Ubuntu 的容器,挂载
mongo容器的所有 volume,映射宿主机的 backup 目录到容器里面的 /backup 目录,然后运行 tar 命令把数据压缩打包到用于导出目录docker run --rm --volumes-from mongo -v d:/backup:/backup ubuntu tar cvf /backup/backup.tar /data/--rm代表在容器停止后自动删除容器
最后你就可以拿着这个 backup.tar 文件去其他地方导入了。
本质其实就是用一个ubuntu镜像的临时容器映射了宿主机的两个目录(分别是要备份的文件目录以及用于导出备份文件的目录),容器中
/data目录下的内容压缩放到容器下backup目录,执行完毕后到宿主机中的d:/backup就可以找到备份文件backup.tar
恢复 Volume 数据演示
- 运行一个 ubuntu 容器,挂载 mongo 容器的所有 volumes,然后读取 /backup 目录中的备份文件,解压到 /data/ 目录
docker run --rm --volumes-from mongo -v d:/backup:/backup ubuntu bash -c "cd /data/ && tar xvf /backup/backup.tar --strip 1"
本质就是将压缩包解压回容器中的
/data下–strip 1 表示解压时去掉前面1层目录,将文件提取到当前目录而不是保留原始目录结构
CMD与ENTRYPOINT
CMD示例
1 | FROM ubuntu |
运行时:
1 | docker run myimage |
ENTRYPOINT示例
强制执行固定命令
1 | FROM ubuntu |
运行时:
1 | docker run myimage |
CMD 和 ENTRYPOINT 组合
1 | FROM ubuntu |
运行结果:
1 | docker run myimage |
使用 ENTRYPOINT 制作工具化容器
工具型容器常用 ENTRYPOINT 设计成不可替换的行为。例如:
制作 curl 工具容器
1 | FROM curlimages/curl |
运行时:
1 | docker run mycurl -X GET https://example.com |
Alias创建别名
1 | alias mytool="docker run --rm -v $(pwd):/data my-image" |
添加到 ~/.bashrc 或 ~/.zshrc 中,使其在每次启动终端时生效。
如果经常使用docker容器中的命令,也可以创建一个函数来简化操作,如:
1 | binarychat() { |
一个C++开发环境的Dockerfile
Dockerfile -> 镜像 ->容器
编写Dockerfile
目录下新建Dockerfile文件
1 | # 基础镜像 |
构建镜像
执行下面命令构建docker镜像
docker build -t 镜像名 .
docker build: 这是 Docker 命令的一部分,用于构建 Docker 镜像。
-t 镜像名: -t 参数用于指定构建的镜像的标签(tag)。可以根据需要自行更改。.: 这表示 Dockerfile 的路径,.表示当前目录。Dockerfile 是一个包含构建指令的文本文件,它定义了如何构建 Docker 镜像。
使用这个命令,您可以在当前目录中的 Dockerfile 中定义的环境中构建一个名为 镜像名 的 Docker 镜像。Docker 将按照 Dockerfile 中指定的指令执行构建过程,并生成一个可用的镜像。
确认镜像构建成功: docker images 如果可以看到前面指定的镜像名,则构建成功
容器中运行镜像
在容器中运行镜像: docker run --name cpp_tutorials_container -v /Users/hejun/project/cpp_tutorials:/cpp_tutorials -it 镜像名
docker run: 这是 Docker 命令的一部分,用于在容器中运行镜像。--name 容器名:--name参数用于指定容器的名称。可以根据需要自行更改。-v /Users/hejun/project/cpp_tutorials:/cpp_tutorials:-v参数用于将主机的目录(/Users/hejun/project/cpp_tutorials)与容器内部的目录(/cpp_tutorials)进行挂载(映射)。这样可以在容器内访问主机上的文件和目录。这使得容器内的操作可以访问主机上的文件和目录,方便在开发环境中共享和处理代码。
-it: -i 和 -t 参数一起使用,以交互模式运行容器,并分配一个终端(TTY)以便与容器进行交互。镜像名: 这是要运行的镜像的名称。 使用这个命令,您可以在一个新的容器中运行名为指定镜像名的镜像。容器将会创建,并在交互模式下启动,您可以在容器的终端中执行命令和操作。
查看容器
docker ps
进入正在运行的容器
docker start -i 容器名
运行docker配置项
Ports左边为在宿主机上访问的端口,右边一般不需要填写,因为这是应用程序默认暴露的端口Volumes卷,可以将容器的目录挂到容器的应用目录下,通常:如果是使用这种方式,修改文件可以立即生效,最多也就是重启容器就可以生效
- Host path 本地的路径
- Container path 容器内的路径
Environment variables环境变量,表示可以配置docker环境中的环境变量注意,环境变量的设置需要停止并删除现有容器,然后重新创建容器
- Variable 环境变量的名
- Value 环境变量的值
K8S
Docker Compose和Kubernetes(通常简写为k8s)都是用于容器编排的工具,但它们的用途不同,适用于不同的环境。
- Docker Compose是一个工具,允许您定义和运行多个容器的Docker应用程序。它主要用于开发和测试环境,您需要在单个主机上运行多个互连的容器。Docker Compose使用YAML文件定义应用程序所需的服务、网络和卷。
- Kubernetes是一个容器编排平台,自动化部署、扩展和管理容器化应用程序。它设计用于生产环境,在这种环境中,您需要在一个机器集群上运行容器。Kubernetes提供自动扩展、自愈和滚动更新等功能,以确保应用程序的可靠性和可扩展性。
- Docker Compose更适用于本地开发和测试
- Kubernetes更适用于在生产环境中部署和管理容器化应用程序。





