应用程序部署打包

一旦应用程序构建完成并准备用于生产环境,它仍然需要进行打包才能部署到服务器。有几种策略可以用于打包 Swift 应用程序以进行部署。

Docker

如今,打包应用程序最流行的方式之一是使用容器技术,例如 Docker

使用 Docker 的工具,我们可以构建应用程序并将其打包为 Docker 镜像,发布到 Docker 仓库,然后直接在服务器上或在支持 Docker 部署的平台(如 Kubernetes)上启动它。许多公共云提供商,包括 AWS、GCP、Azure、IBM 等,都鼓励这种部署方式。

这是一个示例 Dockerfile,它在 CentOS 之上构建和打包应用程序

#------- build -------
FROM swift:centos8 as builder

# set up the workspace
RUN mkdir /workspace
WORKDIR /workspace

# copy the source to the docker image
COPY . /workspace

RUN swift build -c release --static-swift-stdlib

#------- package -------
FROM centos
# copy executables
COPY --from=builder /workspace/.build/release/<executable-name> /

# set the entry point (application name)
CMD ["<executable-name>"]

要从 Dockerfile 创建本地 Docker 镜像,请从应用程序的源代码位置使用 docker build 命令,例如:

$ docker build . -t <my-app>:<my-app-version>

要测试本地镜像,请使用 docker run 命令,例如:

$ docker run <my-app>:<my-app-version>

最后,使用 docker push 命令将应用程序的 Docker 镜像发布到您选择的 Docker 仓库,例如:

$ docker tag <my-app>:<my-app-version> <docker-hub-user>/<my-app>:<my-app-version>
$ docker push <docker-hub-user>/<my-app>:<my-app-version>

此时,应用程序的 Docker 镜像已准备好部署到服务器主机(需要运行 Docker)或支持 Docker 部署的平台之一。

有关 Docker 的更完整信息,请参阅 Docker 文档

Distroless

Distroless 是 Google 的一个项目,旨在创建最小化的镜像,其中仅包含应用程序及其运行时依赖项。它们不包含包管理器、shell 或您期望在标准 Linux 发行版中找到的任何其他程序。

由于 Distroless 支持 Docker 并且基于 Debian,因此在其上打包 Swift 应用程序与上面的 Docker 过程非常相似。这是一个示例 Dockerfile,它在 Distroless 的 C++ 基础镜像之上构建和打包应用程序

#------- build -------
# Building using Ubuntu Bionic since its compatible with Debian runtime
FROM swift:bionic as builder

# set up the workspace
RUN mkdir /workspace
WORKDIR /workspace

# copy the source to the docker image
COPY . /workspace

RUN swift build -c release --static-swift-stdlib

#------- package -------
# Running on distroless C++ since it includes
# all(*) the runtime dependencies Swift programs need
FROM gcr.io/distroless/cc-debian10
# copy executables
COPY --from=builder /workspace/.build/release/<executable-name> /

# set the entry point (application name)
CMD ["<executable-name>"]

请注意,上面使用了 gcr.io/distroless/cc-debian10 作为运行时镜像,这应该适用于不使用 FoundationNetworkingFoundationXML 的 Swift 程序。为了提供更完整的支持,我们(社区)可以向 Distroless 提交 PR,以引入一个 Swift 基础镜像,其中包含 libcurllibxml,它们分别是 FoundationNetworkingFoundationXML 所必需的。

归档文件(Tarball、ZIP 文件等)

由于 Mac 或 Windows 上尚不支持为 Linux 进行 Swift 交叉编译,我们需要使用 Docker 等虚拟化技术来编译目标在 Linux 上运行的应用程序。

也就是说,这并不意味着我们必须将应用程序打包为 Docker 镜像才能部署它们。虽然使用 Docker 镜像进行部署既方便又流行,但应用程序也可以使用简单轻量级的归档格式(如 tarball 或 ZIP 文件)进行打包,然后上传到服务器,在那里可以解压并运行。

这是一个使用 Docker 和 tar 构建和打包应用程序以部署在 Ubuntu 服务器上的示例

首先,从应用程序的源代码位置使用 docker run 命令来构建它

$ docker run --rm \
  -v "$PWD:/workspace" \
  -w /workspace \
  swift:bionic \
  /bin/bash -cl "swift build -c release --static-swift-stdlib"

请注意,我们正在绑定挂载源代码目录,以便构建将构建产物写入本地驱动器,稍后我们将从中打包它们。

接下来,我们可以创建一个包含应用程序可执行文件的暂存区

$ docker run --rm \
  -v "$PWD:/workspace" \
  -w /workspace \
  swift:bionic  \
  /bin/bash -cl ' \
     rm -rf .build/install && mkdir -p .build/install && \
     cp -P .build/release/<executable-name> .build/install/'

请注意,此命令可以与上面的构建命令结合使用——我们将其分开是为了使示例更具可读性。

最后,从暂存目录创建一个 tarball

$ tar cvzf <my-app>-<my-app-version>.tar.gz -C .build/install .

我们可以通过将其解压缩到目录并在 Docker 运行时容器中运行应用程序来测试 tarball 的完整性

$ cd <extracted directory>
$ docker run -v "$PWD:/app" -w /app bionic ./<executable-name>

可以将应用程序的 tarball 部署到目标服务器,可以使用诸如 scp 之类的实用程序,或者在更复杂的设置中使用配置管理系统,如 chefpuppetansible 等。

源代码分发

另一种在 Ruby 或 Javascript 等动态语言中流行的分发技术是将源代码分发到服务器,然后在服务器本身上编译它。

要在服务器上直接构建 Swift 应用程序,服务器必须安装正确的 Swift 工具链。 发布了适用于各种 Linux 发行版的工具链,请确保使用与您的服务器 Linux 版本和所需的 Swift 版本匹配的工具链。

这种方法的主要优点是它很简单。另一个优点是服务器具有完整的工具链(例如调试器),可以帮助在服务器上“实时”排除问题。

这种方法的主要缺点是服务器具有完整的工具链(例如编译器),这意味着复杂的攻击者可能会找到执行代码的方法。他们还可能获得对源代码的访问权限,这些源代码可能是敏感的。如果应用程序代码需要从私有或受保护的仓库克隆,则服务器需要访问凭据,这会增加额外的攻击面。

在大多数情况下,由于这些安全问题,不建议使用源代码分发。

静态链接和 Curl/XML

注意: 如果您使用 -static-stdlib 进行编译,并且将 Curl 与 FoundationNetworking 或 XML 与 FoundationXML 一起使用,则目标系统上必须安装 libcurl 和/或 libxml2 才能使其工作。