開發和測試本地連接到資料庫的 API 並不是開玩笑。資料庫常常成為一個痛點。然而,使用 Docker,這個過程變得更加容易和簡單,使複製變得容易。在這篇部落格中,我們將了解如何使用 MySQL 資料庫對 Golang API 進行 Docker 化,同時使其為 Docker Compose 做好準備
為了演示,我創建了這個 RESTful Golang API。我們可以對 MySQL 資料庫執行 CRUD 操作,例如建立、刪除和編輯計畫。我們可以在專案 README 中了解有關端點、方法等的更多資訊。我們不會太深入地探討 API 的工作原理,因為我們的主要目標是專注於 Docker 化部分。
對於 Dockerzing 應用程序,我們需要建立一個 Dockerfile。我告訴你,Dockerfile 的寫法有上百種,沒有什麼對錯之分,每個人/公司都有自己的一套實踐和寫作方式。在我們的例子中,我們將遵循 Dockerfile 中的四個最佳實踐,以獲得更好、更優化、更小、更安全的映像。在開始編寫 Dockerfile 之前,讓我們先了解所有 4 個實踐以及為什麼要實現它們。
使用更輕的基礎鏡像:幾乎每種語言都有更輕的鏡像版本。我所說的「更輕」並不是指小幾兆字節,它可以小 10 倍,更輕的原因是它不包含不必要的依賴項,這使得它更小、更安全。是的,更多的依賴會帶來更多的安全風險。我們將為節點、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中文網其他相關文章!