Skip to main content

34.2 在 Docker 部署

精简发布文件

如果需要精简发布后的文件,也就是删除不必要的文件夹,可以编辑 Web 项目的 .csproj 并添加 <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>,如:

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
</PropertyGroup>

若无需生成 .pdb 文件,可以继续添加:

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>

34.2.1 关于 Docker

Docker 是一种开源的应用容器引擎,它使用容器(Container)技术来打包、分发和运行应用程序及其依赖。Docker 通过操作系统级虚拟化实现了轻量级的隔离,使得应用可以在几乎任何环境中以一致的方式运行,解决了“一次构建,到处运行”(build once, run anywhere)的问题。

总的来说,Docker 是一个强大的工具,它改变了应用程序的打包、分发和部署方式,使得应用程序的部署更加简单、快速和可靠。

官方网站:https://www.docker.com/

34.2.2 生成/编写 Dockerfile

Dockerfile 用于定义如何构建一个 Docker 镜像,这个镜像包含了应用程序运行所需的所有依赖和配置。通过这种方式,可以确保开发、测试和生产环境中的一致性,避免了“在我的机器上能运行”的问题。

34.2.2.1 使用 Visual Studio 生成(推荐)

Visual Studio 版本

在进行本小节内容之前,请确保您的 Visual Studio 已升级至最新版本,推荐使用 Visual Studio 2022 以获得最佳体验。

1. 选择项目启动层(YourProject.Web.Entry),通过鼠标右键->[添加]->[Docker 支持]

2. 选择容器基架构,强烈推荐选择 Linux,这样可以在任何操作系统(Windows/Linu/MacOS)中构建和运行。

3. 将 Dockerfile 移动(剪切)到解决方案目录,与 .sln 同级目录。

4. 编辑(双击项目名称)启动项 YourProject.Web.Entry.csproj 文件,并添加以下内容。

添加内容如下:

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
<UserSecretsId>5900e6ff-113c-4f08-a1e3-a608a9da52c0</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileFile>..\Dockerfile</DockerfileFile>
</PropertyGroup>

<ItemGroup>
<None Include="..\Dockerfile">
<Link>Dockerfile</Link>
</None>
</ItemGroup>

5. 点击运行测试

34.2.2.2 手动编写

手动编写 Dockerfile 是一件苦差事,这里提供了 .NET5-.NET8Dockerfile 模板。

1. 在解决方案目录,与 .sln 同级目录下创建 Dockefile 文件并写入对应的内容。

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["FurionApi.Web.Entry/FurionApi.Web.Entry.csproj", "FurionApi.Web.Entry/"]
COPY ["FurionApi.Web.Core/FurionApi.Web.Core.csproj", "FurionApi.Web.Core/"]
COPY ["FurionApi.Application/FurionApi.Application.csproj", "FurionApi.Application/"]
COPY ["FurionApi.Core/FurionApi.Core.csproj", "FurionApi.Core/"]
COPY ["FurionApi.Database.Migrations/FurionApi.Database.Migrations.csproj", "FurionApi.Database.Migrations/"]
COPY ["FurionApi.EntityFramework.Core/FurionApi.EntityFramework.Core.csproj", "FurionApi.EntityFramework.Core/"]
RUN dotnet restore "./FurionApi.Web.Entry/FurionApi.Web.Entry.csproj"
COPY . .
WORKDIR "/src/FurionApi.Web.Entry"
RUN dotnet build "./FurionApi.Web.Entry.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./FurionApi.Web.Entry.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "FurionApi.Web.Entry.dll"]

2. 编辑(双击项目名称)启动项 YourProject.Web.Entry.csproj 文件,并添加以下内容。

添加内容如下:

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
<UserSecretsId>5900e6ff-113c-4f08-a1e3-a608a9da52c0</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileFile>..\Dockerfile</DockerfileFile>
</PropertyGroup>

<ItemGroup>
<None Include="..\Dockerfile">
<Link>Dockerfile</Link>
</None>
</ItemGroup>

3. 点击运行测试


补充说明

除了通过 Dockerfile 实现 .NET 项目的完整编译、发布和运行流程外,还可以选择手动编译和发布项目,然后再编写 Dockerfile

例如,如果你已经手动将项目发布到了 D:/publish 目录下,你可以在该目录下创建一个 Dockerfile 文件,并写入以下内容:

# 对应你的 .NET 版本,这里是 6.0
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
EXPOSE 80
EXPOSE 443

COPY . .
ENTRYPOINT ["dotnet", "FurionApi.Web.Entry.dll"]

此方式的好处就是可以减少打包后的镜像大小。

34.2.3 构建 Docker 镜像

编写完 Dockerfile 之后,下一步就是构建 Docker 镜像。

构建镜像是将 Dockerfile 中的指令转化为一个可运行的容器镜像的过程。只有成功构建了镜像,才能进一步分享和运行容器。

通过执行 docker build 命令并指定 Dockerfile 的路径,Docker 会根据 Dockerfile 中的指令逐层构建镜像。

构建完成后,可以使用 docker images 命令查看已构建的镜像列表。之后,可以通过 docker run 命令启动容器,并在容器中运行应用程序或服务。

1. 在 Dockefile 所在的目录中打开 PowerShell/CMD,并按照以下命令格式构建:docker build -t 镜像名:版本号.

2. 使用 docker image ls 查看构建后的镜像

34.2.4 运行 Docker 镜像

有了 Docker 镜像后,我们便可以将镜像通过 docker run 运行起来,这时镜像将变成一个载体,也就是 Docker 中的容器(Container)。

通用格式为:docker run --name 容器名称 -p 本机端口:Dockerfile导出端口 --restart=always -d 镜像名:版本号

1. 运行镜像,运行之后变为了容器

docker run --name yourproject -p 8090:80 --restart=always -d your-project:1.0

2. 查看容器运行日志 docker logs 容器名

docker logs yourproject

3. 还可以进入容器内部系统 docker exec -it 容器名 bash

docker exec -it yourproject

进入系统后,我们可以直接编辑,拷贝,删除等操作。

34.2.5 分享(发布)你的镜像(hub.docker.com)

分享是一种值得称赞的品德,通过分享,我们的知识和资源得以更广泛的传播和应用。

Docker 生态系统中,我们可以将构建好的镜像分享到互联网平台,供其他人运行和使用。Docker 官方提供了一个名为 https://hub.docker.com(需科学) 的镜像仓库,供用户浏览、搜索和共享镜像。通过将镜像推送到这个平台,我们可以方便地将自己的应用或服务分享给全球的开发者和运维人员,促进技术的交流和合作。

34.2.5.1 为需要发布的镜像打上标签

在分享你的镜像之前,需要为你的镜像打上一个标签,也就是分享到 https://hub.docker.com 平台后显示的仓库地址。

通用格式:docker tag 本地镜像名:版本号 docker用户名/仓库名:版本号

docker tag your-project:1.0 monksoul/tests:1.0

34.2.5.2 登录/注册 hub.docker.com 平台

如果没有 Docker Hub 账号可先注册一个。https://hub.docker.com

可通过 docker login 进行登录。

退出/切换账号

可通过 docker logout 退出账号,如果是所有仓库,可通过 docker logout 仓库域名 退出。

34.2.5.3 发布(推送)镜像

通用格式:docker push docker用户名/仓库名:版本号

docker push monksoul/tests:1.0

自此全世界的开发者都可以运行您的镜像了。(赶紧在你的电脑上试试吧):

docker run --name tests -p 8091:80 --restart=always -d monksoul/tests:1.0

34.2.6 私有仓库搭建

自建 Docker 仓库,而不用 Docker Hubhttps://hub.docker.com) 的原因主要有:

  1. 安全性:可以更好地控制镜像的访问权限,确保只有授权的用户或团队可以访问和使用这些镜像,降低了数据泄露的风险。
  2. 网络效率:对于大型企业或项目,频繁地从公共仓库下载和上传镜像可能会占用大量的网络带宽。自建 Docker 仓库可以在内部网络中快速共享和分发镜像,提高网络效率。
  3. 灵活性和定制性:允许企业根据自身的需求和规范进行定制,比如设置特定的访问策略、镜像版本控制等,这些都是公共仓库无法提供的。

总的来说,自建 Docker 仓库可以更好地满足企业的安全和效率需求,提供更灵活和定制化的服务。

34.2.6.1 Docker Registry 方式

Docker Registry https://hub.docker.com/_/registryDocker 官方提供的轻量级私有仓库镜像,可以满足中小型企业搭建私有仓库的需求。(不包含登录,授权,管理后台)

docker run --name registry -p 9000:5000 -v C:\Workspace\DockerImages:/var/lib/registry --restart always -d registry:2

Docker Desktop 设置中找到 Settings -> Docker Engine,在 JSON 配置中添加 insecure-registries 列表:

可通过浏览器访问:http://localhost:9000/v2/_catalog 查看仓库信息。(如果没有仓库出现空白是正常的)

上传镜像到私有仓库

1. 为需要发布的镜像打上标签(别忘记指定私有仓库地址)

通用格式:docker tag 本地镜像名:版本号 私有仓库地址/自定义用户名/仓库名:版本号

docker tag your-project:1.0 localhost:9000/monksoul/tests:1.0

2. 发布(推送)镜像

通用格式:docker push 私有仓库地址/自定义用户名/仓库名:版本号

docker push localhost:9000/monksoul/tests:1.0

可通过浏览器访问:http://localhost:9000/v2/_catalog 查看仓库信息。

3. 运行私有仓库

docker run --name local-tests -p 8092:80 --restart=always -d localhost:9000/monksoul/tests:1.0

34.2.6.2 Harbor 方式(推荐)

Harbor 是一个开源的容器镜像 registry,它用于存储、管理和分发 Docker 镜像。 Harbor 项目由 VMware 公司发起,并且是 Cloud Native Computing Foundation (CNCF) 的托管项目之一。Harbor 提供了企业级的安全性功能,比如基于角色的访问控制(RBAC)、图像签名与验证、镜像复制以及 LDAP/AD 整合等功能,以满足企业在私有云或内部网络中对 Docker 镜像管理的需求。

在基础架构层面,Harbor 可以被部署在企业的内部环境中,使得开发团队能够安全地共享和管理容器镜像。通过 Harbor,企业可以搭建自己的私有仓库来替代或者补充使用 Docker Hub 等公共镜像仓库,确保知识产权的安全性和满足合规要求。

除了作为容器镜像仓库之外,Harbor 还具有日志记录、审计跟踪和垃圾回收等管理工具,方便运维人员进行维护和监控。随着容器化和 Kubernetes 技术的发展,Harbor 成为了现代化软件交付流程中不可或缺的组件之一。

官方地址:https://goharbor.io/

1. 环境准备

确保已经安装了 DockerDocker Compose(对于较新的 Harbor 版本,可能需要 Docker 18.09 或更高版本)

如果是 Windows,那么需要 WSL2 ((https://learn.microsoft.com/zh-cn/windows/wsl/install)[https://learn.microsoft.com/zh-cn/windows/wsl/install])%5Bhttps://learn.microsoft.com/zh-cn/windows/wsl/install%5D%EF%BC%89) 环境支持。

2. 安装 Harbor

访问 https://github.com/goharbor/harbor/releases 查看最新版本,并复制下载链接。

  1. 通过 wget 下载 tgz需要在 WSL 环境中运行 )
wget https://github.com/goharbor/harbor/releases/download/v2.9.2/harbor-offline-installer-v2.9.2.tgz
  1. 解压 .tgz
tar -zxf harbor-offline-installer-v2.9.2.tgz
  1. harbor.yml.tmpl 模板创建 docker-ccompose.yml 文件
cp harbor.yml.tmpl harbor.yml
  1. 输入 explorer.exe. 打开当前目录并使用 Visual Studio Code 或其他文档编辑
  1. 编辑默认配置

通过 Visual Studio Code 打开会有提示,可点击允许即可

  1. 安装 Harborsudo./install.sh
关于 Trivy 漏洞扫描

默认情况下,Harbor 并未启用 Trivy 漏洞扫描器,如需启用,那么需要编辑 install.sh 文件,并将 with_trivy 修改为 $true

修改完成之后保存文件,之后执行 sudo./install.sh --with-trivy 安装。

如果已经安装过 Harbor,那么需要通过 sudo docker-compose down -v 关闭 Harbor 服务后并执行 ./prepare 命令,然后再执行 sudo./install.sh --with-trivy 安装。


3. 访问 http://localhost:9001 并登录

默认账号/密码为:admin/Harbor12345

harbor.yml 配置修改重载

如果修改了 harbor.yml 配置 ,只需要执行(如果需要重新安装,先执行 sudo./prepare 后再操作):

sudo docker-compose down -v
sudo docker-compose up -d

===========上传镜像到 Harbor 仓库===========

1. 创建 Harbor 用户,如这里 monksoul

2. 创建第一个项目,如 first-image

3. 为需要发布的镜像打上标签(别忘记指定私有仓库地址)

通用格式:docker tag 本地镜像名:版本号 Harbor仓库地址/项目名/镜像名:版本号

docker tag your-project:1.0 localhost:9001/first-image/tests:1.0

4. 登录到 Harbor 仓库

docker login localhost:9001

5. 发布(推送)镜像

通用格式:docker push Harbor仓库地址/项目名/镜像名:版本号

docker push localhost:9001/first-image/tests:1.0

Harbor 管理端查看刚刚推送的镜像。

6. 运行私有仓库

docker run --name harbor-tests -p 8093:80 --restart=always -d localhost:9001/first-image/tests:1.0

34.2.7 Docker 数据卷

Docker 数据卷(Volume)是 Docker 中用来持久化和共享数据的一种机制,它提供了一种将宿主机文件系统中的目录与容器内部的文件系统进行映射的方法。通过使用数据卷,可以解决以下几个核心问题:

  1. 数据持久化:当容器停止、删除或重建时,数据卷中的内容不会丢失,因为它们独立于容器生命周期存储在宿主机上。
  2. 数据共享:多个容器可以同时挂载同一个数据卷,实现容器间的数据共享和同步。
  3. 性能:数据卷绕过了容器默认使用的联合文件系统(如 AUFS、OverlayFS 等),直接在宿主机的文件系统上操作,因此具有更好的读写性能。
  4. 备份和迁移:由于数据卷与容器分离,您可以方便地对单独的数据卷进行备份、恢复或迁移操作。

简言之,数据卷用于映射配置文件(如数据库和项目配置)以及运行时系统/用户生成的文件(如数据库文件和用户上传文件)到本地操作系统磁盘。

这确保了在不同应用环境中可以轻松地进行修改,并避免了因容器删除而导致的数据丢失问题。因此,最佳实践是将容器(镜像)设计为无状态容器。

34.2.7.1 简单例子

  1. 在启动项目创建 configs 目录并新增 dbsettings.json 文件
  1. 修改 Dockefile,创建 /app/configs 数据卷
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["FurionApi.Web.Entry/FurionApi.Web.Entry.csproj", "FurionApi.Web.Entry/"]
COPY ["FurionApi.Web.Core/FurionApi.Web.Core.csproj", "FurionApi.Web.Core/"]
COPY ["FurionApi.Application/FurionApi.Application.csproj", "FurionApi.Application/"]
COPY ["FurionApi.Core/FurionApi.Core.csproj", "FurionApi.Core/"]
COPY ["FurionApi.Database.Migrations/FurionApi.Database.Migrations.csproj", "FurionApi.Database.Migrations/"]
COPY ["FurionApi.EntityFramework.Core/FurionApi.EntityFramework.Core.csproj", "FurionApi.EntityFramework.Core/"]
RUN dotnet restore "./FurionApi.Web.Entry/FurionApi.Web.Entry.csproj"
COPY . .
WORKDIR "/src/FurionApi.Web.Entry"
RUN dotnet build "./FurionApi.Web.Entry.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./FurionApi.Web.Entry.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

# 将配置文件复制到临时目录
COPY FurionApi.Web.Entry/configs/* /app/configs_temp/

# 创建数据卷
VOLUME /app/configs

ENTRYPOINT ["dotnet", "FurionApi.Web.Entry.dll"]
  1. 构建镜像和运行镜像,同时挂载数据卷,将本机 C:\Workspace\Vol 目录挂载到容器的 /app/configs 目录中
docker build -t vol:0.1 .
docker run --name vol1 -p 8094:80 -v C:\Workspace\Vol:/app/configs --restart=always -d vol:0.1
  1. 将容器中临时目录配置文件拷贝到本机 C:\Workspace\Vol 中(也可以自行手动复制)
docker cp vol1:/app/configs_temp/ C:\Workspace\Vol

之后打开 C:\Workspace\Vol 目录将 configs_temp 目录所有内容复制到 C:\Workspace\Vol 目录下并删除 configs_temp 目录。

  1. 重启容器即可
docker restart vol1

以上章节属于 Docker VOLUME 基本概念知识,这里只是抛砖引玉,不做详细书写。**

34.2.8 Docker-Compose 编排工具

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。它允许用户通过一个 YAML 文件(通常是 docker-compose.yml)来配置应用程序所需的所有服务,然后通过一个简单的命令来启动和停止这些服务。

这个 YAML 文件描述了每个容器的镜像、环境变量、端口映射、卷挂载等配置信息,以及容器之间的依赖关系。使用 Docker Compose,用户可以轻松地部署和管理整个应用程序,而无需单独处理每个容器

简而言之,Docker Compose 是一个简化和自动化多容器 Docker 应用程序部署的工具。

34.2.8.1 配置示例

docker-compose.yml 官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/

version: "3.8"

services:
xxx.image_name: # 服务名称,用于重启,启动,暂停等操作
image: monksoul/image_name # 可以动态构建,指定构建后的名称
container_name: container_name # 运行时的容器名称
build: # 构建参数
context: . # 指定当前路径
dockerfile: Dockerfile # Dockerfile文件名
volumes: # 数据卷
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
depends_on: #依赖项
- xxx.mysql
expose: #导出80端口
- 80
ports: # 绑定端口
- 8082:80
links: # 配置域网络 (已被弃用,推荐 networks)
- xxx.mysql:link_sql
external_links: 连接外部网络(非当前docker-compose构建的)
- other.mysql:link_sql2
environment: # 配置环境变量
- NAME=monk
networks: # 指定网络类型
- webnet

xxx.mysql:
image: mysql
restart: always
container_name: monk.mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
ports:
- 3306:3306
networks:
- webnet

deploy: # 部署方式
replicas: 5 # 克隆5个,一键部署多个容器当前
resources: # 配置资源
limits: # 资源配置
cpus: "0.1" # 本机cpu的10%
memory: 50M # 当前容器最大内存
restart_policy: # 重启策略
condition: on-failure # 条件:失败就重启

networks: # 创建新的网络类型
webnet:
driver: bridge # 网络方式:桥接或集群

默认情况下,如果没有指定具体的 compose 配置文件名,那么就 docker-compose.yml 就是默认配置文件名。

如需手动指定 .yml 文件,可通过以下命令:

docker-compose -f new-name.yml up

docker-compose -f new-name.yml ps

34.2.8.2 docker rundocker-compose.yml 实战

docker-compose.yml 文件路径

通常 docker-compose.yml 和网站的 Dockerfile 放在同一目录下。

假设我们的项目需要同时用到 MSSQLMYSQLNginx 三个服务,在没有用 Docker Compose 之前,我们需要执行三条命令。

  • 没有 Docker Compose 之前
docker run --name first-mssql -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Furion.com!q1w2e3' -e 'MSSQL_PID=Express' -p 1433:1433 -d mcr.microsoft.com/mssql/server

docker run --name first-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql

docker run --name first-nginx -p 8081:80 -d nginx

可以想象一下,如果我们的网站需要几十个服务(微服务),每一次都需要构建新镜像后再手动执行几十个这样的命令,多可怕....

  • 有了 Docker Compose 之后

我们可以把容器配置写到 docker-compose.yml 文件中,以后只需要通过 docker-compose up -d 启动即可。

version: '3.8'

services:
first-mssql:
container_name: first-mssql
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=Furion.com!q1w2e3
- MSSQL_PID=Express
ports:
- 1433:1433
image: mcr.microsoft.com/mssql/server

first-mysql:
container_name: first-mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
ports:
- 3306:3306
image: mysql

first-nginx:
container_name: first-nginx
ports:
- 8081:80
image: nginx

Docker Componse 还可以用于构建 Dockerfile 镜像并运行 ,也就是 docker build + docker run 的操作 。

由此可见,Docker Compose 解决了 docker run 命令混乱、难记、不易分享、不易构建等问题 。

34.2.9 Docker 部署常见问题

该章节将记录和分享 Docker 部署遇到的一些问题做一个记录。

34.2.9.1 Windows 安装注意事项

如果在 Windows 中安装 Docker,需确保操作系统是 Windows 10/11 专业版、正确安装了 WSL2 工具和正确配置 Windows 功能

安装步骤可参考微软官方文档:https://learn.microsoft.com/zh-cn/windows/wsl/install-manual

34.2.9.2 配置 Docker 国内镜像

由于国内政策限制,目前 https://hub.docker.com 官方 镜像库已无法正常访问,所以可以通过以下方式设置国内镜像库。

WindowsLinuxMacOS 上配置 Docker 使用国内镜像加速服务的方法大同小异,主要是通过修改 Docker 守护进程的配置文件或直接在图形界面中设置registry-mirrors选项。

  • Windows 平台
  1. 通过 Docker Desktop GUI 配置
    • 打开 Docker Desktop 应用。
    • 点击右上角的菜单图标(或者右键任务栏托盘区的 Docker 图标)并选择 SettingsPreferences
    • 在设置面板中找到 Daemon 选项卡。
    • JSON 编辑框中添加或修改如下内容:
      {
      "registry-mirrors": [
      "https://registry.docker-cn.com",
      "https://docker.mirrors.ustc.edu.cn"
      ]
      }
    • 应用更改后点击 Apply & Restart 来重启 Docker Engine 以使配置生效。
  • Linux 平台
  1. 编辑 daemon.json 配置文件
    • 首先确保有 sudo 权限。
    • 使用文本编辑器打开 /etc/docker/daemon.json 文件(如果文件不存在,则新建该文件)。
    • 添加如下内容:
      {
      "registry-mirrors": [
      "https://registry.docker-cn.com",
      "https://docker.mirrors.ustc.edu.cn"
      ]
      }
    • 保存并关闭文件。
    • 重启 Docker 服务:sudo systemctl restart docker
  • MacOS 平台
  1. 通过 Docker Desktop GUI 配置
    • 打开 Docker Desktop 应用程序。
    • 前往 Preferences 菜单(通常在顶部菜单栏的 Docker 图标下)。
    • 选择 Daemon 标签页。
    • 同样在 JSON 编辑区域中添加或修改与上述 Windows 部分相同的配置信息。
    • 点击 Apply & Restart 重启 Docker 服务以应用新的配置。

34.2.9.3 无 https 证书问题

如果你的 Furion/ASP.NET Core 项目在 appsettings.json 文件中配置了 Urls,或者通过代码使用 UseUrls 方法配置了以 https:// 开头的 URL 地址,但你没有提供对应的 https 证书,那么构建 docker 镜像时会启动失败。

要解决此问题,你有两个选择:

  1. 配置有效的 https 证书。
  2. 从配置中移除所有以 https:// 开头的 URL 地址。

34.2.9.4 DateTime.Now 时区问题

Docker 环境中使用 DateTime.Now 可能会存在时区问题,那么可以通过以下方式解决:

  • Dockerfile 构建时设置
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
  • 在容器中设置
docker exec -it 容器名 /bin/bash

rm /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

34.2.10 其他问题

34.2.10.1 Trivy 漏洞扫描数据库离线安装

在安装了 Harbor 私有仓库并配置了 Trivy 漏洞扫描器之后,首次扫描需要检查更新并下载 trivy.db 数据库。路径通常存放在 /data/trivy-adapter/trivy/db 目录下。

如果出现网络无法下载,那么可以安装 trivyoras 进行下载(注意下载后的 trivy.db 一定需要 v2版本)。下载地址:https://github.com/aquasecurity/trivy-db

下载完成之后并解压到 /data/trivy-adapter/trivy/db 目录下:

tar -xzvf trivy.db.tar.gz -C /data/trivy-adapter/trivy/db/

接着修改 /data/trivy-adapter/trivy/db/ 目录权限:

chown -R 10000:10000 /data/trivy-adapter/trivy/db/

之后修改 harbor.yml 文件 trivy节点,将 skip_update 设置为 trueoffline_scan 设置为 true

最后重新构建并重启 harbor 服务即可:

sudo ./prepare
sudo ./install.sh --with-trivy

docker-compose down
docker-compose up -d

这里提供自维护的 trivy.db 仓库下载地址:https://github.com/MonkSoul/trivy-db

34.2.11 其他知识

34.2.11.1 前端(Vue/React/Angular)Dockerfile 参考

  1. 在项目根目录下创建 nginx.conf 文件
server {
listen 80;
# server_name your.domain.com; # 替换为你的实际域名或 IP

# 静态资源路径设置
root /usr/share/nginx/html;

# 对于单页应用,所有未匹配到的路由重定向到 index.html
location / {
try_files $uri $uri/ /index.html =404;
}

# 可以添加其他如 gzip 压缩、缓存控制等配置
}
  1. 在项目根目录下创建 Dockerfile 文件
# 使用官方的 nginx 镜像作为基础镜像
FROM nginx:stable-alpine

# 删除默认配置文件(可选,如果你想要完全自定义配置)
RUN rm /etc/nginx/conf.d/default.conf

# 将本地的 nginx 配置文件复制到容器中
COPY nginx.conf /etc/nginx/conf.d/

# 复制 React/Vue/Angular 应用构建后的静态文件(build 或 dist 目录)到 nginx 的 web 根目录
COPY build /usr/share/nginx/html

# 暴露 80 端口用于HTTP服务
EXPOSE 80

# 设置容器启动时运行的命令为 nginx 服务器
CMD ["nginx", "-g", "daemon off;"]
  1. 构建镜像后运行

比如构建后的镜像为:yourproject:1.0

docker run --name react-project -v 5000:80 -d yourproject:1.0

34.2.11.2 Docker 常用命令

Docker CLI 官方文档:https://docs.docker.com/engine/reference/commandline/docker/

Docker Container CLI 官方文档:https://docs.docker.com/engine/reference/commandline/container/

  • 查看 Docker 版本
docker version
  • 拉取镜像
docker pull 镜像名:版本号
  • 运行镜像
docker run --name 容器名 -p 本机端口:Dockerfile导出端口 -d 镜像名:版本号
  • 查看镜像列表
docker images ls
  • 查看当前运行的容器
docker container ps
  • 查看所有容器
docker container ps -a
  • 删除镜像
docker rmi 镜像名:版本号 镜像名:版本号 ...
  • 删除正在运行的容器
docker rm 容器名1 容器名称2 ...

强制删除可带 -f 参数:docker rm -f...

  • 启动挂起的容器
docker start 容器名1 容器名称2 ...
  • 重启容器
docker restart 容器名1 容器名称2 ...
  • 停止正在运行的容器
docker stop 容器名1 容器名称2 ...
  • 进入容器系统终端
docker exec -it 容器名 bash
  • 查看容器运行日志
docker logs 容器名 bash
  • 删除所有已停止的容器(慎重!!!)
docker container prune
  • 拷贝容器中的目录到本机目录
docker cp 容器名:目录 本机目录

34.2.11.3 Docker Compose 常用命令

Docker Compose CLI 官方文档:https://docs.docker.com/compose/reference/

基本参数

  • -f:指定 yml 文件的路径,默认当前目录下的 docker-compose.yml
  • -p:指定该项目名称,(容器名会以项目名为前缀),如果不指定就是当前所在目录名称
  • 启动 Docker Compose 项目中定义的服务
docker-compose up -d

-d 表示让这些服务在后台以守护进程(daemon)模式运行。

  • 列出 Docker Compose 应用中正在运行的服务
docker-compose ps

-a 参数查看详细信息

  • 启动 Docker Compose 应用并重新构建 Dockerfile
docker-compose up --build
  • 查看 Docker Compose 应用配置文件(如:docker-compose.yml)
docker-compose config

可以指定查询特定节点:--节点:只查询某部分,如:docker-compose config --services

  • 停止并删除 Docker Compose 中所有的服务
docker-compose down
  • 查看 Docker Compose 应用所有镜像
docker-compose images
  • 在 Docker Compose 应用特定服务中执行命令
docker-compose exec 服务名

docker-compose exec 服务名 bash

例如,执行 mysql -u root -p 命令来登录 MySQL 数据库:docker-compose exec your.mysql mysql -u root -p

  • 查看 Docker Compose 应用日志
docker-compose logs
  • 暂停 Docker Compose 应用特定服务
docker-compose pause 服务名
  • 恢复 Docker Compose 应用特定服务
docker-compose unpause 服务名
  • 启动 Docker Compose 应用特定服务
docker-compose start 服务名
  • 重启 Docker Compose 应用特定服务
docker-compose restart 服务名
  • 删除 Docker Compose 应用特定服务
docker-compose rm 服务名

34.2.11.4 Dockerfile 常用命令

Dockerfile 官方文档:https://docs.docker.com/engine/reference/builder/

  • FROM:指定基础镜像。
FROM ubuntu:latest

这个命令表示基于 Ubuntu 的最新版镜像来创建新的镜像。

  • MAINTAINER:维护者信息,提供 Dockerfile 制作者的信息。
MAINTAINER John Doe <johndoe@example.com>

这个命令用于设置 Docker 镜像的维护者信息。

  • RUN:在当前镜像上执行 Linux 命令并形成一个新的层。
RUN apt-get update && apt-get install -y nginx

这个命令在镜像中安装 nginx

  • CMD:启动 docker 时执行的命令。
CMD ["nginx", "-g", "daemon off;"]

这个命令设置容器启动时运行的命令。

  • EXPOSE:设置向外暴露的端口。
EXPOSE 80

这个命令表示容器将监听 80 端口。

  • ENV:设置环境变量。
ENV NAME John
ENV AGE 30

这些命令设置了两个环境变量 NAMEAGE。也可以通过 ENV NAME=John 方式

  • COPY:制作 image 时,将文件系统中的文件复制到 Docker 镜像中。
COPY . /usr/src/myapp

这个命令将当前目录下的所有文件复制到镜像的 /usr/src/myapp 目录中。

  • ADD:类似 COPY 命令,支持 URL 路径。
ADD https://example.com/app.tar.gz /usr/src/myapp

这个命令将从 URL 下载 app.tar.gz 文件并解压到镜像的 /usr/src/myapp 目录中。

  • ENTRYPOINT:设置容器启动后的第一个命令。
ENTRYPOINT ["nginx"]

这个命令设置容器启动后首先运行 nginx

  • VOLUME:设置容器与外界映射的目录。
VOLUME /data

这个命令表示容器将 /data 目录映射到宿主机的一个目录。

  • USER:设置运行容器的用户。
USER nginx

这个命令设置容器以 nginx 用户身份运行。

  • WORKDIR:设置工作目录。
WORKDIR /usr/src/myapp

这个命令设置容器的工作目录为 /usr/src/myapp

  • ONBUILD:当构建一个被继承的 Dockerfile 时运行命令。
ONBUILD RUN apt-get update && apt-get install -y python

这个命令表示当基于当前 Dockerfile 构建新的镜像时,将运行指定的命令。

34.2.11.5 docker-compose.yml 常见配置

docker-compose.yml 官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/

version: "3.8"

services:
xxx.image_name: # 服务名称,用于重启,启动,暂停等操作
image: monksoul/image_name # 可以动态构建,指定构建后的名称
container_name: container_name # 运行时的容器名称
build: # 构建参数
context: . # 指定当前路径
dockerfile: Dockerfile # Dockerfile文件名
volumes: # 数据卷
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
depends_on: #依赖项
- xxx.mysql
expose: #导出80端口
- 80
ports: # 绑定端口
- 8082:80
links: # 配置域网络 (已被弃用,推荐 networkds)
- xxx.mysql:link_sql
external_links: 连接外部网络(非当前docker-compose构建的)
- other.mysql:link_sql2
environment: # 配置环境变量
- NAME=monk
networks: # 指定网络类型
- webnet

xxx.mysql:
image: mysql
restart: always
container_name: monk.mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
ports:
- 3306:3306
networks:
- webnet

deploy: # 部署方式
replicas: 5 # 克隆5个,一键部署多个容器当前
resources: # 配置资源
limits: # 资源配置
cpus: "0.1" # 本机cpu的10%
memory: 50M # 当前容器最大内存
restart_policy: # 重启策略
condition: on-failure # 条件:失败就重启

networks: # 创建新的网络类型
webnet:
driver: bridge # 网络方式:桥接或集群

默认情况下,如果没有指定具体的 compose 配置文件名,那么就 docker-compose.yml 就是默认配置文件名。

如需手动指定 .yml 文件,可通过以下命令:

docker-compose -f new-name.yml up

docker-compose -f new-name.yml ps

34.2.12 反馈与建议

与我们交流

给 Furion 提 Issue