本文系上一个系列教程的学习记录第三章,原链接是.NET Microservices – Full Course。本文基于上一章开发的平台服务,介绍了如何将.NET Core的Web API部署到Docker以及Kubernetes中,以及过程中各个操作的说明解释。除此之外,还介绍了Docker和Kubetnetes必要的概念。

Docker

这部分视频教程介绍比较简单,本文主要参考了微软培训文档的资料。

容器/Container

Microsoft Learning: What is Container?[1]:
容器是一个松散孤立的环境,使我们能够构建并运行软件包。这些软件包(被称作“容器镜像”)包括代码和所有依赖项在任何计算环境快速而可靠地运行应用程序。

容器化/Containerization

Microsoft Learning: What is software containerization?[1]:
软件容器化是一种操作系统虚拟化方法,用于在不使用虚拟机 (VM) 的情况下部署和运行容器。 容器可在物理硬件上、云和 VM 中运行,还可以在多个操作系统上运行。

容器化VS虚拟机

Microsoft Learning: Compare virtual machines to containers (Video)[2]:
类似于在单个物理主机上运行多个虚拟机,你可以在单个物理或虚拟主机上运行多个容器。
与虚拟机不同,你不用管理容器的操作系统。 虚拟机就像是可以连接和管理的操作系统的实例,但容器是轻型的,其设计目的是实现动态创建、横向扩展和停止。 虽然可在应用程序需求增加的情况下创建和部署虚拟机,但容器的作用旨在使你能够响应基于需求的更改。使用容器,可以在出现崩溃或硬件中断时快速重启。

.NET 微服务实践(3)-部署服务到Docker与Kubernetes_应用程序

A comparison between VMs and Docker containers.

总结就是:虚拟机虚拟化计算机硬件,而容器虚拟化操作系统。

Docker是什么

Microsoft Learning: What is Docker[1]:
Docker 是一个用于开发、交付和运行容器的容器化平台。 Docker不使用虚拟机监控程序,如果要开发和测试应用程序,可以在台式机或笔记本电脑上运行 Docker。 桌面版 Docker 支持 Linux、Windows 和 macOS。 对于生产系统,Docker 适用于服务器环境,包括 Linux 的多种变体和 Microsoft Windows Server 2016 及更高版本。

.NET 微服务实践(3)-部署服务到Docker与Kubernetes_Docker_02

Docker Architecture

Docker引擎[3]

Docker引擎:包含配置为客户端-服务器实现的多个组件,其中,客户端和服务器在同一主机上同时运行。 客户端使用 REST API 与服务器通信,该 API 还让客户端能够与远程服务器实例通信。
Docker客户端:名为docker的命令行应用程序,它为我们提供了一个命令行接口 (CLI),用于与 Docker 服务器进行交互。docker命令使用 Docker REST API 将指令发送到本地或远程服务器,并作为用于管理容器的主要接口。
Docker服务器:一个名为dockerd的守护程序。dockerd守护程序通过 Docker REST API 响应来自客户端的请求,并且可以与其他守护程序进行交互。 此外,Docker服务器还负责跟踪容器的生命周期。

Docker镜像[3]

容器镜像/Image:一种包含软件的可移植程序包。 它在运行时便成为了我们的容器。容器是镜像的内存中实例。容器镜像是不可变的。 生成镜像后,无法更改该镜像; 更改镜像的唯一方法是创建新映像。 此特性可保证在生产环境中使用的镜像与在不同 环境中使用的相同。
可堆叠的统一文件系统/Unionfs:Unionfs用于创建 Docker镜像。Unionfs是一种文件系统,允许以看似合并内容的方式堆叠多个目录(称为分支)。但是,内容在物理上是保持分开的。Unionfs允许在生成文件系统时添加和删除分支。假设要为之前的 Web 应用生成一个镜像:将 Ubuntu 发行版作为基础镜像叠加到引导文件系统之上;接下来,将安装 Nginx 和 Web 应用;有效地将 Nginx 和 Web 应用叠加到原始 Ubuntu 镜像之上;在通过镜像运行容器后,将创建最终的可写层。但是,当容器被销毁时,此层将不复存在。

.NET 微服务实践(3)-部署服务到Docker与Kubernetes_Docker_03

Unionfs

基础镜像/Base Image:使用 Docker scratch镜像的镜像。scratch镜像是一种空容器镜像,不会创建文件系统层。 此镜像假设要运行的应用程序可以直接使用主机操作系统内核。
父级镜像/Parent Image:用于创建镜像的容器镜像。例如,将使用已基于Ubuntu的镜像,而不是从scratch创建镜像再安装 Ubuntu。甚至可以使用已安装 Nginx 的镜像。父级镜像通常包含一个容器操作系统。父级镜像和基础镜像都可用于创建可重复使用的映像。但是,基础镜像能够更好地控制最终镜像的内容——镜像是不可变的,只能对镜像进行添加操作而不能进行删减操作。

Docker Host[3]

主机操作系统/Host OS:Docker 引擎运行依赖作系统。在 Linux 上运行的 Docker 容器共享主机操作系统内核,只要二进制文件可以直接访问操作系统内核,便无需容器操作系统。但是,Windows 容器需要容器操作系统。容器依靠操作系统内核来管理服务,例如文件系统、网络管理、进程调度和内存管理。
容器操作系统/Container OS:是已打包映像包含的操作系统。 我们可以灵活地在容器中包含不同版本的 Linux 或 Windows 操作系统。 这种灵活性使我们能够访问特定操作系统功能或安装应用程序可能使用的其他软件。容器操作系统独立于主机操作系统,我们要在这一环境中部署和运行应用程序。 结合映像的不可变性,这种隔离意味着应用程序开发环境和生产环境相同。在示例中,使用 Ubuntu Linux 作为容器操作系统,并且此操作系统不会因开发或生产而改变。 我们所使用的映像始终是同一映像。

.NET 微服务实践(3)-部署服务到Docker与Kubernetes_应用程序_04

Host OS and Container OS

Docker Hub[3]

Docker Hub是一个软件即服务 (SaaS) Docker 容器注册表。 Docker 注册表是用于存储和分发创建的容器镜像的存储库。 Docker Hub是Docker用于镜像管理的默认公共注册表。可以创建和使用专用 Docker 注册表,也可以使用不同公司提供的注册表服务。

Dockerfile

一种文本文件,其中包含用于生成和运行 Docker镜像的说明,可以定义镜像的以下方面:

  • 用于创建新镜像的基础映像或父级镜像
  • 用于更新基础操作系统和安装其他软件的命令
  • 要包含的生成项目,例如开发的应用程序
  • 要公开的服务,例如存储和网络配置
  • 要在启动容器时运行的命令

平台服务容器化

可以参考Docker的文档[4]

配置Dockfile文件

在平台服务的工程文件目录下创建Dockerfile文件

  • 声明父级镜像
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
  • 配置(容器运行时)工作目录
WORKDIR /app
  • 拷贝工程文件并将其作为独立的层
COPY *.csproj ./
RUN dotnet restore
  • 拷贝其它项目文件并且编译
COPY . ./
RUN dotnet publish -c Release -o out

截至目前,所做都是拉取一个.NET Core的SDK、利用它做编译工作。之后将再获取一个运行时的父级镜像,打包出一个生产环境的镜像——相比于开发环境会更加小巧。

  • 拷贝运行时父级镜像,设置工作路径,拷贝编译后的工程,并且指定程序运行的入口
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "PlatformService.dll"]

制作平台服务的容器镜像

在Dockfile所在的目录下,运行如下Docker命令

>>docker build -t <docker hub id>/platformservice .
[+] Building 6.2s (15/15) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                               0.0s
 => => transferring dockerfile: 32B                                                                                                                                                                0.0s
 => [internal] load .dockerignore                                                                                                                                                                  0.0s
 => => transferring context: 2B                                                                                                                                                                    0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:5.0                                                                                                                               0.3s
 => [internal] load metadata for mcr.microsoft.com/dotnet/sdk:5.0                                                                                                                                  0.4s
 => [build-env 1/6] FROM mcr.microsoft.com/dotnet/sdk:5.0@sha256:3ff465d940de3e2c727794d92fd7bb649c498d4abd91bc9213ea7831ebf01f1e                                                                  0.0s
 => [internal] load build context                                                                                                                                                                  0.1s
 => => transferring context: 1.42MB                                                                                                                                                                0.1s
 => [stage-1 1/3] FROM mcr.microsoft.com/dotnet/aspnet:5.0@sha256:1a7d811242f001673d5d25283b3af03da526de1ee8d3bb5aa295f480b7844d44                                                                 0.0s
 => CACHED [build-env 2/6] WORKDIR /app                                                                                                                                                            0.0s
 => CACHED [build-env 3/6] COPY *.csproj ./                                                                                                                                                        0.0s
 => CACHED [build-env 4/6] RUN dotnet restore                                                                                                                                                      0.0s
 => [build-env 5/6] COPY . ./                                                                                                                                                                      0.2s
 => [build-env 6/6] RUN dotnet publish -c Release