开发和测试本地连接到数据库的 API 并不是开玩笑。数据库常常成为一个痛点。然而,使用 Docker,这个过程变得更加容易和简单,使复制变得容易。在这篇博客中,我们将了解如何使用 MySQL 数据库对 Golang API 进行 Docker 化,并使其为 Docker Compose 做好准备
为了演示,我创建了这个 RESTful Golang API。我们可以对 MySQL 数据库执行 CRUD 操作,例如创建、删除和编辑计划。我们可以在项目 README 中了解有关端点、方法等的更多信息。我们不会太深入地探讨 API 的工作原理,因为我们的主要目标是关注 Docker 化部分。
对于 Dockerzing 应用程序,我们需要创建一个 Dockerfile。我告诉你,Dockerfile 的编写方式有上百种,没有什么对错之分,每个人/公司都有自己的一套实践和编写方式。在我们的例子中,我们将遵循 Dockerfile 中的四个最佳实践,以获得更好、更优化、更小、更安全的映像。在开始编写 Dockerfile 之前,让我们先了解所有 4 个实践以及为什么要实现它们。
使用更轻的基础镜像:几乎每种语言都有更轻的镜像版本。我所说的“更轻”并不是指小几兆字节,它可以小 10 倍,更轻的原因是它不包含不必要的依赖项,这使得它更小、更安全。是的,更多的依赖会带来更多的安全风险。我们将为 Node、Golang 等提供 Bullseye 和 Alpine 版本。
多阶段构建:它们是 Docker 的超能力之一,它们允许我们并行运行构建步骤,还允许我们通过复制必要的文件和内容来创建最终映像来自其他步骤并且仅具有运行我们的程序所需的项目。
创建二进制文件:许多语言支持从源代码创建二进制文件,使其更小且更易于运行,因为我们不需要处理完整的源代码。而且,我们可以在任何环境中运行,不受语言障碍的影响。
分解层:我们知道 Dockerfile 中的每条指令都是一个层,分解层是加快构建速度的好方法。例如,如果我们从源复制所有文件(以及要安装的依赖项文件),然后安装依赖项,即使我们没有对依赖项进行任何更改,每次重建映像时,它都会复制所有文件并安装依赖项。为了克服这个问题,我们将它们分成几层,并且可以一步复制依赖文件并安装它。在下一步中,我们可以复制所有文件。现在,当我们对代码进行更改并重建时,只会重建我们复制所有文件的层,而保留依赖项步骤(由于没有更改而被缓存)。我们还可以在下面的 Dockerfile 中看到一个示例。我们以这样的方式编写 Dockerfile,即那些变化较少的东西,如基础镜像、依赖项等,将采用自上而下的方法。
所以,这是我们为 Go API 创建的 Dockerfile。
# Build Stage FROM golang:alpine3.20 AS builder WORKDIR /build COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -o /app . # Final Stage FROM alpine:3.20 COPY --from=builder /app /app CMD ["/app"]
在 FROM 中,我们可以看到我们使用了 golang:alpine 版本作为基础镜像,而不是使用成熟的 golang 版本并命名步骤构建器,名称/标签将帮助我们将文件从一个阶段复制到其他。之后,我们创建了一个工作目录。然后,我们不再将所有文件复制在一起,而是复制 go.mod 和 go.sum 并安装依赖项(我已经在分解层点中解释了上面的原因)。
现在,一旦安装了依赖项,我们就会复制剩余的文件。然后,我们通过运行 go build 并使用 -o 输出标志将二进制文件命名为当前位置,从源代码创建一个二进制文件。
现在,事情变得有趣了,在最后阶段,我们不需要 golang 映像等,我们可以使用 Alpine 基础映像,因为我们现在有了二进制文件,并且无论编程如何,我们都可以在任何 Linux 系统上运行语言细节。在下一步中,我们可以将二进制文件从构建器步骤复制到最后阶段并运行该二进制文件。
就是这样。这就是 Dockerzie 我们的应用程序的方式,我们可以通过引入最佳实践(例如创建用户并以非 root 身份运行等)来进一步改进 Dockerfile。现在我们可以使用 Dockerfile 构建一个映像并运行,然后连接到远程或本地 MySQL 服务器,提供所需的凭据,然后访问这些 API 端点。
But, we will not stop here we will take a step further, and we will also run a MySQL server in a container and connect with our app. But, one point to note here is we can run a spin of a MySQL container and connect our API container to that, but there is so much manual work and long commands to type in the terminal, and things can go wrong. To overcome this we will use Docker Compose instead to make our life easier.
Let's create a file called compose.yml and use the blow config.
services: app: container_name: go-api build: context: . dockerfile: Dockerfile image: go-api ports: - 8080:8080 environment: - DB_HOST=mysql - DB_PORT=3306 - DB_USER=user - DB_PASSWORD=password - DB_NAME=my-database depends_on: mysql: condition: service_healthy networks: - go-network mysql: container_name: go-mysql image: mysql:9.0 environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_USER=user - MYSQL_PASSWORD=password volumes: - dbdata:/var/lib/mysql networks: - go-network healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 3 volumes: dbdata: networks: go-network: driver: bridge
It's a pretty basic configuration, but a couple of key things I want to mention is that if we see DB_HOST is mysql, there is no localhost or ip because in compose services communicate with other services by the service name. This is out-of-the-box networking provided by Docker Compose.
Another point, it often happens when working with Docker Compose where we have two services: an app and a database, and the app service starts first and crashes because the database isn't ready when the app tries to connect. To overcome this, we set up a healthcheck for the database to confirm its readiness. Then, in our app service, we can use depends_on with a condition to ensure the app only starts when the database service is healthy.
Now when we do Docker compose for 1st time, we might encounter an error saying permission denied because it doesn't have permission as well as a database with the name my_database, so we need to both by execing into the container.
Even though our app has crashed the DB is still up and running. We can check by doing docker ps.
Now exec into the container by doing docker exec -it
mysql -u root -p
It will ask for the password, enter the password you mentioned in the compose.yml file. Once we log in, we can create a database. Create a database with the same name specified in the compose file. In my case, it's my_database. Execute the below command:
CREATE DATABASE my_database;
Now to give the right privileges and flush it execute the below command.
GRANT ALL PRIVILEGES ON my_database.* TO 'user'@'%'; FLUSH PRIVILEGES;
Once we are done, we need to stop the running compose service and restart again by doing docker compose up
That's it for this blog. I'm glad you're still reading and made it to the end—thank you so much for your support and reading. I sometimes share tips on Golang on Twitter. You can connect with me there.
以上是使用 MySQL 对 Golang API 进行 Docker 化并添加 Docker Compose 支持的详细内容。更多信息请关注PHP中文网其他相关文章!