나는 프로젝트를 하면서 aws에 프로젝트를 배포하는 역할을 많이 했었는데, 거의 다 docker를 사용했다.
앞으로도 애용할 예정이기에 더 자세히 알아보기로 했다
도커가 필요한 이유
컴퓨터마다 각각의 버전과 os가 다르다. -> 단순히 내 컴퓨터 내의 코드를 전송한다고 잘 작동한다는 보장이 전혀 없다.
우리가 배포를 하면 작성한 코드는 서버용 컴퓨터에서 돌아가게 된다.
서버용 컴퓨터와 개발용 컴퓨터는 버전 등의 요소가 다를수밖에 없다.
만약 도커가 없다면, 다음과 같이 두가지의 프로그램이 한 서버에서 돌아갈 때 두 프로그램이 쓰는 특정 툴의 버전이 다르다면 에러가 날 수 있다.
그럼 이런식으로 각각 만들면 되지 않나?라고 생각할 수 있지만 이렇게 하면 각 부분이 컴퓨터자원을 잘라서 가져가야하고, 또 겹치는 os기능을 각각 가지고 있어야하기때문에 자원 낭비도 발생한다.
이렇게 컨테이너로 관리한다면 컴퓨터 자원을 공유해서 사용하고, 버전이 다른 근무자들로 인한 혼란도 발생하지 않는다.
(근로자들이 전기, 수도를 나눠 쓴다고 비유할 수 있다.)
이러한 자원은 특정 코드들을 다른 환경에 옮기는 것에도 도움을 준다.(개발용 컴 -> 서버용 컴)
도커에서는 어떤 버전을 쓸것인지.. 등등을 설계도로 만들 수 있고, 이를 코드와 함께 서버로 보내면 서버는 그 설계도대로 컨테이너를 설치해서 개발했던 환경과 동일하게 서비스를 실행할 수 있도록 한다.
도커 사용해보기
로컬 컴퓨터에 node js가 깔려있지 않으면 자바스크립트를 실행하지 못한다.
하지만
docker run -it node 명령어를 실행하면
이렇게 잘 실행되는 것을 볼 수 있다.
위 환경은 갑자기 어디서 나타난걸까?
Docker hub 사이트에 들어가면 우리가 개발할 때 사용하는 환경을 이미지화 한 파일들이 있다.
도커 이미지는 리눅스 컴퓨터의 특정 상태를 그대로 얼려서 박제해둔 것을 말한다
컴퓨터는 일단 내 컴퓨터에서 이미지를 찾아본 뒤 해당 이미지가 없으면 Docker Hub에서 해당 이름으로 등록된 이미지를 다운받는다
run 명령어는 위 방법으로 이미지를 구한 후 이를 컨테이너로 만든다.
이미지 하나로 컨테이너 여러개를 만들 수 있다. 이미지는 컨테이너를 만들어내는 틀이라고 생각하면 된다.
위 명령어에서 -it는 CLI를 사용해서 컨테이너랑 소통하겠다는 의미이다.
그래서 자바 스크립트 콘솔을 통해서 컨테이너랑 상호작용 할 수 있는 것이다.
docker ps 명령어를 입력하면 현재 실행되고 있는 컨테이너들을 확인할 수 있다.
그럼 이번엔 docker exec -it 컨테이너명 bash를 입력했다.
이건 컨테이너 내부를 통해 가상의 리눅스 환경으로 들어간 것이다.
ls를 입력하면 리눅스 환경에서의 파일들이 보인다.
컨테이너마다 파일시스템과 네트워크가 있는 것이다.
그렇다고 모든 리눅스가 들어간 건 아니다. 이 리눅스 환경은 도커 테스크탑 프로그램으로 구현되고 있는 것이다.
위 쉘에서 ctrl+c를 입력하면 쉘이 종료되고, 다시 docker -ps하면 해당 컨테이너가 뜨지 않는 것을 볼 수 있다.
docker -ps는 현재 실행중인 컨테이너만 뜨기 때문이다.
이처럼 docker ps -a를 사용하면 현재 중지되어있는 컨테이너도 확인할 수 있다.
DockerFile
DockerFile은 나만의 이미지를 만들기 위한 설계도이다.
node 이미지를 받았지만, 컴퓨터에서 http-server란 프로그램을 돌리려면 node.js만 있으면 안되고, npm 등으로 http-server가 전역으로 깔려 있어야한다.
기존 이미지만을 사용하려면 컨테이너화 할 때마다 해당 프로그램을 설치해야한다.
하지만 해당 이미지를 튜닝하여 http-server도 깔리도록 한다면 더욱 수월해진다
이것이 도커파일이다.
우선 Node를 기반으로 한다는 From을 사용하였고,
Run npm install -g http-server 명령어로 해당 프로그램을 설치하도록 하였다.
WORKDIR로 이미지 내에서 명령어를 실행할 디렉토리를 지정한다.
RUN은 이미지에서 컨테이너를 실행하는 시점에서 실행되는 명령어이고,
CMD는 컨테이너가 실행될 때 기본적으로 바로 실행되는 명령어이다.
이 상태에서 원하는 컨테이너명을 입력하고 빌드하면
기본적인 node 이미지와 커스텀한 이미지가 만들어진 것을 볼 수 있다
이 이미지를 컨테이너로 만들기 위해 run명령어를 사용한다.
-v는 볼륨이라는 뜻인데, 볼륨이란 컨테이너와 특정 폴더를 공유하는 것을 말한다.
이렇게 로컬의 폴더에 모든 하나 또는 여러개의 컨테이너가 접근할 수 있다.
그림으로 설명하면 이렇다. 로컬에서 매번 코드를 수정할 때마다 run을 해야한다면 매우 번거로울 것이다.
그래서 위와 같이 볼륨을 통해서 동기화를 시키는 것이다.
-p는 포트 포워딩 옵션이다. 이건 -p 8080:8080은 호스트의 8080 포트를 컨테이너의 8080 포트에 연결한다는 뜻이다.
만약 이렇게 두개의 컨테이너가 있다면 포트가 충돌이 나면 안된다.
이 때에는 8081과 같이 다른 포트를 연결해주면 된다.
이런 명령어를 사용한다.
8080:8080으로 도커를 올렸으면 localhost:8080으로 브라우저에서 접속했을 때 이와같이 사이트가 잘 나오는 것을 볼 수 있다.
만약 8080:8081로 올렸다면, localhost:8081로 접속해야한다.
그러면 브라우저가 호스트의 8081 포트로 요청을 보내고, 도커가 그 요청을 받아서 컨테이너의 8080 포트로 전달한다.
docker compose
도커 컨테이너들이 각각 있는 상태에서(데이터베이스, 백엔드, 프론트엔드) 각각의 네트워크는 분리되어있어서 서로 통신하지 못한다.
이를 수행할 수 있도록 하기 위해서 거시적인 설계도인 docker-compose가 사용된다.
docker compose는 여러개의 컨테이너들을 한번에 정의하고 실행할 수 있도록 한다.
만약 docker compose가 없다면 이런 명령어를 하나하나 작성해야한다.
하지만 docker compose.yml파일이 있으면 한번에 컨테이너를 관리할 수 있다.
이와 같이 yml파일에는 services의 하위로 db ,백엔드 등 각각 내부 항목들로 들어간다.
build: ./~ 는 도커파일의 위치이다.
docker-compose.yml이 있는 위치에서 docker compose up를 입력하면 이미지가 빌드되고, 컨테이너가 생성된다.
docker compose up -d를 하면 백그라운드에서 실행된다.
이렇게 실행되면 세 컨테이너는 같은 네트워크를 사용한다.(같은 공유기 아래에 있다고 보면 된다.)
따라서 백엔드 컨테이너는 데이터베이스 컨테이너에 이름으로만 접근이 가능하다.
예를들어, 위에는 내 프로젝트의 application.yml파일인데
여기서 docker compose를 사용했기 때문에 위와 같이 컨테이너명과, 포트만으로 접근이 가능해진다.
Docker Daemon
이건 내가 궁금해서 알아봤다.
도커를 사용하다보니 내 컴퓨터 내에 설치된 도커 앱을 실행시키지 않은 상태에서 docker compose up 명령어를 치면 에러가 항상 발생했었다.
그 이유는 내 컴에 Docker Daemon이 떠있지 않기 때문이었다.
Docker Deamon은 도커 컨테이너를 실제로 실행하고 관리하는 백그라운드 프로그램이다.
Docker 이미지 빌드, 컨테이너 실행/종료, 포트 연결, 볼륨 마운트 등 모든 핵심 작업을 실제로 수행한다
리눅스 환경에서는 도커가 os 수준에서 직접 설치되고, 데몬도 자동으로 실행된다. 즉, demon이 백그라운드에서 항상 떠있으므로, 그냥 docker 명령어로 바로 실행이 가능하다.
근데 내 환경은 mac이다. 여기서는 도커데몬을 직접 띄울수가 없다.
따라서 docker desktop를 설치하면 내부적으로 linux vm을 띄우고, 그 위에서 도커데몬을 실행시킨다.
이미지와 컨테이너
이미지
애플리케이션을 실행하기 위한 모든 요소를 포함한 템플릿이다.
불변이고, 컨테이너를 만드는데 사용된다
docker pull python:3.10
예를 들어 위 코드는 python:3.10 이미지를 가져오는 명령어이다.
컨테이너
애플리케이션과 그 실행환경을 패키징한 가볍고 독립적인 실행 단위를 의미한다
호스트 OS 위에서 격리된 상태로 실행된다.
이미지를 기반으로 실행되며 실행중인 인스턴스를 컨테이너라고 한다.
docker run -it python:3.10
위 코드는 이미지를 실행해서 컨테이너를 생성하고 터미널로 들어가는 명령어이다.
이미지는 컨테이너를 만들어내는 틀이라고 생각하면 된다.
출처
https://www.youtube.com/watch?v=hWPv9LMlme8