김코딩

코딩에도 밀키트가 있더라(docker) - 1 본문

개발팁

코딩에도 밀키트가 있더라(docker) - 1

김코딩딩 2025. 6. 20. 17:42

이번에는 필자가 docker에 대해서 공부했던 것을 하나하나 작성해보려고 한다.

나만의 언어로 작성하려고 하니까 글이 불편하게 느껴질수도 있다. 하지만 확실한 공부, 뇌를 사용하는 공부를 하기 위해서 공부한 내용을 정리해보려고 한다.


docker를 왜 사용하는가?

현업에서는 대부분 docker를 많이 사용한다고 한다. 왜? 사람들이 도커를 많이 사용하는걸까? 무엇이 그렇게 좋을까? 라고 생각해보았는데, 가장 큰 장점은 이것이라고 생각한다.

 

이식성 : 특정 프로그램을 다른 곳으로 쉽게 옮겨서 설치 및 실행할 수 있는 특성

예시) 만약에 철수영수가 있다고 하자.

철수는 컴퓨터에 MySQL을 정상적으로 깔았다. 그런데 영수철수가 알려준 방법으로 MySQL을 다운받으니까 자꾸 에러가 난다. 다른 버전을 설치하였거나, 운영체제(Window, Mac OS 등)가 다른 원인들이 있을수가 있다.
그리고 항상 새로운 컴퓨터를 구매할 때, 이런 툴을 설치해야하는게 귀찮을 수 있다.
이것을 해결하기 위해 나타난게 docker 이다. docker를 사용하면 명령어 한줄로 MySQL을 에러 없이 설치하고 실행할 수 있다. 

장점 :
1. 항상 일관되게 프로그램을 설치할 수 있다.
2. 각 프로그램이 독립적인 환경에서 실행되기 때문에 프로그램 간에 서로 충돌이 일어나지 않는다.

docker란 무엇인가?

컨테이너를 사용하여 각각의 프로그램을 분리된 환경에서 실행 및 관리할 수 있는 툴이다.

 

컨테이너를 사용한다? 보통 컨테이너라면 물건을 여러개 담을 수 있는 박스같은 것을 생각할 것 이다. 그렇다면 docker에서 컨테이너란 무엇인지 알아보자


컨테이너(Container)란? ⭐⭐⭐⭐⭐

하나의 컴퓨터 환경 내에서 독립적인 컴퓨터 환경을 구성해서, 각 환경에 프로그램을 별도로 설치할 수 있게 만들어 준다.

 

한 컴퓨터 내에 여러개의 컨테이너가 존재할 수 있고, 그런 컨테이너를 가지고 있는 컴퓨터를 호스트 컴퓨터라고 부른다.

 

컨테이너의 독립성

  • 디스크(저장 공간) : 각 컨테이너마다 서로 각자의 저장 공간을 가지고 있다. 일반적으로 A 컨테이너에서 B 컨테이너에 있는 파일에 접근할 수 없다.
  • 네트워크(IP, Port) : 각 컨테이너마다 고유의 네트워크를 가지고 있다. 컨테이너는 각자의 IP 주소를 가지고 있다.

한줄 요약 : 음 호스트 컴퓨터가 주방이라면, 컨테이너는 각각 독립적으로 포장된 밀키트처럼, 각자 필요한 재료와 조리도구를 갖춘 요리 공간이다.


이미지(image)란? ⭐⭐⭐⭐⭐

이미지(image)는 프로그램을 실행하는 데 필요한 설치 과정, 설정, 버전 정보 등을 포함하고 있다. 즉, 프로그램을 실행하는 데 필요한 모든 것을 포함하고 있다.

 

음 만약에 MySQL 서버를 이미지로 만들었다면, 이 이미지를 docker로 실행시키는 순간 MySQL 서버가 컨테이너 환경에서 실행된다. 그렇다면  MySQL을 일일이 설치할 필요없이 MySQL을 사용할 수 있게 된다.

 

한줄 요약: 컨테이너가 각각 독립적으로 포장된 밀키트라면, 이미지는 컨테이너를 만들기 위한 레시피 인 것 같다.


이미지(image) 명령어 ⭐⭐⭐⭐⭐

1. 이미지 다운 명령어 : docker pull (이미지명): tag -> 이미지를 다운로드 할 때 Dockerhub이라는 곳에서 이미지를 다운 받는다.

-> 그냥 이미지명만 작성하면 tag가 latest로 자동 설정된다.

 

다운받은 이미지 확인 명령어 : docker image ls

REPOSITORY: 이미지 이름

TAG: 이미지의 버전

IMAGE_ID: 이미지 아이디

CREATED: 이미지가 만들어진 날짜(다운로드일 X)

SIZE: 이미지 용량

 

2. 이미지 삭제 명령어 : docekr image rm 이미지 ID 또는 REPOSITORY(이미지명)

-> 컨테이너에서 사용중인 이미지는 삭제가 불가능하다

 

3. 컨테이너에서 사용중인 이미지 삭제 명령어 : docker image rm -f 이미지 ID 또는 REPOSITORY(이미지명)

 

4. 컨테이너에서 사용하고 있지 않은 이미지만 전체 삭제 명령어 : docker image rm $(docker images -q)

 

5. 컨테이너에서 사용하고 있는 이미지를 포함해서 전체 이미지 삭제 : docker image rm -f $(docker images -q)

 

docker images -q : 시스템에 있는 모든 이미지의 ID를 반환한다. 여기서 -q 옵션은 quite를 의미하며, 상세 정보 대신에 각 이미지의 고유 한 ID만 표시하도록 지시한다.


컨테이너(container) 명령어 ⭐⭐⭐⭐⭐

 

컨테이너 생성 : docker create 이미지명 (예: docker create mysql)

-> 이미지를 바탕으로 컨테이너를 생성한다. 이때, 컨테이너를 실행시키지는 않는다.

 

모든 컨테이너 조회 : docker ps -a

 

컨테이너 실행 : docker start 컨테이너명 or 컨테이너 ID

 

실행중인 컨테이너 조회: docker ps

 

컨테이너 중단 :

1. docker stop 컨테이너 ID -> 컨테이너를 정상적으로 종료하는것 (컴퓨터를 컴퓨터 종료 버튼을 눌러서 끄는 것)

2. docker kill 컨테이너 ID -> 컨테이너를 비정상적으로 종료하는 것 (컴퓨터의 전원버튼을 눌러서 강제로 종료시키는 것)

 

중지되어있는 컨테이너 삭제 : docker rm 컨테이너 ID 

 

실행중인 컨테이너 삭제 : docker rm -f  컨테이너 ID

 

중지되어 있는 컨테이너 모두 삭제 : docker rm $(docker ps -qa)

 

실행중인 컨테이너 모두 삭제 : docker rm -f $(docker ps -qa)

 

보통 현업에서는 create랑 start를 따로 작성하는 일은 별로 없다고 한다.

 

컨테이너 생성과 동시에 실행 : docker run 이미지명 <- 포그라운드(foreground)에서 실행

                                              docker run -d 이미지명 <- 백그라운드(background)에서 실행

포그라운드 : 내가 실행시킨 프로그램의 내용이 화면에 출력되고 있는 상태 -> 터미널을 완전히 점유하고 있어서 포그라운드 실행중일 때에는 터미널 작동 x, 컨트롤 + c 눌러서 종료 시킨 후에 터미널을 사용해야함

백그라운드 : 내가 실행시킨 프로그램이 컴퓨터 내부적으로 실행되는 상태 -> 백그라운드 상태에서는 컨테이너가 실행중일 때에도 터미널을 사용할 수 있다.

 

그렇다면 백그라운드가 좋은거 아닌가요? 왜 포그라운드를 사용하나요?

-> 둘 다 각각의 장점이 있다.

구분 포그라운드 실행 (docker run) 백그라운드 실행 (docker run -d)
실행 방식 터미널에 프로그램 실행 내용이 바로 출력됨 터미널에 아무 출력 없이 내부적으로 실행됨
터미널 사용 컨테이너 실행 중엔 터미널 사용 불가 컨테이너 실행 중에도 터미널 사용 가능
종료 방법 Ctrl + C로 종료 (컨테이너도 같이 종료됨) docker stop [컨테이너 ID]로 수동 종료 필요
용도 디버깅, 테스트, 로그 실시간 확인 서비스 운영, 배포, 장시간 실행
장점 실행 상태를 직접 확인 가능, 실시간 로그 확인 용이 터미널 자유롭게 사용 가능, 장시간 실행에 적합

 

컨테이너에 이름 붙여서 생성 및 실행하기 : docker run -d --name [컨테이너 이름] 이미지명[:태그명]

                                                           예: docker run -d --name my-web-server nginx


호스트의 포트와 컨테이너의 포트를 연결하기 : docker run -d -p 호스트 포트:컨테이너 포트 컨테이너명

                                                                예 : docker run -d -p 4000:80 nginx

나는 이 부분이 제일 헷갈렸다. 음 쉽게 설명하자면 내 로컬 포트를 4000번으로 설정해놓고, 컨테이너의 포트를 80으로 설정해놓는다는 말이다. 이제 나는 실행을 시킬 때 localhost:4000을 실행시키면 자동으로 80번 포트로 연결이 되어서 컨테이너를 사용할 수 있다는 말이다!


컨테이너(container) 로그 조회 명령어

포그라운드 실행일 때에는 로그가 자동으로 나와서 사용할 일이 없겠지만, 백그라운드 실행일때에는 로그를 보고싶다면 직접 명령어를 입력하여 로그를 조회하여야 한다.

 

특정 컨테이너의 모든 로그 조회 : docker logs 컨테이너 ID 또는 컨테이너명

 

최근 로그 10줄만 조회하기 : docker logs --tail 10 컨테이너 ID 또는 컨테이너명

 

컨테이너에 기존에 존재하는 로그 조회 + 그 다음부터 생성되는 로그를 실시간으로 보고 싶은 경우 : docker logs -f 컨테이너ID

 

기존에 존재하는 로그는 조회하지 않기 + 지금부터 생성되는 로그를 실시간으로 보고싶은 경우 : docker logs -- tail 0 -f 컨테이너ID


실행중인 컨테이너(container) 내부에 접속하기

실행 중인 컨테이너 내부에 접속하기 : docker exec -it 컨테이너ID bash

bash : 쉘(shell)의 일종

-it : -it 옵션을 사용해야 명령어를 입력하고 결과를 확인할 수 있다. -it를 적지 않으면 명령어를 1번만 실행시키고 종료되어 벌니다.

-it를 적어야 계속해서 명령어를 입력할 수 있다.

 

컨테이너 내부에서 나가기 : exit


도커 볼륨(Docker Volume) ⭐⭐⭐⭐⭐

도커 볼륨이란 컨테이너 내부에 있는 데이터를 호스트 컴퓨터(내 로컬 컴퓨터)에 저장하는 방법이다. 도커 컨테이너에서 데이터를 영속적으로 저장하기 위한 방법

 

볼륨을 사용하는 명령어 : docker run -v [호스트의 디렉토리 절대 경로] : [컨테이너의 디렉토리 절대 경로] [이미지명]

 


볼륨 없이 데이터를 저장한다면!!

 

docker run -e MYSQL_ROOT_PASSWORD=password123 -d -p 3307:3306 mysql

 -> 컨테이너 내부의 MySQL 비밀번호를 password123으로 지정하고, 백그라운드로 실행하고, 로컬 컴퓨터에 3307포트를 사용해 컨테이너 내부의 3306 포트를 실행한다.


docker ps

docker exec -it 컨테이너ID  bash

-> docker ps 명령어를 사용하여 현재 실행중인 컨테이너를 확인한 후에

-> docker exec -it 0a42 bash를 사용해 실행중인 컨테이너 내부로 들어간다.


mysql -u root -p (이거는 docker 명령어가 아니고 mysql 명령어다!)

-> 컨테이너 내부의 mysql에 비밀번호를 입력하여 접속해준다.


show databases (이거도 mysql 명령어다!)

create database 데이터베이스 명 (이거도 mysql 명령어다!)

-> 내부에 mydatabase라는 데이터베이스를 생성해주었다!


docker rm -f 컨테이너 ID

-> 이제 실행중인 mysql 컨테이너를 강제 종료 시켰다.


-> 다시 mysql 컨테이너를 생성하고 실행시켜보면 이전에 만들어놓은 mydatabase라는 데이터베이스가 사라진 것을 확인할 수 있다!!!!

 

한줄 요약 : 도커 컨테이너를 사용해서 데이터를 저장한다면, 컨테이너를 삭제하고, 다시 실행을 하면 저장된 데이커가 삭제된다.

이제 도커 볼륨(docker volume)을 사용해서 호스트 컴퓨터에 데이터를 저장하면, 컨테이너가 삭제되어도 데이터가 영구적으로 보관이 된다. 


도커 볼륨(docker volume)을 사용한 데이터 저장

1. 데이터를 저장하고 싶은 위치에 폴더를 생성합니다.

필자의 경우에는 C:\Users\user\study\docker-mysql 파일에 데이터를 저장 할 예정입니다.

 

2. docker run -e MYSQL_ROOT_PASSWORD=password123 -d -p 3307:3306 -v /c/Users/user/study/docker-mysql/mysql_data:/var/lib/mysql mysql

 

docker run -e MYSQL_ROOT_PASSWORD=password123 -d -p 3307:3306 C:/Users/user/study/docker-
mysql/mysql_data:/var/lib/mysql

기존에 이 경로를 사용하였는데 바로 오류를 마주하였습니다.

 

 

chat gpt를 사용하여 오류를 분석한 결과

윈도우에서는 볼륨마운트(-v) 형식으로 바꾸고 작성해야한다고 답변을 받았습니다.

 

docker run -e MYSQL_ROOT_PASSWORD=password123 -d -p 3307:3306 -v /c/Users/user/study/docker-mysql/mysql_data:/var/lib/mysql mysql

-> 경로를 이렇게 변경하여 작성해주었습니다!

그 결과로 컨테이너가 정상적으로 실행이 되는것을 확인할 수 있었습니다.

 

위의 예제와 동일하게 컨테이너 내에서 mysql을 실행시켜서 데이터베이스를 생성하고 나와주었습니다.

 

 

그 후에 컨테이너를 삭제한 후, 다시 컨테이너를 실행시켜주었습니다. 이전에는 컨테이너 삭제 후 컨테이너를 다시 실행하면, mysql에 있는 데이터베이스가 삭제되어있는 것을 확인하였습니다.

 

하지만 이번에는?!

헐!!!!!!! mydatabase 라는 데이터베이스가 그대로 살아있습니다!!!!

 

도커 볼륨(docker volume)이라는 개념을 사용하면 컨테이너에서 저장한 데이터를 이전에 지정해준 폴더 경로에 데이터를 저장해줍니다. 즉, 컨테이너에서 저장한 데이터를 로컬(호스트 컴퓨터)에 저장이 되게 됩니다.

 

주의사항 1. 비밀번호 변경이 적용되지 않는 이유

그런데 여기서 한가지 조심해야할게 있습니다. 사용자가 mysql 컨테이너를 한번 더 지우고, 이번에는 비밀번호를 변경해서 다시 생성 후 실행하면 어떻게 될까요? 어차피 생성할 때 비밀번호도 같이 만들어주니까 새로 생성된 비밀번호를 사용하면 되지 않을까요?

이번에는 컨테이너를 생성할 때, mysql의 비밀번호를 password1234로 설정을 해주었습니다.(이전 비밀번호 password123)

mysql에 접속할 수 없는 모습을 볼 수 있습니다.

 

그렇다면 why?

도커 볼륨(docker volume) 으로 설정해준 폴더에 이미 비밀번호 정보까지 같이 저장이 되어버렸기 때문입니다.

 

주의사항 2. 볼륨으로 지정할 폴더는 항상 비어있어야 함

도커 볼륨을 저장하려는 파일은 항상  비어있어야 한다.

도커 볼륨은 지정해준 파일 경로에 데이터가 들어있는 경우 항상 디렉토리에 저장된 데이터를 컨테이너 저장공간에 보내주기 때문에, 도커 볼륨을 제대로 사용하려면 지정해준 폴더는 항상 비어있거나, 새로 만들어주어야한다.


도커의 내용이 너무 길어질거같아서 분량 조절을 위해서 나눠서 내용을 정리하려고 한다.

 

요약 정리

  • docker를 사용하는 이유 : 항상 일관된 프로그램을 사용하여 개발 환경을 동일하게 세팅해준다.
  • 컨테이너 : 하나의 호스트 컴퓨터에서 각각의 독립된 개발 컴퓨터를 생성하는 것과 같다.
  • 이미지 : 프로그램을 실행하는 데 필요한 설치 과정, 설정, 버전 정보 등을 포함하고 있다.
  • 도커 볼륨 : 도커 컨테이너에서 생성된 데이터를 호스트 컴퓨터(내 로컬)에 저장하여 컨테이너가 삭제되어도 데이터가 삭제되는 것을 방지한다.