照片由Moritz Kindler 拍摄/Unsplash

这篇文章继续我们在 F# 领域中静态检查 SQL 模式的旅程。我们仍在使用 SQLProvider,仍然在 .NET Core 3.1 上,并且仍然使用我们的控制台应用程序生活在 CLI 世界中。所有代码都位于公共GitLab 存储库中,此处为。这篇文章从这个 commit开始,所有的工作都包含在MR#3中。我的之前的帖子(GitLab Kubernetes Runners 上的 F# SQLProvider 管道)改进了我们的 CI 管道,以在私有 k8s 集群上运行,而不是在 GitLab 的共享运行器上运行,这将使我们在这篇文章中更快地迭代。

所以,今天,我们想要 dockerize 我们的应用程序并构建我们的管道以在每次提交时运行docker build。一旦管道成功,我们应该合并并标记新生成的代码以剪切完整版本。

现在,因为我们在 docker 容器中严格执行我们的模式 - 使用我们出色的 SQLProvider - 我们应该意识到我们可能会遇到一些障碍。我们将发出的可能导致这种颠簸的命令是dotnet publish,因为它运行编译器,随后运行我们的 SQLProvider。让我们尝试一个简单的 Dockerfile 并进行迭代 - #agile。

# use 3.1 LTS dotnet SDK image
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS compiler
WORKDIR /app

# add everything; .dockerignore will filter files and folders
ADD . .

# run publish!
RUN dotnet publish -f netcoreapp3.1 -o dist

# switch to a runtime image w/out full sdk
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-alpine AS runtime
WORKDIR /app

# copy only the compiled dlls
COPY --from=compiler /dist .

# setup entrypoint to run the app
ENTRYPOINT ["dotnet", "test-sql-provider.dll"]

进入全屏模式 退出全屏模式

如果你运行它,你会得到一个类似Exception while connecting的错误,这基本上意味着我们的 dotnet publish 命令,在我们的本地 docker 守护进程中,找不到要连接的 postgre db。幸运的是,docker build docs (docker build --help) 向我们展示了一个简洁的小选项:--network。我们想使用主机网络来公开我们的 postgres 数据库或服务。所以现在,在本地,我们可以运行docker build --network host -t test .并且我们将构建一个 docker 镜像!耶!

现在,为了在本地_运行_我们的容器,您还需要--network host选项:docker run -it --rm --network host your-image-tag。现在您的 docker 容器将能够连接到您的本地数据库!

CI - 真正的交易

所以它在本地工作——它会在 GitLab 的 CI 中工作吗?

嗯......几乎 - 为了在我们的 GitLab CI 中构建一个 docker 镜像,我们需要选择如何这样做。在这篇文章中,我选择了Kaniko 路由但也有 Docker-In-Docker 路由,尽管该路由需要特权容器。如果可能的话,您应该避免使用特权容器。

现在,即使在选择了 kaniko、浏览了文档并获得了有效的 yaml 之后——道路还是有点坎坷:

[近 10 个失败构建的图片。](https://res.cloudinary.com/practicaldev/image/fetch/s--cQm_JZHk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sean.thenewells.us/content/images /2020/02/TryAndTryAgain.PNG)

如果你一开始没有成功...

因此,我将免除您的痛苦,并开始解释 Kaniko。

Kaniko是一个 google 项目,用于使用普通二进制文件而不是 docker 守护程序构建 OCI 图像。这是一个可移植的 docker build 的尝试。这很有用的原因正是我们的用例——我们在 k8s 中有一个私有 CI 队列,并且希望在没有特权容器的情况下在 CI 作业中构建 docker 镜像。

这一切听起来都很棒 - 但我遇到的一个问题是无论我做了什么,_ 我无法运行 _.sh_ ** kaniko 容器中的脚本** _。如果你尝试,你可能会得到这样的结果:

docker run --entrypoint "" -it --rm gcr.io/kaniko-project/executor:debug sh

$ vi test.sh
$ chmod +x test.sh
$ cat test.sh
#!/bin/sh

echo 'hey'
# ./test.sh
sh: test.sh: not found
$ sh -c test.sh
sh: test.sh: not found

进入全屏模式 退出全屏模式

如果您对此有所了解...发表评论或在推特上@我 - 我非常想知道为什么 kaniko 不能处理 shell 脚本。我知道 kaniko 图像的调试标签有一个 shell,否则它只会让你进入 kaniko 执行程序,所以它可能与此有关 - 但我不知所措。

为什么我们需要执行你问的 shell 脚本?好吧,当然是播种我们的数据库。但有志者事竟成!我们可以创建自己的镜像,在启动时将我们的模式放入容器化的 postgres 数据库,而不是像我们那样在 CI 管道中播种我们的数据库。所以这就是我们将做的事情!

FROM postgres:12.1-alpine

RUN echo "CREATE SCHEMA IF NOT EXISTS test AUTHORIZATION test_app;" > /docker-entrypoint-initdb.d/setup.sql
RUN mkdir /sql
ADD schema.sql /sql/schema.sql
RUN cat /sql/schema.sql >> /docker-entrypoint-initdb.d/setup.sql

进入全屏模式 退出全屏模式

这是一个非常简单的 Dockerfile,基本上只是将我们的模式放在一个特殊的 init 文件夹中。 Postgres 有个记录的环境变量来设置 test_app 用户和密码,所以如果你试图拉下这个图像,请确保你设置了这些。

现在我们有了一个“种子”数据库(当然不是数据种子,只是模式)——我们可以在我们的管道中使用它!

通过 Kaniko Pipeline

Kaniko Step

GitOps 发布

最终,我们将需要一个发布管道和版本控制,因此我们可以继续为 db 映像和我们的主应用程序映像设置标签构建。我还添加了一些甜蜜的测试,因此构建将不仅仅是编译。我决定将dotnet builddotnet test步骤压缩到一个版本中以节省一些时间。在这种情况下,我认为将它们作为同一工作的步骤而不是不同的工作是有意义的,但您的情况可能会有所不同。

  • 应用程序 docker 镜像的标记发布

  • db docker 映像的标记版本

  • 我们也有预发布版本,带有提交 SHA 标记

这比我一开始想的要复杂得多,如果你查看我的 GitLab repo 上的整个管道历史和我的提交历史,你会看到我正在玩的实验(多行,buildah ,让 kaniko 正常工作,服务,为数据库播种......)。但我确实学到了很多东西!在这次冒险之前,我不知道网络标志、kaniko、buildah 或如何对 F# SQLProvider 项目进行 docker 化。

结论

我认为我现在拥有的东西是相当稳定的。我对在这个合并请求中进行的测试感到满意,现在我们已经 dockerized,我们可以在任何地方部署我们的 cat db 应用程序。此外,这个 MR 获得了一个DB_CONN_STR环境变量,所以只要我们将--network host添加到docker run,我们就可以传递这个带有-e标志的环境变量,以将我们的图像连接到具有它编译时所针对的架构的任何数据库 - 如果我们想要为了把它也拉下来,我们有一个带有预烘焙模式的图像。好的!

在接下来的几篇文章中,我们现在可以探索:

  • 在我们的核心逻辑之上添加一个 API 层

  • 添加前端可能吗?

  • 构建管道以使预发布的 docker 映像通过步伐(实际上在 docker 映像上运行集成测试)

  • 以某种方式在发布版本上从重建切换到重新标记

  • 添加更高级的 db 功能以展示 F# 的 SQLProvider 的强大功能

  • 添加更多有用的测试(FsCheck 测试对于我们的辅助层来说已经非常强大了)

  • 将这种策略迁移到“真实”项目(如我的trakr 项目)

很快见!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐