6
3

More than 1 year has passed since last update.

Dockerでnode.js + PostgreSQLを動かす

Last updated at Posted at 2022-11-10

諸事情でDocker上のnode.jsとPosgreSQLを連携させる必要があったので調査。

方針

最終的にクラウド上のマネージドサービス(Cloud Run想定)でコンテナを動かす予定なのでdocker-composeへの依存は可能な限り下げます。

  • 書ける記述はなるべくDockerfileに記述する
  • 全体制御をdocker-composeに記述する

環境はDocker Desktop for Macを利用。

準備

作業場の確保

cd
mkdir docker-node-pg-test
cd docker-node-pg-test
mkdir app db

PostgreSQL(db)関連の作業

appはdbに依存するので、先にdbの準備をします。

dbに移動

cd db

ディレクトリ作成

mkdir data init

必要なファイル作成

touch Dockerfile .dockerignore init/init.sql

init/init.sqlの記述

init.sql
create table if not exists members(
    id serial primary key,
    name text,
    age int
);

insert into members(name,age) values('hoge',10);

Dockerfileの記述

FROM postgres:14.5-bullseye

COPY ./init/init.sql /docker-entrypoint-initdb.d/init.sql

ENV POSTGRES_USER postgres
ENV POSTGRES_PASSWORD postgres

EXPOSE 5432

イメージのビルド

docker build -t my_postgres .

動作確認

起動

docker run --name my_db -p 5432:5432 -d my_postgres

ログイン

psql -h localhost -U postgres -d postgres

データ確認

postgres=# select * from members;

 id | name | age
----+------+-----
  1 | hoge |  10
(1 row)

どうやら動いているようです。

この状態ではデータは永続化されていないので、コンテナを削除するとデータも消えます(停止では消えません)。

node.js(app)の開発作業

では次にPostgreSQLにアクセスするnode appを作成したいと思います。

appに移動

cd ../app

必要なファイルの生成

touch index.js

モジュールのインストール

npm install express pg

実装

index.js
const express = require("express");
const { send } = require("express/lib/response");
const app = express();

const pg = require("pg");

// PostgreSQL connect info
const pool = new pg.Pool({
    user: "postgres",
    host: "localhost",
    database: "postgres",
    password: "postgres",
    port: 5432
});

// /
app.get("/", (req, res) => {
    res.send("Hello Node.js");
});

// /members
app.get("/members", (req, res) => {

    pool.connect((err, client) => {
        if (err) {
            res.send(err.stack);
        } else {
            const query = {
                text: "select * from members",
                values: [],
            };
            client.query(query, (error, response) => {
                if (error) {
                    res.send(error.stack);
                } else {
                    res.json(response.rows);
                }
            })
        }
    });

})

app.listen(3000, () => {
    console.log("Start server on port 3000.");
});

動作確認

node index.js

http://localhost:3000/
http://localhost:3000/members

[{"id":1,"name":"hoge","age":10}]

PostgreSQLにアクセスするには先述のmy_postgresが動作している必要があります。

node.js(app)のDocker Image化

必要なファイルの生成

touch Dockerfile .dockerignore

Dockerfile

FROM node:18-bullseye-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node","index.js"]

.dockerignore

node_modules
npm-debug.log

イメージのビルド

docker build -t my_node .

実行

docker run --name my_app -p 3000:3000 -d my_node

動作確認(エラーと対応)

/は問題ないが、/membersはPostgreSQLの接続エラーが発生する。

Error: connect ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1300:16)

エラーの原因と対応

原因

localhostはコンテナ自信を指すので(ここではmy_app)当然、PostgreSQLは動いていない。
localhostではなくコンテナ名を指定する必要がある。また、コンテナ間で通信を行うには同じネットワークに所属してる必要があるみたい。

対応

以下の2つの対応が必要。

  • localhostではなく、コンテナ名(my_db)でhostを指定
  • 接続するコンテナを同じネットワークに所属させる

docker-composeを利用している場合はサービス名orコンテナ名でいけるみたい。

localhostではなくコンテナ名でホストを指定

抜粋
// PostgreSQL connect info
const pool = new pg.Pool({
    user: "postgres",
    host: "my_db", //ココを変更
    database: "postgres",
    password: "postgres",
    port: 5432
});

同じネットワークでコンテナを起動

docker network create test-network

docker network lsで一覧が確認できる。

docker run --name my_db --network test-network -p 5432:5432 -d my_postgres
docker run --name my_app --network test-network -p 3000:3000 -d my_node

動作確認(再)

[{"id":1,"name":"hoge","age":10}]

docker-compose化する

cd
cd docker-node-pg-test

touch docker-compose.yml
docker-compose.yml
version: '3'

services:
  app:
    build: ./app
    container_name: my_app
    ports:
      - 3000:3000
    networks:
      - backend
    depends_on:
      - db
  db:
    build: ./db
    container_name: my_db
    ports:
      - 5432:5432
    networks:
      - backend

networks:
  backend:
docker-compose up -d
docker-compose down

Kubernetesで動かす

長くなりそうなのでこちらに分けました。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3