[BooTakHae] 배포 준비(2/2)

Kim Hyen Su·2024년 8월 13일

BooTakHae

목록 보기
19/22
post-thumbnail

배포 준비


개요

이전까지 Docker에 대한 개념을 간단하게 얘기해봤습니다. 이번 포스팅에서는 도커를 어떻게 사용하는지에 대해서 알아보겠습니다.

Docker 사용 관련 포스팅

Docker 설치하기

도커는 Linux 컨테이너 기술이므로 macOS나 windows에 설치할 때 가상머신에 설치가 됩니다.

Docker Desktop 설치(Windows 11 기준)

해당 포스팅은 설치 관련 내용을 다루는 것이 아니므로, 설치 관련 포스팅을 공유합니다.

사용자 권한 설정

docker는 기본적으로 root 권한이 필요합니다. root 가 아닌 사용자가 sudo 없이 사
용하기 위해서는 사용자를 "docker 그룹"에 추가해줘야 합니다.

$ sudo usermod -aG docker $USER # 현재 접속중인 사용자에게 권한 주기
$ sudo usermod -aG docker new-user # new-user 사용자에게 권한 주기

해당 설정을 해준 다음에 재로그인을 해줍니다.

Docker 설치 확인

  • 설치 확인
    설치가 완료되었다면 정상 설치 되었는지 도커 명령어를 입력해 확인해봅니다.

    $ docker version

    output:

    Client:
     Cloud integration: v1.0.35+desktop.13
     Version:           26.1.1
     API version:       1.45
     Go version:        go1.21.9
     Git commit:        4cf5afa
     Built:             Tue Apr 30 11:48:43 2024
     OS/Arch:           windows/amd64
     Context:           default
     
    Server: Docker Desktop 4.30.0 (149282)
     Engine:
      Version:          26.1.1
      API version:      1.45 (minimum version 1.24)
      Go version:       go1.21.9
      Git commit:       ac2de55
      Built:            Tue Apr 30 11:48:28 2024
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          1.6.31
      GitCommit:        e377cd56a71523140ca6ae87e30244719194a521
     runc:
      Version:          1.1.12
      GitCommit:        v1.1.12-0-g51d5e94
     docker-init:
      Version:          0.19.0
      GitCommit:        de40ad0

Docker version을 조회했을 때, 클라이언트와 서버가 나뉘어져 버전 정보가 조회됩니다. 도커는 하나의 실행파일이지만, 실제 클라이언트와 서버 역할을 각각 할 수 있습니다. Docker command 입력 시 Docker client가 Docker server로 명령어를 전송하고 결과를 받아 터미널에 출력해줍니다.

Docker client는 기본적으로 Docker server 소켓을 바라보고 있기 때문에 사용자는 명령어를 바로 내린 뒤 결과를 받는 느낌을 받습니다.

Docker architecture

Docker는 내부 구조를 보면, 구조적으로 클라이언트-서버 아키텍처를 사용합니다. 즉, Docker Daemon과 Docker Client 간에 REST API, UNIX 소켓 또는 네트워크 인터페이스를 사용하여 통신하며, Client에서 요청한 명령어를 Docker Daemon에서 실행하여 결과를 반환해줍니다.

Docker 실행하기

Docker의 실행은 Docker Container의 실행을 의미합니다.

Docker를 실행하는 명령어는 다음과 같습니다.

$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARGs...]

다음은 자주 사용하는 옵션들입니다.

옵션설명
-ddetached mode 흔히 말하는 백그라운드 모드
-p호스트와 컨테이너의 포트를 연결 (포워딩)
-v호스트와 컨테이너의 디렉토리를 연결 (마운트)
-e컨테이너 내에서 사용할 환경변수 설정
--name컨테이너 이름 설정
--rm프로세스 종료시 컨테이너 자동 제거
-it-i와 -t를 동시에 사용한 것으로 터미널 입력을 위한 옵션
--link컨테이너 연결 [컨테이너명:별칭]

ubuntu 16.04 container 실행 테스트

$ docker run ubuntu:16.04

run 명령어를 사용하면 로컬에 이미지가 저장되어 있는지 확인하고 없다면 이미지 다운로드(pull) 한 뒤에 컨테이너를 생성(create)하고 시작(start) 합니다.

위 명령어만 입력한 경우, 컨테이너는 정상적으로 실행됐지만 추가적인 명령어가 전달되지 않았기 때문에 컨테이너는 생성되자마자 종료됩니다. 컨테이너는 프로세스이기 때문에 실행중인 프로세스가 없으면 컨테이너는 종료됩니다.

다음과 같이 명령어를 입력해보겠습니다.

$ docker run --rm -it ubuntu:16.04 /bin/bash

# in container $ cat /etc/issue
Ubuntu 16.04.1 LTS \n \l

# in container $ ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

# in container $ exit
종료

컨테이너 내부에 들어가기 위해서 bash shell을 실행하고 키보드 입력을 위해 -it 옵션을 줍니다. 추가적으로 프로세스가 종료되면 컨테이너는 자동 삭제되도록 하기 위해서 --rm 옵션을 추가해줍니다.

eixt로 bash shell을 종료하게 되면 container도 함께 종료됩니다.

redis container 실행 테스트

redis는 인메모리 기반의 다양한 타입의 데이터들을 제공하는 스토리지입니다. 6379 포트로 통신하며, telnet 명령어로 테스트해 볼 수 있습니다. redis 컨테이너는 백그라운드 모드로 실행하기 위해 -d 옵션을 추가해주며, -p 옵션을 추가해주어 컨테이너의 포트를 호스트 포트로 연결해보겠습니다.

$ docker run -d -p 1234:6379 redis

# redis test
$ telnet localhost 1234
set mykey hello
+OK
get mykey
$5
hello
quit
+OK
...

telnet 사용 설정

-d 옵션으로 인해 컨테이너 실행 후 컨테이너 ID를 출력한 뒤 다시 shell로 돌아오게 됩니다. 컨테이너는 백그라운드 모드에서 동작하고 있고 컨테이너 ID를 이용하여 컨테이너 제어가 가능합니다. -p 옵션을 이용하여 호스트의 1234 port를 컨테이너의 6379 port로 연결하였고, localhost 1234 port로 접속하면 redis를 사용할 수 있습니다.

테스트 결과 redis에 접속하여 새로운 키를 저장하고 불러오는데 성공했습니다. 실행이 간단한건 물론이고 호스트의 포트만 다르게 하면 하나의 서버에 여러개의 redis 서버를 띄우는 것도 간단합니다.

MySQL Contianer 실행 테스트

그 다음으로 MySQL 서버를 실행 테스트하겠습니다. 이번에는 -e 옵션을 사용하여 환경변수를 설정하고 --name옵션을 통해 컨테이너에 읽기 어려운 ID 대신에 쉬운 이름을 부여해보겠습니다.

DockerHub 내 MySQL 페이지에 접속하면 간단한 사용법과 환경변수에 대한 설명이 명시되어 잇습니다. 여러 설정값들이 존재하는데 패스투어드 없이 root 계정을 만들기 위해서 MySQL_ALLOW_EMPTY_PASSWORD 환경변수를 설정해줍니다. 그리고 컨테이너의 이름은 mysqldb로 할당하고 백그라운드 모드로 실행시키기 위해서 -d 옵션을 추가해줍니다. 포트는 기존에 로컬에서 사용하는 db가 존재하기 때문에, 13306 port를 호스트에서 사용하겠습니다.

정상적으로 MySQL 서버가 실행되었습니다.

Docker 기본 명령어

앞서 Docker CLI 명령어인 run을 이용하여 여러개의 컨테이너를 실행했습니다. 이제 컨테이너의 상태를 확인하고 어떠한 이미지들이 설치되어 있는지 확인하는 명령어를 알아보겠습니다.

컨테이너 목록 확인하기(ps)

컨테이너 목록을 확인하는 명령어는 다음과 같습니다.

$ docker ps [OPTIONS]

기본 옵션으로 -a,--all 이 있습니다.

output:

ps 명령어는 실행중인 컨테이너 목록을 보여줍니다. detached mode로 실행중인 컨테이너들이 보입니다. 어떤 이미지를 기잔으로 만들었는지 어떤 포트와 연결이 되어있는지 등 간단한 정보들을 나타냅니다.

다음으로 -a 옵션을 추가로 실행하겠습니다.

$ docker ps -a

output:

맨 처음 실해된 이후에 종료된 컨테이너들도 추가로 보입니다. 컨테이너는 종료되더라도 삭제되지 않고 남아있습니다. 종료된 건 다시 시작할 수 있고 컨테이너의 읽기/쓰기 레이어가 그대로 존재하게 됩니다.

컨테이너 중지하기(stop)

실행중인 컨테이너를 중지하는 명령어는 다음과 같습니다.

$ docker stop [OPTIONS] CONTAINER [CONTIANER ... ]

옵션은 특별한 건 아니고 실행중인 컨테이너를 하나 또는 여러개(띄어쓰기로 구분) 중지 할 수 있습니다.

앞에서 실행했던 MySQL 컨테이너의 실행을 중지해보겠습니다.

$ docker ps
$ docker stop [MySQL CONTAINER ID | NAME]
$ docker ps

output :

stop 명령어로 docker 컨테이너가 정상적으로 중지된 것을 확인할 수 있습니다.

컨테이너 제거하기(rm)

중지된 컨테이너를 삭제하기 위한 명령어는 다음과 같습니다.

$ docker rm [OPTIONS] CONTAINER [CONTAINER ... ]

방금 중지한 MySQL 컨테이너를 삭제해보겠습니다.

$ docker ps -a
$ docker rm [MySQL CONTAINER ID | NAME]
$ docker ps -a

output :

중지된 컨테이너를 일괄로 삭제하기 위해서는 다음과 같은 명령어를 사용할 수 있습니다. docker rm -v $(docker ps -a -q -f status=exited)

이미지 목록 확인하기(images)

도커가 다운로드한 이미지 목록을 보는 명령어는 다음과 같습니다.

$ docker images [OPTIONS] [REPOSITORY[:TAG]]

간단하게 도커 이미지 목록을 확인해보겠습니다.

$ docker images

output:

이미지 다운로드(pull)

이미지를 다운로드하는 명령어는 다음과 같습니다.

$ docker pull [OPTIONS] NAME[:TAG | @DIGEST]

ubuntu:14.04 이미지를 다운받아보겠습니다.

$ docker pull ubuntu:14.04

output:

run 명령어를 입력 시 이미지가 없을 때, 자동으로 다운로드 받도록 해주는데, pull을 언제 사용하는지 궁금할 수 있습니다. pull은 최신 버전의 이미지를 다시 다운 받아올 수 있습니다. 같은 태그이지만 이미지가 업데이트 된 경우 pull 명령어를 통해 새로 받을 수 있습니다.

이미지 삭제하기(rmi)

이미지를 삭제하는 방법은 다음과 같습니다.

$ docker rmi [OPTIONS] IMAGE [IMAGE ... ]

images 명령어를 통해 얻은 이미지 목록에서 이미지 ID를 입력하면 삭제가 됩니다. 단, 컨테이너가 실행중인 이미지는 삭제되지 않습니다. 컨테이너는 이미지 레이어를 기반으로 실행중이기 때문에 당연히 삭제할 수 없습니다.

방금 다운로드 해봤던 ubuntu14.04 이미지를 삭제하겠습니다.

$ docker rmi [ubuntu14.04 이미지 ID]

output:

컨테이너 로그 보기(logs)

컨테이너가 정상적으로 동작하는지 확인하는 좋은 방법은 로그를 확인하는 것입니다. 로그를 확인하는 방법은 다음과 같습니다.

$ docker logs [OPTIONS] CONTAINER

기본 옵션으로 -f, --tail이 있습니다.

기존에 생성한 MySQL 서버의 로그를 확인해보겠습니다.

$ docker logs [MySQL Container ID | NAME]

output:

PS C:\Users\user> docker logs 018f27e9099a
2024-08-14 06:15:24+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-08-14 06:15:24+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2024-08-14 06:15:24+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-08-14 06:15:24+00:00 [Note] [Entrypoint]: Initializing database files
2024-08-14T06:15:24.414709Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.
2024-08-14T06:15:24.415439Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 9.0.1) initializing of server in progress as process 80
2024-08-14T06:15:24.424332Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-08-14T06:15:24.933461Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-08-14T06:15:27.348296Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2024-08-14T06:15:30.144819Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.
2024-08-14 06:15:30+00:00 [Note] [Entrypoint]: Database files initialized
2024-08-14 06:15:30+00:00 [Note] [Entrypoint]: Starting temporary server
2024-08-14T06:15:30.263796Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-08-14T06:15:30.426414Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 123
2024-08-14T06:15:30.446509Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-08-14T06:15:30.921833Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-08-14T06:15:31.311823Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-08-14T06:15:31.311855Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-08-14T06:15:31.320361Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-08-14T06:15:31.347522Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: /var/run/mysqld/mysqlx.sock
2024-08-14T06:15:31.347628Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1'  socket: '/var/run/mysqld/mysqld.sock'  port: 0  MySQL Community Server - GPL.
2024-08-14 06:15:31+00:00 [Note] [Entrypoint]: Temporary server started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leapseconds' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/tzdata.zi' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.

2024-08-14 06:15:32+00:00 [Note] [Entrypoint]: Stopping temporary server
2024-08-14T06:15:32.988315Z 10 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 9.0.1).
2024-08-14T06:15:33.612207Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 9.0.1)  MySQL Community Server - GPL.
2024-08-14T06:15:33.612232Z 0 [System] [MY-015016] [Server] MySQL Server - end.
2024-08-14 06:15:33+00:00 [Note] [Entrypoint]: Temporary server stopped

2024-08-14 06:15:33+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.

2024-08-14T06:15:34.000117Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-08-14T06:15:34.165694Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 1
2024-08-14T06:15:34.184808Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-08-14T06:15:34.671511Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-08-14T06:15:34.936821Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-08-14T06:15:34.936857Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-08-14T06:15:34.943488Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-08-14T06:15:34.970060Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2024-08-14T06:15:34.970132Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

아무 옵션을 추가하지 않은 경우에는 전체 로그를 보여 줍니다. 너무 많으니 --tail 옵션을 사용하여 끝 10줄의 로그만 출력하도록 해보겠습니다.

$ docker logs --tail 10 [MySQL Container ID | NAME ]

output:

그 다음으로 -f 옵션으로 실시간 로그를 확인할 수 있습니다.

$ docker logs -f [MySQL Container ID | NAME ]

위 로그를 그만보려면 ctrl + c 를 입력하면 됩니다.

로그에 대한 자세한 내용

Docker 에서 로그 관리는 컨테이너가 생성하는 표준 출력(stdout)과 표준 오류(stderr) 스트림을 수집하여 수행됩니다. 이러한 로그는 기본적으로 Docker Host에 JSON 파일로 저장됩니다. 이는 Docker의 기본 로깅 드라이버가 json-file이기 때문입니다.

로그 출력 방식
컨테이너에서 실행되는 프로그램의 로그를 파일이 아닌 표준 출력으로 전환하면, Docker는 이 로그를 자동으로 수집하여 관리해줍니다. 이렇게 하면 모든 컨테이너의 로그를 일관된 방식으로 처리가 가능합니다. 이는 특히 다양한 환경에서 동일한 로그 관리 정책을 적용할 수 있게 해줍니다.

로그 저장 및 관리
Docker는 로그를 /var/lib/docker/containers/<container_id>/<container_id>-json.log 경로에 저장합니다. 이 파일은 컨테이너가 삭제될 때까지 쌓이게 되며, 디스크 공간을 많이 차지할 수 있습니다. 따라서 로그 파일의 크기와 개수를 제한하는 로그 로테이션 설정이 필요합니다. 로그 파일의 최대 크기와 파일 갯수를 설정하여, 설정된 크기에 도달 시 새로운 파일로 교체하고 가장 오래된 파일을 삭제하는 방식으로 관리할 수 있습니다.

로그 서비스와 플러그인
Docker는 다양한 로그 드라이버를 지원하여 JSON 파일이 아닌 특정 로그 서비스로 고르글 스트리밍할 수 있습니다. 이는 애플리케이션의 규모가 커지면 기본 로그 저장 방식 대신 외부 로그 서비스를 이용하는 것을 고려해야 하는 이유입니다. 이러한 로그 서비스는 로그의 중앙 집중화, 분석, 모니터링을 용이하게 합니다.

이러한 방식을 통해서 Docker는 컨테이너의 로그를 효율적으로 관리하고, 디스크 공간을 절약하며, 로그 분석을 위한 다양한 옵션을 제공합니다.

컨테이너 명령어 실행하기(exec)

컨테이너를 관리하다 보면 실행중인 컨테이너에 들어가거나 컨테이너의 파일을 수행하고 싶을 때가 있습니다. 컨테이너에 SSH를 설치하면 되지 않을까? 라고 생각할 수 있지만 SSH는 권장하지 않습니다.

이는 보안문제, 컨테이너의 경량성과 효율성 저하 야기, 대체 가능, 복잡성 증가 등의 문제 때문입니다.

컨테이너 명령어를 실행하는 방법은 다음과 같습니다.

$ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

해당 명령어를 사용하여 MySQL 컨테이너에 접속해보겠습니다.

$ docker exec -it mysql /bin/bash

mysql -uroot

quit

output:

키보드 입력이 필요하니 -it 옵션을 주었고 bash shell로 접속하여 마치 가상머신에 들어온 것 같은 느낌이 듭니다. 접속한 이후에는 어떤 작업도 할 수 있습니다.

Docker Container 업데이트

Docker Container를 새로운 버전으로 업데이트 하는 과정에 대해서 알아보겠습니다.

도커에서 컨테이너를 업데이트 하려면 새 버전의 이미지를 다운받고 기존의 컨테이너를 삭제한 후 새 이미지를 기반으로 새 컨테이너를 실행 하면 됩니다.

컨테이너를 삭제한다는 것은 컨테이너 내에서 생성되었던 파일들이 사라진다는 뜻입니다. 데이터베이스인 경우, 그동안 쌓였던 데이터들이 모두 사라진다는 의미이며, 웹 어플리케이션에서는 그동안 사용자가 업로드한 모든 이미지가 삭제되는 것을 의미합니다.

이런 상황을 방지하기 위해서 컨테이너 삭제 시에 유지해야하는 데이터는 반드시 컨테이너가 아닌 외부 스토리지에 저장해줘야 합니다. 이를 위한 방법 중 하난가 AWS S3와 같은 클라우드 서비스를 이용하는 것이고 그렇지 않은 경우, 데이터 볼륨(Data Volume)을 컨테이너에 추가해서 사용해야 합니다. Volume을 사용하면 해당 디렉토리는 컨테이너와 별도로 저장되고 컨테이너를 삭제하더라도 데이터가 지워지지 않습니다.

데이터 볼륨을 사용하는 방법은 여러가지 있는데 해당 포스팅에서는 호스트의 디렉토리를 마운트해서 사용하는 방법에 대해서 알아보겠습니다. run 명령어에서 소개한 옵션중에 -v 옵션을 사용하겠습니다. MySQL 이라면, /var/lib/mysql 디렉토리에 모든 데이터베이스 정보가 담기므로 호스트의 특정 디렉토리로 연결해주면 됩니다.

$ docker run -d -p 13306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=true --name mysql -v /my/own/datadir:/var/lib/mysql mysql:latest

위 명령어를 보면, 호스트의 /my/own/datadir 디렉토리를 컨테이너 내 /var/lib/mysql 디렉토리로 마운트 하였습니다. 이제 데이터베이스 파일은 호스트의 /my/own/datadir 디렉토리에 저장되고 컨테이너를 삭제해도 데이터는 삭제되지 않습니다.

마운트의 의미
호스트 운영체제의 파일 시스템에 있는 특정 디렉토리를 Docker 컨테이너 내부의 파일 시스템에 연결하는 것을 의미합니다. 이 과정을 통해서 두 환경 간의 파일 공유가 가능합니다.

  • 디렉토리 공유 : 마운트를 통해 호스트의 디렉토리에 저장된 파일이 컨테이너 내부에서도 동일하게 접근이 가능하게 됩니다. 이를 통해 컨테이너가 삭제되더라도 데이터가 호스트 안에 남아 있기 때문에 데이터 손실을 방지합니다.
  • 데이터 영속성 : Docker Container 개념 자체가 임시적인 서버이므로, 컨테이너 삭제 시 그 안의 데이터도 함께 삭제됩니다. 하지만, 볼륨 사용 시 호스트의 디렉토리에 마운트하게 되고 이를 통해 영구적으로 데이터를 저장할 수 있게 됩니다.
profile
백엔드 서버 엔지니어

0개의 댓글