Dockerizing 我们的 F# SQLProvider 应用程序
照片由Moritz Kindler 拍摄/Unsplash 这篇文章继续我们在 F# 领域中静态检查 SQL 模式的旅程。我们仍在使用 SQLProvider,仍然在 .NET Core 3.1 上,并且仍然使用我们的控制台应用程序生活在 CLI 世界中。所有代码都位于公共GitLab 存储库中,此处为。这篇文章从这个 commit开始,所有的工作都包含在MR#3中。我的之前的帖子(GitLab
照片由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 之后——道路还是有点坎坷:
[](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 build
和dotnet 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 项目)
很快见!
更多推荐
所有评论(0)