我正在学习 docker 并尝试将节点应用程序与 Postgres 数据库连接。但是当我启动容器时,我无法解决以下错误:
注意:添加 Hans Killian 建议的健康检查部分后出现更新错误。
我已经知道问题出在与 Postgres 的连接上。问题是我不明白应该使用哪些参数或如何获取它们。这就是我的困惑。我一直在关注几个教程,所有这些教程,即使它们提供了丰富的信息,也会跳过这一部分,可能认为它太明显了。我尝试了几种组合(通常的 localhost、0.0.0.0 等),但均无济于事。正如您所看到的,有两个图像,一个用于应用程序,另一个用于 Postgres,因此一个应用程序正在尝试连接到另一个应用程序。
接下来,我将列出所有我认为重要的细节。我会很感激你能给我的任何指导,任何“孩子,你必须看看这个地方”。
文件夹结构如下:
数据库Dockerfile如下:
FROM postgres:16-alpine
COPY 00-init.sql /docker-entrypoint-initdb.d/
来自服务器的 Dockerfile 如下:
FROM node:21
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["npm", "run", "dev"]
package.js如下:
{
"name": "server",
"version": "0.1.0",
"description": "Backend",
"main": "./src/server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node .",
"dev": "nodemon ."
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.21.0",
"pg": "^8.13.0"
},
"devDependencies": {
"nodemon": "^3.1.7"
}
}
最后 docker-compose.yaml 如下:
services:
database:
image: postgres
container_name: ${POSTGRES_HOST}
build:
context: ./database
dockerfile: Dockerfile
env_file: .env
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
command: "-p ${POSTGRES_PORT}"
volumes:
- database-v:/var/lib/postgresql/data
pgadmin:
container_name: container-pgadmin
image: dpage/pgadmin4
depends_on:
database:
condition: service_started
ports:
- "5050:80"
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: root
restart: unless-stopped
server:
image: server:1.0.0
container_name: ${SERVER_HOST}
build:
context: ./server
dockerfile: Dockerfile
env_file: .env
ports:
- ${SERVER_PORT}:${SERVER_PORT}
volumes:
- server-v-node-modules:/server/node_modules
depends_on:
database:
condition: service_started
volumes:
database-v:
name: "database-v"
server-v-node-modules:
name: "server-v-node-modules"
包含环境变量的.env文件如下:
SERVER_HOST="server-c"
SERVER_PORT="3000"
POSTGRES_HOST="postgres-c"
POSTGRES_PORT="5432"
POSTGRES_USER="[email protected]"
POSTGRES_PASSWORD="root"
POSTGRES_DB="app-db"
以及 server/src 文件夹中的 server.js,以这种方式连接到数据库:
const express = require("express")
const app = express()
const bodyParser = require('body-parser')
const cors = require("cors")
const PORT = 3000;
const Pool = require('pg').Pool
const pool = new Pool({
host: process.env.POSTGRES_HOST,
port: process.env.POSTGRES_PORT,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB
})
async function connectToDatabase() {
const client = await pool.connect();
try {
const response = await client.query("SELECT * FROM users");
const { rows } = response;
console.log(rows)
} catch(err){
console.log(err)
} finally {
client.release();
}
}
app.listen(PORT, () => {
console.log(`Vianni Server started on port ${PORT}`);
connectToDatabase()
.then(() => console.log("Connected to Postgres!"))
.catch(err => console.error("Error connection to Postgres!", err));
});
最后我用来启动应用程序的命令是
docker compose up
另外,如果您发现任何其他错误或我可以改进的地方,如果您提到它,我将非常感激。
我最诚挚的问候。
这已经在评论中提到了,但是您遇到了依赖性问题:您的应用程序在数据库准备好接受连接之前尝试连接到数据库。您已声明以下依赖项:
depends_on:
database:
condition: service_started
但这完全没用,因为只要 postgres 容器启动,条件就满足了;它不知道数据库是否准备好处理连接,因此您的依赖容器会在 postgres 准备好之前启动。
要纠正该问题,您需要:
service_started
更改为 service_healthy
健康检查应该看起来像这样:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
依赖关系应该如下所示:
depends_on:
database:
condition: service_healthy
完整的
compose.yaml
看起来像:
volumes:
database-v:
name: database-v
server-v-node-modules:
name: server-v-node-modules
services:
database:
image: postgres
container_name: ${POSTGRES_HOST}
build:
context: ./database
dockerfile: Dockerfile
env_file: .env
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
command: -p ${POSTGRES_PORT}
volumes:
- database-v:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
pgadmin:
container_name: container-pgadmin
image: dpage/pgadmin4
depends_on:
database:
condition: service_healthy
ports:
- 5050:80
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: root
restart: unless-stopped
server:
image: server:1.0.0
container_name: ${SERVER_HOST}
build:
context: ./server
dockerfile: Dockerfile
env_file: .env
ports:
- ${SERVER_PORT}:${SERVER_PORT}
volumes:
- server-v-node-modules:/server/node_modules
depends_on:
database:
condition: service_healthy
运行
docker compose up
会导致您的应用程序成功连接到数据库:
$ docker compose up
.
.
.
postgres-c | The files belonging to this database system will be owned by user "postgres".
postgres-c | This user must also own the server process.
.
.
.
postgres-c | 2024-10-11 14:08:51.080 UTC [1] LOG: database system is ready to accept connections
server-c |
server-c | > [email protected] dev
server-c | > nodemon .
.
.
.
server-c | Connected to Postgres!
.
.
.