qq

Blackeichi·2023년 4월 11일
0

도커에서는 Dockerfile 이라 명명한 파일을 만들고 이러한 Dockerfile을 build하여 Docker image를 만들고, 이것을 run하여 컨테이너를 실행할 수 있습니다.
Dockerfile에서는 도커에게 최종적으로 컨테이너를 설정하는 방법을 설명합니다.

Docker Hub에는 다양한 공식 이미지가 있으며 우리들의 이미지도 올릴 수가 있습니다.
만약 docker run node 를 작동했을 때 로컬에 node라는 이미지가 존재하지 않으면 자동으로 Docker Hub에서 node 이미지를 가져옵니다.

그리고 여기의 Dockerfile을 사용하면 자체 커스텀 이미지를 사용할 수가 있는데, 일반적으로는 공식 베이스 이미지를 가져온 다음 그 위에 코드를 추가하여 그 이미지로 코드를 실행합니다.

#<Dockerfile>
        FROM node
  		// 이미지의 이름 (node라는 이미지가 없으면 공식 이미지)
        WORKDIR /app
  		// 생성된 컨테이너 안에서 명령어를 실행할 디렉터리를 나타냄
        COPY package.json /app
  		// package.json 파일이 컨테이너 내부의 app폴더에 복사가됨
        RUN npm install
  		// 이제 이미지에서 npm install 명령을 run하고 싶다고 알림
  			(위에서 명령어 디렉터리를 /app으로 설정했음)
        COPY . /app
  		// 현재 이 프로젝트 위치의 모든 폴더/파일을 컨테이너 내부의 app폴더에 복사가됨
        EXPOSE 80
  		// 도커 컨테이너에서 노출할 포트를 알려주는 것인데, 기능을 하지는 않고 문서화의 목적
        CMD ["node", "app.js"]
  		// 모든 작업이 완료되면 node app.js 을 실행하라고 알리는 것

이것은 node백엔드 앱의 Dockerfile 예시입니다.
이렇게 dockerfile을 작성하고 docker build . 명령어를 작성하여 새 커스텀 이미지를 빌드하도록 도커에게 지시를 할 수 있습니다.
그리고 이미지의 이름과 태그명을 지정할 수 있는데 docker build -t test:latest .처럼 -t 옵션 뒤에 이름 콤마 태그명으로 사용하면 됩니다.

그리고 docker image ls(docker images) 를 사용하여 이미지들의 리스트를 볼 수 있으며, 이미지들의 이름, 태그명, ID, 작성일, 크기 등을 확인할 수 있습니다.
또한 이름과 태그명을 사용해서 다음처럼 검색도 가능합니다.
-docker images java
-docker images java:8

docker image rm(docker rmi) 로 이미지를 삭제할 수 있으며 여러 개도 삭제할 수 있습니다.
-docker rmi one two three four

그리고 생성한 이미지를 활용하여 docker create 이미지 이름/ID 로 컨테이너를 생성할 수 있으며,
docker container ls(docker ps) 명령어를 사용하면 실행되고 있는 컨테이너를 조회할 수 있고 뒤에 -a 옵션을 붙이면 모든 컨테이너를 볼 수 있습니다. create한 컨테이너를 확인하기 위해서 -a옵션으로 모든 컨테이너를 출력하여 docker start 컨테이너 이름/ID로 컨테이너를 시작할 수 있습니다.

그리고 docker run 이미지 이름/ID 를 사용하면 create와 start의 역활을 합쳐서 컨테이너를 생성하고 실행시킬 수 있습니다.

docker container rm (docker rm) 은 이미지를 삭제한 것처럼 컨테이너를 삭제할 수 있습니다.
docker image prune 과 docker container prune 은 사용되지 않는 이미지, 중지된 컨테이너 제거해주는 역활을 해주며 옵션을 통해 전체 삭제도 가능합니다.

모든 도커 명령에는 뒤에 --help를 추가하여 사용 가능한 모든 옵션을 볼 수 있다.
docker run 에 다양한 옵션을 붙일 수가 있습니다.

-p 옵션을 사용하면 컨테이너의 포트를 열 수 있습니다. 예를 들어 현재 run으로 실행된 컨테이너애플리케이션에서 localhost으로 접속을 하여도 접속이 안되는데, 컨테이너에서 포트를 publish해주어야 우리의 로컬 머신에서 도커 포트에 액세스할 수 있습니다. -p플래그를 추가하여
docker run -p 3000:80 이미지 명령어를 시작하면 3000에 포트80을 게시한 것으로 이제 localhost:3000에 접속하면 제대로 작동하게 됩니다.
즉 로컬과 컨테이너간에 연결할 수 있게 해줌

그리고 attached, detached 모드가 있는데 docker run으로 실행하면 attached가 디폴트로 실행이 됩니다.
attached(-a) 는 컨테이너의 출력값을 콘솔에서 계속 확인할 수 있지만 명령을 더 이상 사용할 수 없지만 detached(-d) 모드를 사용하면 백그라운드에서 컨테이너를 실행하여 명령어 프롬프트를 계속 사용할 수 있습니다.

그리고 컨테이너를 중지할 때 자동으로 제거하기 위해서는 --rm 플래그를 붙이면 된다.

--name 옵션을 사용하면 컨테이너의 이름을 명명할 수 있다.

docker run -d -p 3000:80 --rm --name test-container test:latest

컨테이너간의 파일을 복사할 때는 docker cp 명령어를 사용할 수 있습니다.
현재 호스트에서 외부 컨테이너(test)에 파일을 옮길 때는 외부컨테이너:경로로 가능합니다.
예를 들어 현재 호스트의 app폴더를 test 컨테이너의 folder안에 옮기때는 다음처럼 사용합니다
docker cp /app test:/folder

반대로 외부 컨테이너에서 호스트로 가져올 때는 거꾸로 입력하면 됩니다.
docker cp test:/folder /app

docker image save(docker save) 은 docker 이미지를 tar파일로 저장할 수 있다.
파일명을 지정하는 옵션으로 -o를 붙입니다.
docker save -o test.tar test:latest

docker image load(docker load) 는 반대로 tar파일로 만들어진 이미지를 다시 docker image로 되돌리는 명령어입니다.
docker load -i test.tar

일반적으로 웹 애플리케이션을 구축할 때 DB, 백엔드, 프론트엔드 이렇게 세 가지의 주요 블록을 가집니다.
프론트엔드는 백엔드와 통신하고 백엔드는 데이터베이스와 통신을 합니다.
그리고 이 앱을 도커화하는데 프로젝트의 구조는 다음과 같습니다.

📂backend
	- 앱 관련 파일들
    - Dockerfile
📂frontend
	- 앱 관련 파일들
    - Dockerfile
package.json

port를 사용하지 않고 컨테이너들 간의 통신을 위해서 docker network를 사용할 수 있는데 docker network create test-net 로 네트워크를 생성하고 DB로 사용할 mongoDB 컨테이너를 생성/실행 시키기 위해 다음과 같은 명령어를 사용한다.
docker run --name mongodb --rm -d -network test-net mongo 이렇게 하여 mongo의 공식이미지로 실행하고 test-net이라는 네트워크 안에 넣습니다.
그리고 프론트엔드폴더안에 Dockerfile을 작성하고

#<Dockerfile>
        FROM node
        WORKDIR /app
        COPY package.json .
        RUN npm install
        COPY . .
        EXPOSE 3000
        CMD ["npm", "start"]

프론트엔드 디렉토리 터미널에서
docker build -t react .
docker run --name frontend --rm -p 3000:3000 -it react
로 이미지를 생성하고 컨테이너를 실행시켜 줍니다.
리액트에서는 -it명령어를 추가하여 인터렉티브 모드, 컨테이너를 시작하고 끝나는 것이 아니라, 명령을 입력하는 상호작용모드로 실행시켜주어야 한다. 이유는 리액트가 그렇게 설정이 되어있기 때문이다.

그리고 백엔드 폴더에서 다음처럼 Dockerfile을 작성하고

    #<Dockerfile>
        FROM node
        WORKDIR /app
        COPY package.json .
        RUN npm install
        COPY . .
        EXPOSE 80
        CMD ["node", "app.js"]

docker build -t node .
docker run --name backend --rm -d -p 80:80 --network test-net node

백엔드에서 --network로 DB와 같은 네트워크에 넣음으로써 컨테이너 mognodb와 서로 통신을 할 수 있습니다.
그래서 백엔드에서 mongo와 연결하는 코드에서 mongodb라는 컨테이너 이름으로 connect할 수 있다.

    mongoose.connect(
        "mongodb://mongodb:27017/test1231",
        { 어쩌구 }
    )

단 프론트엔드와 백엔드에서는 port를 지정해줘서 브라우저와 연결이 가능하도록 설정을 하여야 하는데, 그 이유는 프론트엔드와 백엔드가 통신을 해야하지만 프론트엔드를 실행하는 것은 컨테이너가 아닌 브라우저이기 때문에 브라우저를 통해서 통신을 해야하기 때문입니다.

이렇게 세 가지의 컨테이너를 서로 통신하게 하여 하나의 애플리케이션을 작동시킬 수 있다.

도커 컴포즈는 docker build와 docker run 명령을 대체할 수 있는 도구입니다. 다수의 컨테이너의 build, run 명령을 하나의 구성 파일로 사용할 수 있습니다.
모든 컨테이너에서 docker run, docker build 명령을 사용하는 것은 비효율족이며 여러 개의 컨테이너를 사용하는 애플리케이션에서 도커컴포즈는 효율적입니다.

frontend와 backend 폴더가 있는 프로젝트에서 docker-compose.yml 파일을 만든다.
yaml은 들여쓰기를 사용하여 종속성을 표현하는데, 항상 version을 정의하는 것으로 시작합니다.
version은 도커 컴포즈 공식 문서에서 확인할 수 있는데, 점점 업그레이드된 버전을 사용할 수 있으므로, 각 버전에서 지원하는 내용을 확인하고 설정을 하면 됩니다.
그리고 services를 추가해야하는데, 중첩된 값을 가지며 들여쓰기를 하는 것이 중요합니다. services의 자식으로 컨테이너를 넣는데, 방금 보여드렸던 앱을 예시로 들면 backend, frontend, mongodb 이렇게 세 개의 컨테이너를 넣을 수 있으며 앞에 적은 이름이 label로 컨테이너 이름을 명명해준 것 입니다.
mongodb 컨테이너에서 image를 지정해주어 공식 mongo 이미지를 사용할 수 있게 해준다. 그리고 컨테이너가 종료되었을 때 자동으로 종료해주게 하는 --rm 옵션과 detached 모드 옵션은 디폴트로 설정이 되어잇기 때문에 추가하지 않아도 됩니다. 그리고 network의 경우에는 같은 services 자식으로 넣으면 자동으로 같은 네트워크안에 넣어준다.
docker run --name mongodb --rm -d -network test-net mongo 가 이렇게 짧아졌다.

그리고 backend 컨테이너에서 build해야 하는 Dockerfile의 위치를 알려주어야 하는데, yaml(야믈)파일이 있는 위치를 기준으로 경로를 작성해준다.
port를 지정해주고, 도커 컴포즈에서는 depneds_on 옵션을 추가할 수 있는데, 이것은 하나의 컨테이너가 다른 컨테이너에 의존할 경우 사용할 수 있습니다.
현재 백엔드에서는 mognodb와 연결하는 코드가 있기 때문에 mongodb컨테이너가 실행된 이후에 백엔드 컨테이너가 실행되어야 함을 도커 컴포즈에게 알려주는 것 입니다.

프론트엔드에서 stdin_opne: true 로 서비스에 개방형 입력 연결이 필요하다는 것을 알리고 tty: true 로 터미널에 연결할 수 있도록 하여 인터렉티브 모드에서 시작하게 한다.

#<docker-compose.yaml>
    version: "3.8"
    services:
		mongodb:
        	image: "mongo"
        backend:
        	build: ./backend
            ports:
				- '80:80'
            depends_on:
                - mongodb
        frontend:
        	build: ./frontend
            ports:
            	- '3000:3000'
            stdin_opne: true
            tty: true
            depends_on:
                - backend

이렇게 작성한 후 docker-compose up 명령어를 사용하면 모든 이미지를 빌드하고 컨테이너를 실행시켜 준다. 그리고 docker-compose down을 실행하면 모든 서비스를 중지하고 모든 컨테이너를 제거해준다.

profile
프론트엔드 주니어 개발자 한정우입니다. 😁

0개의 댓글