Docker 初体验
Docker 初体验
经常在各个地方看到 Docker,关于什么是 Docker,官方文档已经给了专业详尽的解释,个人粗浅的理解是它不仅将应用程式,还将应用程式所需要的环境和各种依赖一起打包成了一个盒子,当我们使用这个应用程式时,直接“打开”盒子就能用,不需要本机电脑再安装配置什么,因为需要的东西盒子里已经都有了。
那这样有什么用呢?对于个人开发者来说,假如设备同时运行着几个项目,而这些项目所需要的环境各有不同,如果不用 Docker,可能就会相互冲突了。
而对于公共项目来说,假如一个用户数量庞大的公共项目,每个人的设备各有不同,有的安装了 A 的这个版本,有的安装了 B 的那个版本,有的只安装了一部分,怎么保证这个项目能在所有设备上正常平稳地运行呢?直接连同所用的环境打包成 Docker 是个不错的选择。
由于 Docker 能够轻松地封装应用程序和其依赖项,所以大大方便并简化了应用程序的部署和使用。
◇ Docker 的用途
Docker 的主要用途,目前有 3 大类:
- 提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
- 提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
- 组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
◇ Windows 精简版初体验
官方推荐 Windows 安装 Docker Desktop,因为安装包有点大,旧电脑磁盘空间有些告急,所以先通过 Scoop 下载体验一下。
注意: 通过此方法下载的程序只包含用于 Windows 容器的 Docker CLI 和 Docker Engine。仅支持运行 Windows 容器,可以通过下载镜像连接到现有的 Linux 容器。建议直接采用官方的推荐安装 Docker Desktop,功能更全,也方便添加拓展等。
▷ 安装
1 |
|
▷ 注册服务
安装完毕后,输入 dockerd --register-service
命令,注册服务。发现访问被拒绝,这是因为 Docker 需要用户具有管理员权限。
1 |
|
重新用 sudo
命令输入,没有返回报错,说明已经成功了。
1 |
|
dockerd
是 Docker 守护程序,是在后台运行的服务,负责管理 Docker 容器。当在 Windows 系统上运行该命令时,会将 Docker 守护程序注册为一个 Windows 服务。
将 Docker 守护程序注册为服务意味着在 Windows 系统启动时,Docker 将自动启动,而不必每次登录或系统重新启动时手动启动它。
💡 如果需要取消注册服务,可以通过以下命令来完成:
1 |
|
▷ 启动服务
为了避免每次命令都输入 sudo
,可以以管理员身份开启窗口。(或者将当前用户加入 Docker 用户组,参见:将用户加入 Docker 用户组)
接下来输入 start-service docker
命令启动 Docker 引擎,但发现启动服务失败了。
1 |
|
使用快捷键 win
+x
,选择并打开 “事件查看器” (Event Viewer)。
找到关于 Docker 的错误信息,显示:
fatal: failed to start daemon: failed to load vmcompute.dll, ensure that the Containers feature is installed
如图所示:
上面的信息显示当 Windows 尝试启动 Docker 守护程序 (Docker daemon) 时,无法加载 “vmcompute.dll”。这通常是由于缺少或损坏了 Windows 容器所需的组件,或者没有正确安装 Windows 容器功能引起的。
打开 “Windows 功能”,发现 “Windows 容器” 确实没有开启,所以需要勾选该选项,点击确认后电脑需要重启。
重启之后再运行上面的命令,没有返回错误信息,表明启用成功了。
1 |
|
💡 如果需要停止服务,可以通过以下命令来完成:
1 |
|
▷ 测试
安装完成后我们可以通过运行 hello-world
镜像来验证 Docker 是否已正确安装:
1 |
|
nanoserver
是指示使用 Windows Nano Server 基础镜像的版本。Windows Nano Server 是一种轻量级 Windows Server 镜像,适用于 Windows 容器。
结果又返回了错误信息:
1 |
|
查询得知 Windows 容器需要 Hyper-V 技术来提供虚拟化支持,打开 “Windows 功能”,发现果然没有开启,于是勾选该选项,勾选后需要重启电脑。
重启之后再运行上面的命令,发现终于可以成功运行了。显示如下:
1 |
|
▷ 将用户加入 Docker 用户组
为了避免每次命令都使用管理员身份,可以把用户加入 Docker 用户组。
- 创建组并添加用户
先创建一个用户组,组名可以自定义,我这里直接命名为 “docker”。管理员身份运行以下命令:
1 |
|
然后将当前用户加入这个组:
1 |
|
💡 如果想要移除用户组或组里的用户,可以使用以下命令:
1 |
|
- 配置用户组的 Docker 访问权限
Docker Desktop 和 Linux 平台似乎已经配置好了,直接创建特定组 (Docker Desktop for Windows 名为:docker-users
;Linux 平台名为:docker
) 并添加用户即可。
但是这个精简版并没有啊!刚才创建的组 Docker 其实并不认识。而网上全是关于 Docker Desktop 和 Linux 的教程,最后本人好不容易在 “Windows 容器” 的官方文档中找到了配置的方法。
首先创建配置文件 C:\ProgramData\Docker\config\daemon.json
,然后打开文件,输入以下内容,设置 Docker 安全组:
1 |
|
设置好后,重启 Docker 服务:
1 |
|
然后再去普通用户窗口输入 docker 命令,发现已经不报错了:
⚠ 如果还是报错,显示没有权限,重新登录用户或者重启一下设备,用来刷新用户的组员资格,使其生效。
1 |
|
▷ 其它配置
Windows 中 image
、container
等文件默认保存在 c:\programdata\docker
,因为本人的旧电脑 C 盘已爆满,所以需要修改一下保存路径。
打开配置文件 C:\ProgramData\Docker\config\daemon.json
,新增内容:
1 |
|
注意每个配置项末尾需要以 ,
分割,最后一项不需要加。
设置好后,重启 Docker 服务:
1 |
|
▷ 卸载方法
先记录一下卸载大致流程:
1 |
|
◇ 命令相关
1 |
|
1 |
|
1 |
|
1 |
|
◇ 项目实例
▷ sub-web
先前使用过的 sub-web 项目正好也有 Docker 版,之前是下载源码使用的 (参见:链接),现在来看看 Docker 部署的方法。
- 部署
> 直接部署
可以直接下载项目官方的 Docker 镜像进行部署:
1 |
|
一些参数解释:
-d
:让容器在后台运行,启动后会立即恢复到本机命令提示符。-p 58080:80
:将主机的 58080 端口映射到容器的 80 端口,即可以通过主机 http://localhost:58080 访问运行在容器中的 web 服务。--restart always
:始终自动重启。--name subweb
:自定义容器名称为“subweb”。careywong/subweb:latest
:拉取镜像的仓库、名称和版本。
> 自定义部署
如果有自定义需求,需要下载源码修改,然后自行打包生成镜像再运行:
(但是不推荐这种方法,不方便维护,推荐使用后面自动构建的方法,参见:链接)
1 |
|
一些参数解释:
docker build
:构建一个新的 Docker 镜像。-t subweb-local:latest
:指定构建的镜像的名称和标签。.
:构建镜像所需的 Dockerfile 文件的目录,这里表示当前目录。
- Dockerfile
上面提到的 “Dockerfile” 是一个文本文件,包含构建 Docker 镜像所需的指令和配置。本项目的 Dockerfile 文件内容如下:
1 |
|
上面的文件采用了 Docker 多阶段构建 (multi-stage build) 的方法,这种方法可以用来优化镜像的大小和性能。
在上面的例子中,第一个阶段(build)用于构建应用程序,第二个阶段用于构建 Nginx 服务器的镜像。
下面详细解释一下它的含义:
1 |
|
FROM
指定了第一个构建阶段的基础镜像。它使用了 Node.js 16
的 Alpine Linux
版本,并将其命名为 “build”,以便在后续引用中使用。
Alpine Linux 是一种轻量级的 Linux 发行版,专注于提供最小的系统资源消耗,同时具备强大的安全性和可定制性。大多数 Docker 项目也基于此版本。
1 |
|
设置容器工作目录为 /app
,然后将当前目录中的所有文件复制到容器的工作目录中。
💡 如果有需要排除的文件,可以在当前目录新增 .dockerignore
文件,然后填写需要排除的路径,类似 Git 中的 .gitignore
文件。
1 |
|
使用 Yarn
安装项目的依赖包,然后进行构建,从之前搭建的经验可以得知,构建生成的内容将会在 /dist
目录。
1 |
|
此时来到了镜像构建的第二阶段,FROM
指定了第二个构建阶段的基础镜像,即 Nginx 1.24
的 Alpine Linux
版本。
Nginx 是一个开源的高性能、轻量级的 Web 服务器和反向代理服务器软件,能够将客户端的请求转发到多个后端服务器上,可用于托管网站和 Web 应用程序。
1 |
|
从第一个构建阶段 “build” 阶段复制生成文件到 Nginx 容器中的 /usr/share/nginx/html
目录,这将配置 Nginx 以显示生成的前端页面。
1 |
|
EXPOSE
指定容器侦听的端口,这里是 80。
然后通过 CMD
指定容器启动时要运行的命令:nginx -g daemon off;
。
其中 daemon off;
是 -g
选项后面的参数,表示让 Nginx 以前台进程运行,以确保容器保持运行状态。
在 Docker 容器中运行服务时,通常推荐让服务以前台进程运行。这是因为 Docker 的最佳实践是一个容器只运行一个进程。当这个进程退出时,容器也就结束了。
如果 Nginx 以后台进程 (即守护进程) 运行,那么在 Nginx 启动后,启动命令就立即结束了,Docker 会认为服务已经结束,于是就会关闭容器。
因此,我们需要通过 daemon off;
指令让 Nginx 以前台进程运行,这样 Docker 容器就会一直运行,直到 Nginx 服务结束。
普通情况下,Nginx 以后台守护进程的方式运行,但在 Docker 容器中,以非守护进程模式运行更为常见,以便容器保持运行状态。
- 自动构建镜像
如果有自定义需求,修改源码本地构建肯定是不方便的,我们可以利用 GitHub Actions 来实现自动构建 Docker 镜像并实时发布到 Docker Hub,这样部署的时候直接拉取我们在 Docker Hub 自定义的镜像即可。
本项目的 Docker 构建工作流文件如下:
1 |
|
这个工作流文件主要分为 4 个步骤:
首先通过官方的 actions/checkout
从当前的GitHub仓库中检出代码。
然后通过 Docker 官方的 docker/setup-buildx-action
来设置 Docker Buildx,一个用于构建多架构的 Docker 镜像的工具。
之后需要登录 Docker Hub,登录所需的用户名和密码通过 GitHub Secrets 提供,需要在仓库的 Settings
> Secrets and variables
> Actions
> new repository secret
按照上面的名称新建 2 个变量,一个是 Docker 账号的用户名,一个在 Docker 账户生成的 token,用于登录。如下图所示:
最后通过 docker/build-push-action
来构建和推送 Docker 镜像:
context: .
:表示构建上下文是当前目录,即代码库的根目录。platforms: linux/amd64,linux/arm64
:指定要构建的目标平台,这里构建了两个架构的镜像,分别是 x86_64 (amd64) 和 ARM64。push: true
:表示构建后将镜像推送到 Docker Hub。tags: careywong/subweb:latest
:指定了要构建的镜像的名称和标签。这里需要修改为自己的名称,如<user_name>/sub-web:latest
。
修改完成后将代码推送至远程仓库,Action 会自动运作,将构建好的镜像推送至自己的 Docker Hub:
之后我们便可在任意设备下载自己的镜像进行部署:
1 |
|
◇ 参考内容
- Failed to Start Docker Service on Windows 10 AE. https://dscottraynsford.wordpress.com/2016/08/04/failed-to-docker-service-on-windows-10-ae/
- Install Docker Engine from binaries. https://docs.docker.com/engine/install/binaries/
- Error response from daemon: hcsshim::CreateComputeSystem. https://github.com/microsoft/navcontainerhelper/issues/811
- Running any Windows container returns: docker: Error response from daemon: hcsshim::CreateComputeSystem …: The request is not supported. #227. https://github.com/microsoft/Windows-Containers/issues/227
- Docker for Windows - Access Denied #868. https://github.com/docker/for-win/issues/868
- Windows 上的 Docker 引擎. https://learn.microsoft.com/zh-cn/virtualization/windowscontainers/manage-docker/configure-docker-daemon#configure-docker-on-the-docker-service
- Docker 入门教程. https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html