Image란?
도커에서 이미지는 간단하게 밀키트 라고 볼수있다.
이미지는 우리가 만든 프로그램을 돌리기위한 os , 라이브러리 , 환경셋팅 , 소스코드 등등을 전부 합친 하나의 덩어리다.
- 도커가 없을 경우의 배포과정
웹서버 소스코드 ⇒ AWS등에서 빌린컴퓨터에 코드 옮기기 ⇒ 코드실행 환경셋팅 + 라이브러리 설치 + 코드실행
- 도커로 할 경우
이미지 생성 ⇒AWS등에 빌린 컴퓨터에 이미지 보내기 ⇒ 실행
Containers란?
결국 이미지는 컨테이너를 만들어주기 위한
밀키트같은 존재라는거다.
그렇다면 여기서 컨테이너는 뭐라고 할 수 있을까?
컨테이너는 간단하게 이미지라는 밀키트를 사용하여 만든 요리 라고 볼수있다.
정확히말하면 이미치 하나를 실행중인 가상 컴퓨터라고 할수있다.
Docker 를 사용하여 이미지 실행하는 방법
- 터미널 open
- docker run 이미지이름 : 태그
위 이미지를 실행하고 싶을 경우
docker run hello-world:latest
Image를 쓰는 이유
내 프로그램을 이미지로 만들어두면
아무 컴퓨터에서나 해당 이미지를 내려받아 매우 쉽게 실행할 수 있다.
- 이미지를 만드는 과정
- 해당 코드 파일에 Dockerfile 이란 이름의 파일을 생성
- 이미지에 넣을 내용 작성
- 터미널에 docker build 명령어 입력시 이미지 생성
Dockerfile에 넣을 수 있는 것들
- 어떤 OS인가
- 어떤 프로그램을 설치할것인가
- 어떤 터미널 명령어를 실행할 것인가
- 내 컴퓨터에 있던 파일을 어디에 집어넣을 것인가
등등 전부 작성이 가능하다.
간단하게 도커파일은 내 프로그램을 돌리기위해서 해야할 행위를 차례대로 작성하는 파일이다.
Dockerfile 예시
#어떤 OS인가? 이미지:태그
FROM node:20
#폴더이동 , 폴더가없다면 생성해서 이동
WORKDIR /src
#어떤 프로그램을 설치할것인가?
#RUN을 사용하면 개별적으로 다 다운해줘야하며 늘 최신라이브러리를 설치함
#COPY를 사용하여 package.json을 카피하여 install해주는게 관습
#RUN의 경우
RUN yarn add express
RUN yarn add jsonwebtoken
RUN yarn add bcrypt
#COPY의 경우 => 원래경로 이미지경로 "."=현재경로에있는 모든파일을 모두복사
#node modules등과같은 파일은 용량이 크기때문에 전부 복사하기 비효율적이므로 .dockerignore로 관리
COPY . .
RUN ["yarn","install"]
#이 컴퓨터에 어떤 포트로 열어서 쓸지 명시하는 명령어, 기능적으로 아무 연관없음 메모용임
EXPOSE 3333
#서버를 실행하는 명령어 , 혹은 도커의 마지막 명령어를 입력할때는 RUN이아닌 CMD사용 ENTRYPOINT도 있음
CMD ["node","src/server.js"]
Dockerfile 디테일
도커의 경우 파일을 빌드할때 도커내부에 캐싱하여 기존 데이터를 저장한다.
이는 빌드할때마다 매번 새로운 파일을 받지 않기 위해 기존 파일과 별 차이가없다면 기존 캐싱데이터에서 일정부분을 옮겨오기 위함인데 이를 이용해 빌드시간을 단축할 수 있다.
빌드시간을 단축하기위해 자주변하는 부분을 코드의 아래쪽에 위치하도록 작성한다면 조금이라도 더 빠르게 빌드할 수 있다.
#1.package.json 파일 먼저 옮기기
#2.npm,yarn 등 install실행
#3.소스코드 옮기고 실행
FROM node:20
WORKDIR /src
#1.npm의 경우 package가 붙은 모든파일을 가져온다.
COPY package*.json .
#2.yarn의 경우
#이렇게 하면 package.json과 yarn.lock 파일이 모두 컨테이너의 /src 디렉토리로 복사된다.
#그런 다음 yarn install 명령어를 실행하여 의존성을 설치할 수 있습니다.
COPY package.json yarn.lock ./
#여기서 json파일등을 보면 ^같은 특수기호를 볼수있는데 ^4.22.1 이런경우 앞에 버전이 4버전이기만하다면
#아무 버전이나 상관없다는 뜻 즉 4.33.1버전이 출시된다면 그 버전을 다운받는 경우가 생김
#이를 방지하기위해 npm install이 아닌 npm ci 명령어를 사용할 수 있다.
RUN ["npm","ci"]
#ENV 키워드를 사용해 환경변수를 정의할수있다.
#구버전 프로그램의 경우 NODE_ENV=production 를 작성해줘야 성능이 향상되는 경우가있어 관습으로 작성함
ENV NODE_ENV=production
#복사할 파일
COPY . .
EXPOSE 3333
#서버를 실행할경우 권한을 좀 낮춰실행하는게 안전하다함
#node이미지의 경우 이미 유저가 생성되어있으므로 해당유저 사용
USER node
CMD ["node","src/server.js"]
Docker 명령어
- docker build -t 이미지이름:태그명 경로 ⇒Dockerfile로 이미지 생성하는명령어
#빌드를 여러번할 경우 태그명으로 구분 가능
docker build -t nodeserver:1 .
- docker run 이미지명:태그명
#이미지를 실행하는 명령어 => docker run 이미지명:태그명
#여기서 latest = 최신버전
#하지만 이런식으로 실행시 터미널을 점유당함 => 다른명령어 입력불가 ,해결방안: 백그라운드실행
docker run nodeserver:1
#백그라운드에서 실행하는 명령어 -d = detached의 약자 ,-p 포트설정
docker run -d -p 3333:3333 nodeserver:1
- docker ps
#실행중인 컨테이너 조회
docker ps
- docker logs 컨테이너명
#실행중인 컨테이너 로그출력 => 로그를 볼 컨테이너 이름도 함께 작성
docker logs silly_newton
- docker exec -it 컨테이너명 sh
#실행중인 컨테이너에 접속하기 =>접속할 컨테이너 이름도 함께 작성
docker exec -it silly_newton sh
#접속한 컨테이너에서 터미널 명령어 사용가능
#예 : ls , cd .. 등등
#작업 마무리하고 나올경우
ctrl+p , ctrl+q
- docker stop 컨테이너명
#컨테이너 일시정지
docker stop silly_newton
- docker rm 컨테이너명
#정지된 컨테이너 삭제시키고 싶은 경우
docker rm silly_newton
#실행중인 컨테이너 바로 삭제시키고 싶은 경우
docker rm -f silly_newton
- docker run -e 환경변수이름=”값”
#환경변수 설정
docker run -e NODE_ENV=production
- docker network create 네트워크이름
#네트워크 생성
docker network create mynetwork
네트워크를 생성하는 이유
네트워크 안에 컨테이너를 넣어줘야 서로 통신이 가능하기 때문이다.
포트번호를 붙여줘야하는 이유
- 포트연결 안할시
- 포트연결 설정시
Docker Hub 사용법
- docker hub 레포지토리 생성 순서
- 생성한 레포지토리에 이미지 업로드
- 이미지 이름은 레포지토리명과 동일하게 변경 ⇒ 레포지토리와 이미지의 이름이 동일해야 업로드 가능함
- 터미널⇒ docker push 레포지토리:태그 3. 레포지토리에 있는 이미지 가져오기
Reverse proxy
reverse proxy는 서버로 들어오는 요청을 중간에 가로채주는 프로그램이다.
- 기본구조
- Reverse proxy의 경우
왜 이런 비효율적인 프로그램을 사용하는가?
- 서버의 정보를 숨길 수 있다.
- https 인증서를 설치하기 쉽다.
- 로드밸런싱을 할 수 있다.
- 누가 어디로 접속했는지 로그남기기
- IP차단 등
Nginx 기본사용법
- nginx설치
- nginx폴더 생성
- conf확장자 파일 생성
- default.conf파일 지우기
- nginx실행명령어 입력
#nginx 기본코드
server {
listen 80; =>들어온 경로
location / {
proxy_pass http://(컨테이너 이름 혹은 주소):8080; =>이 경로로 보내기
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
데이터베이스 컨테이너로 띄우기 +volume 사용법
3가지 배포 방식
- docker 파일을 만들어 docker hub에 올린후 EC2로 배포하기
- docker 파일을 ECR에 올리고 EC2로 배포하기
- docker 파일을 ECR에 올리고 ECS로 배포하기
더 많은 방법이 있겠지만 위의 3가지 방법을 간단하게 알아보자
3가지 방식의 차이점
도커파일을 만들어 도커 허브에 올린후 EC2에 배포하는 방식의 경우
도커허브에 내 도커 이미지를 올리게 되는데 문제는 도커허브는 퍼블릭이라는 점이다.
도커 허브에 내 이미지를 올릴경우 누구나 다운받아 사용할 수 있게 된다.
개인 프로젝트의 경우 별 문제 없으나 이후 기밀을 유지해야하는 기업등에서 사용할 경우를 대비하여
다른 방식을 사용하는 것이 좋다.
물론 도커허브도 프라이빗으로 설정할 수 있으나 무료 플랜에서는 계정당 1개만 사용할 수 있으므로 큰 의미는 없어보임
여기서 도커 이미지를 프라이빗 하게 올릴수 있게 해주는게 ECR이라고 한다.
또한 ECS는 여러개의 컨테이너를 담기 용이하다 하여 그런 니즈가 있는 기업에서 많이 사용된다함
하여 이번 프로잭트의 경우 ECR에 이미지를 올린후 ECS로 배포할 예정이다.
Docker Compose 파일 작성
- Docker Compose란? 여러개의 Docker 컨테이너를 하나의 서비스처럼 정의하고 관리 할 수 있도록 도와주는 도구이다. 복잡한 애플리케이션은 종종 여러 서비스 (예: 웹 서버 , 데이터베이스 , 캐시 서버 등) 로 구성되어 있는데 이때 Docker Compose를 사용하여 여러 컨테이너를 하나의 파일로 정의하고 한번의 명령으로 이들을 동시에 실행할 수 있다.
- Docker-compose.yml 파일 구조 YAML 형식으로 작성되며 기본적으로 version , services , volumes , networks 등의 주요 항목으로 구성된다. 각 항목의 구성을 알아보자면
- version version 키는 Docker Compose 파일의 버전을 지정한다. 현재 가장 많이 사용되는 버전은 3.x 이며 버전3은 Docker Swarm과 호환성을 제공하며 다양한 기능을 지원한다. 하지만 최근 Docker Compose에서는 version을 사용하는것을 권장하지 않는다.
- services services는 애플리케이션의 각 컨테이너를 정의하는 가장 중요한 섹션이다. 서비스 내부에 컨테이너를 정의함으로써 우리의 서비스를 만들어가는 것이기 때문이다. 여기에 각 컨테이너의 이미지 , 명령 , 환경변수 , 네트워크 설정 등을 포함할 수 있다.
위 예시에서는 3개의 서비스 game-server , mysql , redis가 정의되어있다.# 예시 version: '3.8' services: game-server: image: node:latest working_dir: /usr/src/app volumes: - ./:/usr/src/app # 전체 디렉토리를 컨테이너에 마운트 ports: - "3333:3333" networks: - my-network command: ["yarn","start"] mysql: image: mysql:latest environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: example_db MYSQL_USER: example MYSQL_PASSWORD: example ports: - "55555:3306" volumes: - mysql-data:/var/lib/mysql networks: - my-network redis: image: redis:latest ports: - "11109:6379" networks: - my-network networks: my-network: volumes: mysql-data:
- game-server 서비스 이 서비스는 node.js 애플리케이션을 실행한다.
3. redis서비스 이 서비스는 Redis데이터베이스를 실행한다.ports: - “11109 : 6397”은 호스트의 11109포트를 컨테이너의 6397 포트와 연결하여 외부에서 Redis에 접근할 수 있도록 한다. 4. 네트워크 및 볼륨 1. networks networks는 Docker네트워크를 정의한다. 각 서비스는 이 네트워크를 통해 서로 통신할 수 있으며 기본적으로 모든 서비스는 동일한 네트워크에 연결되지만 필요에 따라 여러 네트워크를 정의하고 각 서비스에 연결할 수 있다Docker Compose 명령어
Docker Compose 파일을 작성한 후에는 다음과 같은 명령어를 사용하여 관리할 수 있다.- docker-compose up : 정의된 모든 서비스를 시작한다.
- docker-compose up --build : 정의된 모든 서비스를 빌드하고 시작한다.
- docker-compose down : 실행 중인 모든 서비스를 중지하고 네트워크를 제거한다.
- docker-compose ps : 현재 실행 중인 서비스를 확인한다.
- docker-compose logs : 모든 서비스의 로그를 출력한다.
- my-network는 모든 서비스가 동일한 네트워크 내에서 서로 통신할 수 있도록 설정한다. 위 예시에서 my-network라는 네트워크가 정의되어 있고 game-server와 db서비스는 이 네트워크를 통해 서로 통신이 가능하다. 2. volumes volumes는 데이터를 영구적으로 저장할 수 있는 Docker 볼륨을 정의한다. 이를통해 컨테이너가 삭제되더라도 데이터는 유지된다. 위 예시에서는 mysql-data 라는 이름의 볼륨이 정의되어 있다. 이 볼륨은 db서비스에서 사용되며 MySQL데이터베이스 데이터를 영구적으로 저장한다. mysql-data는 MySQL데이터의 지속성을 위해 사용되는 볼륨을 정의한다.
- image: redis : latest 설정을 통해 최신 Redis 이미지를 사용한다.
- ports: - “55555 : 3306”은 호스트의 55555 포트를 컨테이너의 3306 포트와 연결하여 외부에서 MySQL에 접근할 수 있도록 한다.
- image: mysql : latest 설정을 통해 최신 MySQL 이미지를 사용한다.
- ports: - “3333:3333”은 호스트의 3333포트를 컨테이너의 3333포트와 연결하여 외부에서 접근할 수 있도록 한다.
- working_dir: /usr/src/app는 컨테이너 내에서 작업할 디렉토리를 설정한다.
- 각 서비스는 Docker 컨테이너로 실행되며 특정 역할을 수행한다.
왜 compose를 사용하는가?
Docker Compose와 docker-compose.yml파일을 사용하여 복잡한 애플리케이션을 쉽게 정의하고 관리할 수 있다고 한다. docker run 명령어 등을 통해 컨테이너를 관리하고자 하면 각각의 컨테이너에 대해 직접 관리하여 관리의 복잡성이 증가한다. 하지만 docker Compose를 통해 여러 컨테이너로 구성된 애플리케이션을 하나의 파일로 정리하면 명령어 몇 줄만으로 쉽게 개발환경이나 운영 환경을 구축할 수 있다. 이를통해 개발 및 배포 과정에서의 복잡성을 줄이고 일관된 환경을 유지할 수 있다.
'Docker' 카테고리의 다른 글
[AWS]Docker 배포 연결 트러블슈팅 (0) | 2024.12.19 |
---|---|
docker redis password 설정 (0) | 2024.11.17 |