0. 背景
0.1 虚拟化技术的弊端
随着硬件的大力发展,除了运行一些大型软件之外,大部分情况硬件都处于空闲状态。除此之外,在一些特殊的开发情况下,可能需要使用不同版本的环境进行测试。有些甚至不能使用 Windows 系统,必须使用 Linux 系统。虽然 Windows 已经推出 Linux 的子系统——WSL,但是在不同环境之间的切换是个很大的问题,特别是在一台电脑上配置多环境的情况下。
这样硬件虚拟化技术就出现了,让用户能以单个物理硬件系统为基础创建多个模拟环境或专用资源。称为“Hypervisor” (虚拟机监控程序)的软件可直接连接到硬件,从而将一个系统划分为不同的、单独安全环境,即虚拟机(VM)(也可以称为,Guest OS)。这样我们就能从原有的系统中分配出多个可监控的,安全的子系统。
+-----+-----+-----+-----+
|App A|App B|App C|App D|
+-----+-----+-----+-----+ +-----+-----+-----+-----+
|App A|App B|App C|App D| |Guest|Guest|Guest|Guest|
+-----+-----+-----+-----+ | OS0 | OS1 | OS2 | OS3 |
|Guest|Guest|Guest|Guest| +-----+-----+-----+-----+
| OS0 | OS1 | OS2 | OS3 | | Hypervisor |
+-----+-----+-----+-----+ +-----------------------+
| Hypervisor | | Host OS |
+-----------------------+ +-----------------------+
| Hardware | | Hardware |
+-----------------------+ +-----------------------+
Type I Type II
Type I 是 Hypervisor 直接访问硬件资源,通常会有另一个操作系统运行于 Hypervisor 之上来对硬件资源,例如 VMware EXSi,Windows的Hyper-V,Linux 的 Xen;Type II 是 Hypervisor 和普通的应用一样,运行在某个操作系统(例如 Windows 或者 Linux 等,这里称之为宿主机操作系统,Host OS)之上,Hypervisor 通过 Host OS 访问硬件资源,例如 VMware Workstation,Virtual Box。
虚拟机的一个缺点在于 Guest OS 通常会占用不少硬件资源,并且性能损失的情况也比较严重。虽然不少 Hypervisor支持 动态内存,但基本上都会降低虚拟机的性能。如果说这样的资源占用少量的虚拟机还可以接受的话,同时运行十数台数十台虚拟机的时候,浪费的硬件资源就相当可观了。通常来说,其中相当大部分甚至全部 Guest OS 都是相同的。
0.2 Docker 问世
+-----+-----+-----+-----+ +-----+-----+-----+-----+
|App A|App B|App C|App D| +-----+-----+-----+-----+ |App A|App B|App C|App D|
+-----+-----+-----+-----+ |App A|App B|App C|App D| +-----+-----+-----+-----+
|+---------------------+| +-----+-----+-----+-----+ |Guest|Guest|Guest|Guest|
|| Runtime Library || |Lib A|Lib B|Lib C|Lib D| | OS0 | OS1 | OS2 | OS3 |
|+---------------------+| +-----+-----+-----+-----+ +-----+-----+-----+-----+
|| Kernel || | Container Engine | | Hypervisor |
|+---------------------+| +-----------------------+ +-----------------------+
| Operating System | | Host OS | | Host OS |
+-----------------------+ +-----------------------+ +-----------------------+
| Hardware | | Hardware | | Hardware |
+-----------------------+ +-----------------------+ +-----------------------+
Physical Machine Container Type II Hypervisor
上图中,每一个App和Lib的组合,就是一个容器。也就是Docker图标里面的一个集装箱。和虚拟机相比,容器有以下优点:
- 迅速启动:没有虚拟机硬件的初始化,没有Guest OS的启动过程,可以节约很多启动时间,这就是容器的“开箱即用”;
- 占用资源少:没有运行Guest OS所需的内存开销,无需为虚拟机预留运行内存,无需安装、运行App不需要的运行库/操作系统服务,内存占用、存储空间占用都小的多。相同配置的服务器,如果运行虚拟机只能运行十多台的,通常可以运行上百个容器毫无压力——当然前提是单个容器应用本身不会消耗太多资源。
当然,因为 Docker 公用内核的原因,只靠 cgroup 隔离,如果某一个容器导致内核崩溃,那么所有的容器都会崩溃。而对于彻底隔离应用的虚拟机,除非硬件或者 Hypervisor 出现问题,否则不会出现崩溃的问题。
当然如果还是不懂,可以拿别墅、公寓和胶囊式公寓类比(bushi)。
0.3 Docker 特性
有人说,Docker 的出现就像集装箱一样,所谓的穿着马甲的“标准化”。想要搞懂 Docker,需要明白它的两句口号。
Build, Ship and Run 搭建、发送、运行三板斧
Build once,Run anywhere 一次构建,随处运行
从这个口号我们就能够得到几个信息:
- 使用 Docker 时候,我们就可以避免配置文件的问题;
- 我们可以构建自己的镜像,并且将其打包到 Docker hub 上。这样别人就可以使用你的镜像了;
- 运行的容器可以随时进行更改或者停止。
Docker 技术的核心概念分别是
镜像(Image)别人存放好文档/环境的地方,只需要在 Docker hub 搜索并且下载,就即将可以使用。和 GitHub 共享代码类似,别人也会共享自己配置的镜像;
容器(Container)实现具体操作程序的地方,将本地的镜像放在容器中运行;
仓库(Repository) 自己本地下载别人的镜像,也可以把自己打包的镜像上传到 Docker hub。
就以运维中举例,我们可能会看到多种语言写出来的各种各样的东西,并且可能还有历史遗留的不同版本导致的错误。
这个时候,标准化管理显得尤其重要,这个时候就需要一个统一的操作方法。就算你只用 PHP/Java 写程序,PHP/JDK 的版本不同,加上 SQL 的不同,使用容器的不同,Nginx 或者 Apache,甚至有不知名的 Web 容器,还有自己写的 Web 容器。这样你就不可能在原生的 Linux 服务器中管理多个版本的环境。
1. Docker 镜像
在 Linux 上运行 Docker 需要 root 权限,千万注意。除此之外,Docker 是在外网的服务器上,所以需要进行换源,具体可以参考这个网站。
+---------+ +---------+ +---------+ +-----+ +-----+ +-----+
| abc.com | | def.com | | xyz.com | | DB1 | | DB2 | | DB3 |
+----+----+ +----+----+ +----+----+ +--+--+ +--+--+ +--+--+
| | | | | |
+----+----+ +----+----+ +----+----+ +--+--+ +--+--+ +--+--+
| abc.com | | def.com | | xyz.com | | DB1 | | DB2 | | DB3 |
| config | | config | | config | | conf| | conf| | conf|
| data | | data | | data | | data| | data| | data|
+----+----+ +----+----+ +----+----+ +--+--+ +--+--+ +--+--+
| | | | | |
+------------+------------+ +-------+-------+
| |
+------+------+ +------+------+
| Nginx Image | | MySQL Image |
+------+------+ +------+------+
| |
+----------------+----------------+
|
+------+-------+
| Alpine Image |
+------+-------+
从这里我们可以看到,Docker 的镜像可以在某个基础上再进行分装,对于我们使用 jar 包项目,我们可以使用 Dockerfile 进行配置。下面的内容会有说到如何使用 Dockerfile 打包一个 Java 项目。
1.1 拉取镜像
我们可以使用pull
命令对一个镜像进行拉取
对于同一个镜像,都有一个 tag 对其进行区分,一般都是作为不同版本的管理。对于官方镜像。如果没有指定拉取的 tag,则会默认为 latest。
#默认会拉取最新版本的镜像
docker pull ubuntu
Using default tag:latest
#拉取18.04版本的 ubuntu
docker pull ubuntu:18.04
pull 命令中存在的子选项:
-a:是否获取仓库中的所有镜像,默认为否;
–disable-content-trust:取消镜像的内容校验,默认开启。
1.2 查看镜像
对于已经下载下来的镜像,我们可以使用docker images
进行查看。
images 命令存在的子选项:
-a:列出所有的镜像文件(包括临时文件),默认为否;
-q:仅输出 ID 信息,默认为否;
-f:过虑列出的镜像。
如果我们需要特别使用某个镜像,可以使用docker tag
命令为本地镜像任意添加新的标签。
如果你需要一个镜像的具体信息,可以使用docker inspect
,会显示出包括创建时间、仓库 ID 等详细信息。
docker inspect ubuntu
#result
[
{
"Id": "sha256:54c9d81cbb440897908abdcaa98674db83444636c300170cfd211e40a66f704f",
"RepoTags": [
"chenxinyang621/ubuntu:0.1",
"myubuntu:0.1",
"ubuntu:latest"
],
"RepoDigests": [
"chenxinyang621/ubuntu@sha256:7c9c7fed23def3653a0da5bc9ecb651efe155ebd5802c7ba5d585edaa6c89496",
"ubuntu@sha256:669e010b58baf5beb2836b253c1fd5768333f0d1dbcb834f7c07a4dc93f474be"
],
"Parent": "",
"Comment": "",
"Created": "2022-02-02T02:14:46.177066251Z",
"Container": "3d4cc5cf7dc1af55a2be4440b5be4f96ea35516b98407a9b9446c218bb43818a",
"ContainerConfig": {
"Hostname": "3d4cc5cf7dc1",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"bash\"]"
],
"Image": "sha256:b7032458728a84cd355ae42a8f7b323e29af86a22b211f4701363191b25fa805",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.7",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"bash"
],
"Image": "sha256:b7032458728a84cd355ae42a8f7b323e29af86a22b211f4701363191b25fa805",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 72775208,
"VirtualSize": 72775208,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/2438f9a3ea62d8d4b5f545240e0f21d299807845882f742eddf9042276e618b0/merged",
"UpperDir": "/var/lib/docker/overlay2/2438f9a3ea62d8d4b5f545240e0f21d299807845882f742eddf9042276e618b0/diff",
"WorkDir": "/var/lib/docker/overlay2/2438f9a3ea62d8d4b5f545240e0f21d299807845882f742eddf9042276e618b0/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:36ffdceb4c77bf34325fb695e64ea447f688797f2f1e3af224c29593310578d2"
]
},
"Metadata": {
"LastTagTime": "2022-03-04T05:21:55.8145906Z"
}
}
]
1.3 搜索镜像
当然,我们可能需要确认我们需要的工具是否存在对应的 Docker 镜像,这个时候就要使用docker search
。
search 的子选项:
-f:过滤输出内容;
–limit:限制输出结果个数,默认为25个;
–no-trunc:不截断输出结果。
#查询所有 nginx 有关的镜像
docker search nginx
#限制查询10个
docker search --limit 10 nginx
#只查询官方的 nginx 镜像
docker search -f is-official=true nginx
1.4 删除镜像
镜像删除使用docker rmi/docker image rm
命令。当然如果是在 Windows 上的 Docker 已经提供可视化操作平台,但是我们还是要了解对应的命令。
不管是对于之后的容器删除还是现在的镜像删除,都有两种删除方式:
- 使用名称(+标签)删除。每个容器和镜像都有对应的名称,可以使用这个进行区分并进行删除;
- 使用 ID 删除,ID 是唯一值,所以使用 ID 也能进行删除操作(P.S. 可以不用输入完整 ID,只要能辨别出是唯一值即可)。
rmi 的子选项:
-f:强制删除镜像,即使存在容器依赖;
-no-prune:不清理未带标签的父镜像。
对于一些没有被使用的镜像,以及产生的残留临时镜像文件,可以使用docker image prune
进行清除。
prune 的子选项:
-a:删除所有无用镜像,不只是临时镜像;
-filter:对清理对象进行过滤;
-f:强制删除镜像,不进行提示确认。
2. Docker 容器
如果认为虚拟机是模拟运行的一整套操作系统(包括内核 应用运行态环境和其他系统 环境)和跑在上面的应用 那么 Docker 容器就是独立运行的一个(或一组)应用,以及它们 必需的运行环境
2.1 简单的例子
Docker 允许你在容器内运行应用程序, 使用docker run
命令来在容器内运行一个应用程序(容器)。当然run
其实包含了一个create
命令用来创建一个新的容器。
docker run ubuntu /bin/echo "Hello world"
Hello world
# 存在镜像之后,就不需要指定版本了
docker run ubuntu /bin/echo "Hello world"
docker: Docker 的二进制执行文件
run: 与前面的 Docker 组合来运行一个容器
ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像
/bin/echo “Hello world”: 在启动的容器里执行的命令
2.2 启动容器
#先拉取一个 ubuntu 的镜像
docker pull ubuntu
#创建一个新的容器
docker create --name ubuntu1 -it ubuntu
#运行容器
docker start ubuntu1
#创建并运行一个容器
docker run --name ubuntu2 -it -d --restart=always ubuntu
-t:在新容器内指定一个伪终端或终端;
-i:允许你对容器内的标准输入 (STDIN) 进行交互;
–name:指定容器的名称,否则 Docker 会随机生成一段字符串;
-d:让容器在启动在启动时在后台运行;
–restart=always:设置容器随着 Docker 自启动。
之后我们可以使用 Ctrl+d/exit/Ctrl+w+d 退出容器,回到宿主机中。
2.3 停止容器
可以使用docker pause
来暂停一个运行中的容器,使用docker pause
来解除暂停一个运行中的容器。
如果需要终止一个容器,我们使用docker stop
。
docker ps -a
让我们可以查看所有容器(默认只能查看运行中的容器);docker ps -qa
只会显示 ID。
2.4 进入容器
有些时候我们需要进入容器修改一些设置,或者进行一些操作,我们需要使用exec
#参数的设置
docker exec -it ubuntu1 bash
-e:指定环境变量列表(在 MySQL Docker 配置中会有用到);
-u:执行明的用户名或 ID。
2.5 网络端口映射
在运行容器的过程中,我们需要对其绑定一个端口(Redis/MySQL/MinIO 的 Docker 操作就必需要这个步骤)
- -P :**是容器内部端口随机**映射到主机的高端口;
- -p :**是容器内部端口绑定到指定**的主机端口。
在绑定端口之前,还可以指定需要映射的地址,比如主机的127.0.0.1。
docker port
命令可以让我们快捷地查看端口的绑定情况(绑定的端口默认都是 TCP,可以在后面使用 /UDP 绑定为 UDP )。
2.6 解决 docker ps 折行问题
docker ps 默认的显示内容过多,当值过长时就会导致折行,可读性很差,所以希望只显示自己关心的某些列。
可以自己指定显示的模板,例如:
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"
可用的占位符:
名称 | 含义 |
---|---|
.ID | 容器ID |
.Image | 镜像ID |
.Command | 执行的命令 |
.CreatedAt | 容器创建时间 |
.RunningFor | 运行时长 |
.Ports | 暴露的端口 |
.Status | 容器状态 |
.Names | 容器名称 |
.Label | 分配给容器的所有标签 |
.Mounts | 容器挂载的卷 |
.Networks | 容器所用的网络名称 |
3. 配置 VSCode 访问 Docker
3.1 远程 ssh 连接
首先需要安装一个 remote ssh 插件,之后在侧边栏中选择进行连接。
3.2 访问拒绝
因为 Docker 需要 root 身份进行访问,所以正常使用 Docker 插件会出现权限问题。网上提供的方法大多数是开放 root ssh 权限,但这是非常非常危险的行为,特别是放置在公网上的云服务器。
这个时候可以将普通用户添加到 Docker 组中,之后重启服务器,即可访问。
sudo groupadd docker #添加docker用户组
sudo gpasswd -a $USER docker #将当前用户添加至docker用户组
newgrp docker #更新docker用户组
4. Docker Compose
4.1 配置 Compose
安装最新的 Docker Compose,版本截止至2022.4.5
(使用国内镜像源下载):
curl -L https://get.daocloud.io/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
添加可执行权限:
sudo chmod +x /usr/local/bin/docker-compose
创建软链:
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
#检测是否安装成功
docker-compose --version
4.2 Dockerfile 配置
需要注意的是,每一次的执行都会创建一个新的层,过多的命令就会导致过多的层数,使得镜像过于膨胀。
#定制的镜像都是基于 FROM 的镜像,第一行必须
FROM **
#作者和邮箱
MAINTAINER ** <**@**>
# VOLUME 指定了临时文件目录为 /tmp,防止重要数据丢失
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
#指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在
#因为 docker build 构建镜像每一个命令都是一层,除了通过 workdir 定义
WORKDIR /app
#把项目中的所有东西都复制到工作目录下面
COPY . .
# 将 jar 包添加到容器中并更名为 app.jar(按照 SpringBoot 构建方式为例)
# add 的功能和 copy 类似(在相同的需求下,官方更推荐 copy)
ADD target/*.jar /app/app.jar
#改变容器时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' >/etc/timezone
#比使用两次 run 命令少一层构建
#仅仅只是声明端口
EXPOSE 10000
#也可以使用 cmd 命令
#如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。ENTRYPOINT 同理
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
#这里的参数表示 `可执行命令`...`各个参数`
run
和cmd
的区别在于,前者是 docker build 过程中执行的命令,后者是 docker run 的时候执行的命令。
ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
(entrypoint 可以搭配 cmd 使用,相当于 cmd 给 entrypoint 传参。)
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
转换成命令,相当于docker run nginx:test -c /etc/nginx/new.conf
。
4.3 yaml 解释
version: "3.7"
services:
example: #服务名称
image: tomcat:8.0-jre8 #使用的镜像
container_name: example_container_name #容器启动时的名字
ports: #容器端口映射,前面的是宿主机端口,后面是容器内端口
- "8080:8080"
volumes: #容器中的哪个路径和宿主中的路径进行数据卷映射
- /root/apps:/usr/local/tomcat/webapps #手动映射
- tomcatwebapps:/usr/local/tomcat/webapps #自动创建数据卷映射,需要在后面声明数据卷
networks: #指定容器启动使用的网桥
- aa
command: xxxxx #用于覆盖容器默认启动指令
envoriment: #指定容器启动时的环境参数
- xxxxx=xxxx
#env_file: 使用环境变量文件,书写格式和环境参数相同
# - ./xxx.env
depends_on: #设置这个服务依赖的服务名称(即启动优先级)
#可以关联其他的服务
- xxxxx
#sysctls: #修改容器内部参数
# - xxxx=xxxx
volumes:
tomcatwebapps:
#external: 默认卷名会带上项目名(yml文件所在文件夹名),
# true 可以声明使用外部以存在的卷
networks:
aa: #创建逻辑同volume,将不同服务关联到一个网桥
4.4 示例
整体架构如下,Dockerfile 和 docker-compose.yml 放在同一层目录:
.
`-- freshcup
|-- data
| |-- mysql
| | `-- initsql
| | `-- freshcup.sql
| `-- redis
| `-- conf
| `-- redis.conf
|-- docker-compose.yml
|-- Dockerfile
`-- freshcup.jar
Dockerfile 的写法如下:
FROM openjdk:11
MAINTAINER cxy621 <cxyphp@gmail.com>
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
WORKDIR /app
COPY . .
ADD target/*.jar /app/app.jar
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
EXPOSE 10000
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
docker-compose.yaml 配置如下:
version: "3.7"
services:
freshcup: #自己写的 web 服务
build: #根据指定的 dockerfile 构建镜像
context: . #指定 dockerfile 所在目录作为docker构建镜像的context环境
dockerfile: Dockerfile #指定 dockerfile 的文件,默认为 Dockerfile
container_name: test_spring
ports:
- "10000:10000"
networks:
- freshcup
depends_on:
- mysql
- redis
mysql:
image: mysql:latest
container_name: test_mysql
ports:
- "10001:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=123456
volumes:
- ./data/mysql/initsql:/docker-entrypoint-initdb.d #用于初始化 mysql 数据库
- ./data/mysql/db:/var/lib/mysql #mysql 数据文件挂载
- ./data/mysql/conf:/etc/mysql #mysql 配置文件挂载
- ./data/mysql/log:/var/log/mysql #mysql 日志文件挂载
networks:
- test_net
reids:
image: redis:latest
container_name: test_redis
ports:
- "10002:6379"
volumes:
- ./data/redis/db:/data #redis 数据文件挂载
- ./data/redis/conf/redis.conf:/etc/redis/redis.conf #redis 配置文件挂载
command:
- sh
- -c
- | #设置 redis 只读,并需要密码,
redis-server /etc/redis/redis.conf
redis-server --requirepass 123456
redis-server --appendonly yes
networks:
test_net:
在 idea 中配置好之后,执行就可以对此进行部署。
4.5 注意
如果 cmd 具有多个命令,不能直接通过 -
来执行,需要如下操作:
command:
- sh
- -c
- |
cmd1
cmd2
cmd3
#这是串行的方式,命令
5. Docker Machine
Docker Machine 可以当作一个 Docker 的虚拟机,可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker。可以运行在本地或者云服务平台比如腾讯云。
打开 git bash 进行操作:
# Linux 安装命令
base=https://github.com/docker/machine/releases/download/v0.16.0 &&
curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
chmod +x /usr/local/bin/docker-machine
# Windows 安装命令
base=https://github.com/docker/machine/releases/download/v0.16.0 &&
mkdir -p "$HOME/bin" &&
curl -L $base/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" &&
chmod +x "$HOME/bin/docker-machine.exe"
5.1 启动虚拟机
既然是虚拟机,那就需要一个虚拟机管理的系统作为 machine 的驱动,大部分的网站示例都是使用 ToolBox,我们这里使用 vmwareworkstastion。
在启动虚拟机时,实际上是从一个镜像文件中创建系统需要的文件,所以我们需要一个 ISO 文件放在C:\Users\<用户名>\.docker\machine\machines\cache
中,下载链接。
还需要一个驱动的 exe 文件,放在C:\Program Files\Docker\Docker\resources\bin
中,下载链接。
# 通过这个命令,创建一个名字为 test 的虚拟机
# 也可以使用 -d 参数
docker-machine create --driver vmwareworkstation test
# 通过 ls 查看我们目前已有的虚拟机
docker-machine ls
# 进入虚拟机内部
docker-machine ssh test
# 因为 docker 服务是在外网,我们需要提前换源
sudo vi /var/lib/boot2docker/profile
# 在 provider 下面一行输入以下内容(中科大源)
# 吐槽一句,国内某文章博客的横杠竟然是中文的,导致我换源失败……
--registry-mirror https://docker.mirrors.ustc.edu.cn/
sudo /etc/init.d/docker restart
# 换源之后查看 docker 配置文件信息
docker info
# 运行 hello-world 测试 docker 情况
docker run hello-world
这里需要注意一点,进入 docker 虚拟机修改的时候,可能会有显示错位的问题(显示的位置和实际修改的位置差两个空白符作为的距离),这一点需要注意。
5.2 坑点
如果在使用 vmwareworkstation 驱动时候,出现No default Boot2Docker ISO found locally
报错。说明是没有安装 Boot2Docker 的镜像文件,详细可以参考这篇文章的回答。
6. Docker Swarm
Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。
swarm 集群由管理节点(manager)和工作节点(work node)构成。
swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作;
work node:即图中的 available node,主要负责运行相应的服务来执行任务(task)。
6.1 构建主机
# 创建一个管理用的 docker 虚拟机
docker-machine create -d vmwareworkstation swarm-manager
# 使用 ssh 之后初始化 swarm 管理
# 使用的 ip 是创建之后虚拟管理系统分配的 ip
# 返回的结果是作为连接管理端和其他节点的重要命令,要保存好
docker swarm init --advertise-addr 192.168.114.134
# 创建两个 worker 作为测试,执行返回的命令,讲两个虚拟主机初始化为 manager 的节点
docker swarm join --token SWMTKN-1-4iyqlb1hkizqewx45wq8ixjqyysn39t7ouw808ybqq3gx4uo7n-93hhn1gh6fvqiojx8srkf9via 192.168.114.134:2377
6.2 测试服务
# 创建一个名为 helloworld 的服务
docker service create --replicas 1 --name helloworld alpine ping docker.com
# 查看特定服务的运行情况
docker service ps helloworld
# 查看服务的具体信息
docker service inspect --pretty helloworld
# 将服务扩展到两个节点
docker service scale helloworld=2
docker service rm helloworld
6.3 示例
给所有节点的服务拉取一个 redis 镜像:
docker service create --replicas 1 --name redis --update-delay 10s redis:3.0.6
# 将 redis 的版本滚动升级到最新的 latest
docker service update --image redis:latest redis
# 查看所有的节点
docker node ls
# 将 swarm-worker 激活
docker node update --availability active swarm-worker1
7. 启动错误
7.1 堆栈跟踪的末尾
仅限 Windows 平台的 Docker,原因是 wsl 2 内核出现问题,可能是在刚处于升级状态,暂时无法使用。
需要下载 NoLsp,之后执行 NoLsp.exe C:\Windows\System32\wsl.exe
,success 之后就可以正常使用 wsl 2。
参考文章
- 如何通俗解释 Docker 是什么?
- 通俗易懂,一文带你了解什么是虚拟化技术
- Docker 教程 菜鸟教程
- Docker 技术入门与实战
- Docker — 从入门到实践
- Docker 命令自动补齐
- docker ps 显示指定的列
- Docker 部署 SpringBoot 项目
- 使用 Docker 部署 SpringBoot
- VSCode 远程连接 Docker 容器
- VSCode 中 Docker 插件无法连接
- docker-compose command 执行多条指令
- Docker for Windows 使用 VMware WorkStation
- Docker Toolbox 修改镜像源
- Docker Swarm 集群环境搭建及弹性服务部署
- docker Error An error occurred 引发异常的上一位置中堆栈跟踪的末尾