如何用Docker Compose建立一個本地開發環境

如何用Docker Compose建立一個本地開發環境

作為一個開發者,當你從事一項服務時,你會面臨一個工作環境的問題。當我說到工作環境時,我想到的不是IDE、堆疊、作業系統、庫等等。我想的是我們的服務所處的環境。

這些天,我們的服務通常被裝在一些容器裡,放在某種分散式系統中。大多數容器和其他移動部件都由Kubernetes、Nomad和類似的協調系統控制。

無論它們有多大區別,它們都控制著容器化服務。他們做的不僅僅是控制容器;至少,我們關心的是他們擁有容器。

問題

所以,我正在為一些服務開發一個功能。當我檢查程式碼時,我意識到該服務有外部依賴性:其他服務,一些儲存(資料庫),訊息系統(Kafka)。

在理想的世界裡,我不會太在意。我會新增一個API端點和一些DTOs,並對外部服務進行一些呼叫。為了確保一切正常,我會新增一些單元測試。

後來,當我完成程式碼時,我會把它推到工作環境中,以測試服務與其他元件的整合。而一切都很順利。

在現實世界中,並不是這樣的。當你使用新做的功能時,會存在一些bug、錯誤的假設和新發現的約束。

這裡的痛苦是等待程式碼被編譯和部署。我做了一系列的小改動,一個接一個。每次修改後,我都會把程式碼推送到工作環境中。然後你就進入了一個提交、推送、構建和測試的迴圈,如果通過CI來完成,就會非常慢。

想法: 複製所需的依賴關係

簡單。複製所需的依賴關係。

但是,由於你的依賴性有依賴性,你必須複製這些依賴性,然後這些可以有依賴性,等等。這是否意味著複製整個系統?不,那是不聰明的。我們需要弄清楚所需依賴關係的最小集合。我們的想法是隻複製一組最小的依賴關係。

好的方面是,複製不需要像在工作環境中那樣精確。它可以用更少的記憶體和CPU工作。例如,假設工作環境中的Postgres資料庫版本為14.1.1。在這種情況下,你將使用相同的Postgres版本,但更輕(記憶體和CPU更少)。儲存在副本中的資料將是原始資料的一個片段。

如何做到這一點?

由於有了容器,你可以快速地執行任何程式,而不需要混亂的安裝。如果你不相信我,試著在你的本地機器上安裝Postgres資料庫,然後用Docker做同樣的事情(執行容器化的Postgres)。然後比較一下經驗,特別是如果你需要執行同一個服務的幾個例項,但不同的版本。

所以,容器。我認為,docker compose是這項工作的完美選擇。

例子

讓我描述一下情況:

  • 我的目標服務,名為app
  • 依賴於名為next的服務
  • app的依賴性為Postgres DB
  • next服務的MariaDB的依賴關係
  • Kafka的依賴關係

讓我快速描述一下配置。

服務app和next

這兩個服務共享一個程式碼庫。在容器啟動之前,必須先構建一個映象。映象是通過兩步docker構建的:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM golang:latest as builder
WORKDIR /app
COPY . /app/
RUN go mod tidy
RUN go build -o app
FROM golang:buster
WORKDIR /app
COPY --from=builder /app/app /app/
ENTRYPOINT [ "/app/app" ]
FROM golang:latest as builder WORKDIR /app COPY . /app/ RUN go mod tidy RUN go build -o app FROM golang:buster WORKDIR /app COPY --from=builder /app/app /app/ ENTRYPOINT [ "/app/app" ]
FROM golang:latest as builder
	WORKDIR /app
	COPY . /app/
	RUN go mod tidy
	RUN go build -o app
	FROM golang:buster
	WORKDIR /app
	COPY --from=builder /app/app /app/
	ENTRYPOINT [ "/app/app" ]

但配置是不同的。服務app使用來自檔案的配置,而next服務從環境變數中獲得配置。同時,服務app從Kafka寫和讀,所以它需要等待broker服務。

在另一個方面,next服務只有一個依賴:mariaDB

服務app

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
app:
container_name: echo
build: .
environment:
KAFKA_BROKER: "broker:29092"
ports:
- 9999:9999
volumes:
- ./configs:/app/configs
depends_on:
- liquibase_pg
- broker
restart: always
app: container_name: echo build: . environment: KAFKA_BROKER: "broker:29092" ports: - 9999:9999 volumes: - ./configs:/app/configs depends_on: - liquibase_pg - broker restart: always
app:
	container_name: echo
	build: .
	environment:
	KAFKA_BROKER: "broker:29092"
	ports:
	- 9999:9999
	volumes:
	- ./configs:/app/configs
	depends_on:
	- liquibase_pg
	- broker
	restart: always

指令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
build: .
build: .
build: .

它告訴Docker,映象需要先被構建。構建環境是當前目錄。

接下來,指示Docker將一個卷從本地FS掛載到容器FS:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
volumes:
- ./configs:/app/configs
volumes: - ./configs:/app/configs
 volumes:
	- ./configs:/app/configs

並等待依賴性:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
depends_on:
- liquibase_pg
- broker
depends_on: - liquibase_pg - broker
depends_on:
	- liquibase_pg
	- broker

其中liquibase_pg是一個一次性服務,在pg服務啟動後啟動,以便用Liquibase建立DB模式。只有當模式被建立後,app服務才能啟動。

next服務:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
next:
container_name: beta
build: .
ports:
- 8888:8888
depends_on:
- liquibase_maria
environment:
DB_HOST: maria
DB_PORT: 3306
DB_USER: docker
DB_PASSWORD: password
DB_NAME: docker
DB_TYPE: MARIA
APP_PORT: 8888
TARGET: "http://echo:9999"
ERROR_RATE: 10
DELAY: 3000
restart: always
next: container_name: beta build: . ports: - 8888:8888 depends_on: - liquibase_maria environment: DB_HOST: maria DB_PORT: 3306 DB_USER: docker DB_PASSWORD: password DB_NAME: docker DB_TYPE: MARIA APP_PORT: 8888 TARGET: "http://echo:9999" ERROR_RATE: 10 DELAY: 3000 restart: always
next:
	container_name: beta
	build: .
	ports:
	- 8888:8888
	depends_on:
	- liquibase_maria
	environment:
	DB_HOST: maria
	DB_PORT: 3306
	DB_USER: docker
	DB_PASSWORD: password
	DB_NAME: docker
	DB_TYPE: MARIA
	APP_PORT: 8888
	TARGET: "http://echo:9999"
	ERROR_RATE: 10
	DELAY: 3000
	restart: always

next服務是等待Liquibase在MariaDB中建立模式。

其他服務

其他服務代表依賴性: Postgres DB、MariaDB、Kafka broker和Liquibase。有趣的是,設定所有這些依賴關係是非常容易的。如果你在官方文件或DockerHub上搜尋它們,你會發現關於設定它們的說明。

最重要的是要設定正確的服務啟動順序。例如,Kafka代理應該在任何使用它的服務之前啟動。DB的情況也是如此。

關於名稱

有一件事需要注意:服務名稱和容器名稱。它們可以是不同的。但如果它們是相同的,那就更好了。這將使你的生活更容易。在我的例子中,它們是不同的。原因是要明確這種區別。

在使用docker compose命令時,你會使用服務名稱,因為你會與服務進行互動。另一方面,容器只看到容器。這意味著你將使用容器名稱來稱呼另一個容器。例如,在我的例子中,app服務容器是echo。它週期性地呼叫另一個容器。為了稱呼那個容器,我必須使用容器名:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
TARGET="http://beta:8888"
TARGET="http://beta:8888"
TARGET="http://beta:8888"

原因是Docker使它的網路,而這些容器是通過名字來解決的。看看服務next環境變數:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
environment:
DB_HOST: maria
DB_PORT: 3306
DB_USER: docker
DB_PASSWORD: password
DB_NAME: docker
DB_TYPE: MARIA
APP_PORT: 8888
TARGET: "http://echo:9999"
ERROR_RATE: 10
DELAY: 3000
environment: DB_HOST: maria DB_PORT: 3306 DB_USER: docker DB_PASSWORD: password DB_NAME: docker DB_TYPE: MARIA APP_PORT: 8888 TARGET: "http://echo:9999" ERROR_RATE: 10 DELAY: 3000
  environment:
	DB_HOST: maria
	DB_PORT: 3306
	DB_USER: docker
	DB_PASSWORD: password
	DB_NAME: docker
	DB_TYPE: MARIA
	APP_PORT: 8888
	TARGET: "http://echo:9999"
	ERROR_RATE: 10
	DELAY: 3000

當一切都設定好後,你可以用一個命令啟動整個系統:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
docker compose up -d
docker compose up -d
docker compose up -d

重建應用程式、日誌和停止工作

你設定了這一切。開始對你的功能進行工作,在某個時刻,你想看看你做了什麼。現在你必須重建你的app:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
docker compose -f <compose file> up --detach --build <service name>
docker compose -f <compose file> up --detach --build <service name>
docker compose -f <compose file> up --detach --build <service name>

使用預設的docker-compose檔名,你可以省略帶有檔名的部分:compose.yml

要獲得日誌:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
docker compose logs -f <container name>
docker compose logs -f <container name>
docker compose logs -f <container name>

要停止整個系統:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
docker compose down
docker compose down
docker compose down

要停止並刪除所有卷:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
docker compose down -v
docker compose down -v
docker compose down -v

總結

我希望你喜歡這個想法。它可以做得更好,但這是一個好的開始。我相信你可以改進它。如果你有任何問題,請隨時提出。

參考文獻

評論留言