🎉 berenickt 블로그에 온 걸 환영합니다. 🎉
DevOps
Docker
08-Volume 사용법과 PostgreSQL DB 띄우기

1. Volume 사용법

Volume 사용법을 배워볼 것인데, 데이터베이스(DB)를 컨테이너로 실행해보면서 다뤄봅시다. DB도 직접 설치하고 실행하고 그런 방법을 알면, 직접 Dockerfile 작성해서 이미지로 만들어서 띄워도 되긴 하는데, 근데 DB는 딱히 설정할게 없으면 직접 이미지로 만들 필요는 없고, 미리 만들어진 공식 DB 이미지 같은거 실행만 해도 쉽게 쓸 수 있습니다.


2. PostgreSQL 이미지 다운받기

요즘 인기있는 PostgreSQL을 써봅시다. 엑셀처럼 테이블에 자료를 저장할 수 있는 관계형 데이터베이스입니다. 그러기 위해서 docker desktop 상단에서 postgres 검색해서 원하는 이미지 다운받아옵시다. 저는 postgres:17-alpine 이런거 다운받아왔습니다.

docker_8-1

▲ 근데 DB는 실행할 때 환경변수를 채워서 좀 실행해야합니다. 위처럼 DB 접속용 아이디/비번을 환경변수로 채워야합니다. 포트바인딩은 하고싶으면 합시다.

  • 컨테이너명 : db-container
  • Host port : 5432
  • 환경변수
    • POSTGRES_USER : admin
    • POSTGRES_PASSWORD : qwer1234
1
docker run -d --name db-container -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=qwer1234 postgres:17-alpine

이거말고 터미널에다가 입력하고 싶으면 이렇게 합시다. 명령어가 길고 더러운데, 나중에 docker compose를 배우면 매번 명령어 길게 입력안해도 됩니다.


3. DB 접속해보기

DB에 접속하려면 DBeaver같은 프로그램 쓰면 좀 비주얼적으로 쉽게 접속해볼 수 있고, 아니면 웹서버에서 DB접속해볼 수도 있고, 다 귀찮으면 터미널에서 DB접속도 가능합니다. psql이라는 프로그램이 아마 함께 설치될 것이기 때문에, 그거 쓰면 터미널에서 DB조작이 가능합니다.

1
# docker exec -it 컨테이너이름 /bin/sh
2
$ docker exec -it db-container /bin/sh

일단 DB 컨테이너 터미널로 들어가봅시다. 위 명령어를 터미널에 입력하거나, docker desktop에서 DB 컨테이너의 exec 메뉴로 들어가면 되겠습니다.


4. psql로 DB 다루기

psql은 터미널에서 DB를 조작해볼 수 있는 간단한 프로그램입니다.

1
$ bash # bash 터미널 사용하겠다는 의미
2
$ psql -U admin -W
3
4
$ \l # 데이터베이스 리스트 출력
5
6
# \c 데이터베이스명
7
$ \c postgres
8
9
$ \d # 테이블 구경

PostgreSQL DB 설치된 컨테이너 터미널에 입력하면 DB 접속이 가능합니다. admin자리에는 여러분들 DB접속용아이디 입력하고 -W는 비번 확인하라는 뜻입니다. 그러면 비번 입력하라는데 여러분이 설정한 비번 입력하면 됩니다. 그러면 DB에 접속됩니다.

\l 입력하면 데이터베이스 리스트를 볼 수 있습니다. 여기서 데이터베이스라고 부르는건 테이블을 담아놓는 일종의 폴더입니다. \c 데이터베이스명 누르면 거기로 접속할 수 있고, \d 누르면 그 안에 있는 테이블들을 구경할 수 있습니다. 테이블은 엑셀 파일 하나입니다. 이제 테이블 하나 만들어서 거기다가 SQL 문법으로 데이터 저장하고 그럴 수 있습니다.


5. 데이터는 volume 써야 유지가능

컨테이너로 DB를 띄우면 문제가 있습니다. 컨테이너를 껐다켜면 항상 안에 있던 내용이 초기화되기 때문에 DB에 있던 데이터도 당연히 날라갑니다. 껐다켜도 데이터를 유지하고 싶으면 데이터를 volume에 복사해두면 됩니다.

docker_8-2

Docker desktop 왼쪽 메뉴보면 volume 메뉴가 있는데 여기서 볼륨을 하나 만들 수 있습니다. 볼륨이 뭐냐면 “컨테이너에서 발생한 데이터를 백업해둘 폴더”입니다. 실은 그냥 하드디스크에 폴더 하나 만드는거랑 똑같습니다. 근데 docker에서 관리해주는 폴더일 뿐임. test라는 볼륨을 하나 만들어줍니다.

1
docker volume create 볼륨이름 # 볼륨 생성
2
docker volume ls # 볼륨 목록
3
docker volume inspect 볼륨이름 # 볼륨 상세보기
4
docker volume rm 볼륨이름 # 볼륨 삭제

터미널에서 볼륨 생성, 삭제도 가능합니다. 차례로 볼륨 생성, 목록, 상세보기, 삭제 명령어입니다. 볼륨을 만들어놨으면 이제 컨테이너 데이터를 띄울 때 이 볼륨을 장착할 수 있습니다.

  • 그러면 컨테이너에 있던 데이터는 자동으로 볼륨으로 복사되고,
  • 나중에 컨테이너 띄울 때 볼륨에 있던 데이터를 컨테이너에 집어넣어서 띄울 수 있습니다.

이제 컨테이너에 있던 데이터 영구보관이 가능해지겠군요.


6. volume 장착해서 DB 컨테이너 띄우기

방금 띄운 postgres 컨테이너는 삭제하고, 새롭게 postgres 컨테이너를 만들어줍니다.

  • 컨테이너명 : db-container
  • Host port : 5432
  • Volumes : postgres_vol
    • cf. 없는 볼륨명은 자동으로 생성해줌
  • Container path : /var/lib/postgresql/data
  • 환경변수
    • POSTGRES_USER : admin
    • POSTGRES_PASSWORD : qwer1234

PostgreSQL의 경우 /var/lib/postgresql/data 이런 폴더에 DB 데이터를 저장해두기 때문에, 그걸 볼륨에 복사하라고 하면 됩니다. MySQL을 쓰는 경우 /var/lib/mysql 이런 폴더에 DB 데이터를 저장해두기 때문에, 그걸 볼륨에 복사하라고 하면 됩니다. 이런건 DBMS 종류마다 다르기 때문에 찾아서 씁니다.

💡 터미널 명령어로 컨테이너에 볼륨을 장착하려면, 컨테이너 띄울 때 -v 명령어 쓰면 됩니다.

1
# docker run -v 볼륨이름:경로 이미지명
2
$ docker run -v 볼륨이름:/var/lib/postgresql/data posgres:17-alpine

-e로 환경변수 집어넣는건 알아서 해봅시다. 그리고 컨테이너 안에 있는 어떤 폴더를 볼륨에 복사해둘건지 경로도 맘대로 정하면 됩니다.


7. 볼륨에 데이터 저장되나 확인해보자

DB데이터가 진짜로 볼륨에 복사되나 확인해봅시다. 그러기 위해서 DB 컨테이너 접속해서 테이블에 데이터 몇개 집어넣어봅시다.

방금띄운 컨테이너 터미널에 접속합니다.

1
$ bash
2
$ psql -U admin -W # psql 켜기
3
$ \s # 데이터베이스 목록 조회
4
$ \c postgres # postgres라는 이름의 데이터베이스에 접속

이제 여기다가 SQL 문법을 좀 짜서 테이블을 생성하고 거기다가 데이터도 하나 넣어봅시다.

1
CREATE TABLE product ( title VARCHAR(100) );
2
3
INSERT INTO product VALUES ('shirt');
4
INSERT INTO product VALUES ('shirt1');
5
6
SELECT * FROM product;

차례로 테이블 만들기, 테이블에 행 집어넣기, 테이블 출력하기 SQL 문법입니다.

1
########### postgres 폴더
2
title
3
--------
4
shirt
5
shirt1

▲ 지금 DB에 만든걸 그림으로 보자면 이런 식으로 데이터를 하나 저장해봤는데, 볼륨을 장착했을 경우 이 데이터가 볼륨에도 복사됩니다.

이제 컨테이너를 아예 삭제했다가 다시 띄워도 같은 볼륨만 잘 장착하면 데이터를 다시 불러올 수 있는데, 남의 말 믿지 말고 진짠지 확인하려면, 직접 컨테이너 지웠다가 다시 볼륨넣어서 띄워보시면 되겠습니다. 그 다음에 데이터 그대로 남아있는지 psql로 데이터베이스와 테이블 접속해서 SQL 문법으로 출력도 해봅시다.


8. bind mount

볼륨은 “docker에서 관리해주는 폴더”같은 개념입니다. docker가 관리해주는게 싫으면 여러분이 컴퓨터에 만들어둔 폴더를 볼륨으로 장착할 수도 있습니다. 어떻게 하냐면 volume 만들 때 여러분 로컬 폴더 경로 집어넣어주면 됩니다.

1
docker run -v /내컴퓨터폴더경로:/컨테이너경로 이미지명

이러면 내 폴더에 있던 데이터들을 볼륨으로 장착해줍니다. 이걸 bind mount라고 부릅니다. 내가 이 데이터를 주기적으로 백업해야 되는 경우에는 bind mount 방식으로 쓰는게, 나중에 데이터 찾을 때 편리할 수도 있긴 합니다.

하지만 실제 백업을 해야된다면 직접 손으로 하는 것 보다는 볼륨을 장착해서 거기 내용을 압축해서 AWS이런데 업로드하는 별도의 이미지를 만들어서 실행해놓으셔도 되긴 합니다.

  • 아니면 그런 백업 역할의 이미지를 누가 이미 만들어둔 것도 많고,
  • 그런거 실행만 해두면 알아서 주기적으로 볼륨을 가져와서 AWS 이런데 백업해주니까 그런거 돌려두셔도 됩니다.
  • https://github.com/offen/docker-volume-backup

9. 결론

컨테이너 데이터를 영구적으로 보존해야 된다면 볼륨을 만들어서 장착해봅시다. 그럼 컨테이너 데이터볼륨에 자동으로 복사되고, 나중에 컨테이너 띄울 때 볼륨에 있던 내용을 컨테이너에 집어넣어서 띄울 수도 있습니다.

그래서 데이터베이스 컨테이너 띄울 때 유용한데, 하지만 컨테이너는 쉽게 띄우고, 쉽게 교체하고, 다른 곳으로 옮기고 이런게 장점인데, 데이터베이스는 그런 것 보다 안정성이 중요해서, 실은 데이터베이스는 컨테이너로 만들어서 띄우는 경우가 많지는 않습니다. 따로 데이터베이스 호스팅을 받아서 거기서 안전하게 데이터들을 관리하는게 나을 수 있습니다.

💡 cf. 서버에서 PostgreSQL에 접속해서 이거저거 SQL 실행하려면

(1) 터미널에서 npm install pg 입력해서 라이브러리 설치하고,

1
const { Pool } = require('pg');
2
const pool = new Pool({
3
host: 'db', //DB컨테이너이름
4
database: 'postgres', //접속할Database이름
5
user: 'admin', //유저이름
6
password: 'qwer1234', //비번
7
port: 5432,
8
});

(2) 이런 코드 서버에 작성해놓고

1
app.get('/add', async (req, res) => {
2
try {
3
await pool.query(`CREATE TABLE IF NOT EXISTS products (
4
id SERIAL PRIMARY KEY,
5
title VARCHAR(255),
6
price INT
7
);`);
8
res.send('SQL 실행 완료')
9
}
10
catch (err) {
11
console.log(err)
12
res.send('실패')
13
}
14
});

(3) SQL 실행이 필요할 때 마다 pool.query() 쓰면 됩니다.