Docker 간단 총 정리
이전에 Docker를 총 정리 했지만, 좀 더 쉬운 접근 방법으로 Container 기술을 저 나름대로 정의해보았기에, 공유해봅니다.
Docker 배우기 전 준비 단계
왜 Docker를 사용할까?
Docker를 왜 사용하는지에 대한 해답은 우리가 가상화를 왜 사용할까? 라는 물음에서 답을 얻을 수 있습니다
가상화
기본적으로 컨테이너는 가상화 기술의 발전형이라고 생각하면 됩니다.
- 가상화 시스템이 무엇이고, 가상화가 왜 필요한지를 알게 되면, Docker도 왜 탄생했는지를 알 수 있습니다.
가상화는 전통적으로 하드웨어에 종속된 리소스를 사용해 유용한 IT 서비스를 만들 수 있는 기술입니다.
- RedHat에서 정의하는 가상화입니다.
- 하지만, 용어가 어렵기에 쉽게 풀이를 해보겠습니다.
- 가상화란 결국 물리적 머신(PC)을 논리적으로 나누어서 마치 물리적으로 나눈 것처럼 여러대의 컴퓨터를 사용하는 것을 말합니다.
- 아래의 예를 들어보겠습니다.
- 위에는 각각 용도가 다른 물리적인 서버가 있습니다.
- 하나는 메일 서버, 다른 하나는 웹서버, 나머지 하나는 내부 레거시 애플리케이션을 실행하는 서버입니다.
- 우리가 흔히 생각하는 상식은(물리적 분리) 위의 사진과 같습니다.
- 1개의 서버와 1개의 운영체제, 1개의 태스크와 같이 개별 서버에서 개별 테스크를 실행하는 것이 더 쉽고 안정적인 경우가 많습니다.
- 그러나 가상화를 사용하면, 메일 서버를 2개의 고유한 서버로 분할해, 독립적인 태스크를 처리하고 레거시 애플리케이션을 마이그레이션 할 수 있습니다.
- 마찬가지로 하드웨어를 더 효율적으로 사용 가능합니다.
즉, 가상화는 컴퓨터의 자원을 효율적으로 사용하는 방향으로 초점이 맞춰져 있는 기술입니다.
- 이는 Docker도 마찬가지 입니다
왜 Docker를 사용해야할까?
가상화가 효율을 중시한다면, 왜 컨테이너라는 기술이 나왔을까?
- 아마 많은 사람들의 궁금증일 것입니다.
- 당연하게도 시간이 흐르면서, 더 나은 기술이 나오길 마련입니다.
- 이유인 즉슨, 가상화에서 한계가 왔기 때문입니다.
가상화의 문제점
탄력적 자원 사용 불가
물리적인 서버를 논리적으로 분리를 했어도, 여전히 모든 자원을 효율적으로 사용할 수 없었다
- 가상화 머신의 특징 중 하나는, 트래픽 혹은 서버의 증설이 필요할 때는, 임의적으로 서버의 자원을 늘릴 수 있다.
- 하지만, 서버 축소는 불가능하다
즉, 가상화는 서버의 자원을 탄력적으로 사용할 수 없다.
Hypervisor의 한계
Hypervisor 란?
- 가상 머신을 생성하고, 구동하는 소프트웨어 입니다.
- 해당 컴퓨팅 자원들을 애뮬레이팅 하여 Guest OS에 할당 해준다.
- Hypervisor는 CPU, 메모리, 스토리지 등의 리소스를 처리하는 풀로, 기존 게스트 간 도는 새로운 가상 머신에 쉽게 재배치가 가능하다.
- Hypervisor란 서버 컴퓨터의 자원을 나누는 역할을 합니다.
문제점
- 하드웨어를 애뮬레이션을 거쳐서 들어가기 때문에, 성능의 효율성이 떨어진다.
- Hypervisor를 띄우기 위한 컴퓨팅 자원이 또 들어가기에, 자원의 오버헤드가 커진다.
- 컨테이너는 위에서 나오는 가상화의 문제점들을 해결하기 위해서 나오게 됐습니다.
Container Deployment
- 성능, 자원, 격리 문제 등등 해결하기 위해서 나온 기술이 Container라는 기술입니다.
- 추가적으로 격리 기술이 들어갑니다.
- chroot를 이용한 파일 격리
namespace를 이용한 Network, Process Id를 격리- 자원 효율도 CPU를 에뮬레이팅하는 것이 아니라, 본연의 성능을 낼 수 있다.
Docker를 사용하기 전에 알아야할 지식
사전 지식
- 기본적으로 docker는 인프라를 효율적으로 사용하기 위해서 나온 개념이다.
- 즉, 인프라의 주요 개념을 알지 못한다면, Docker를 이해하는데 굉장히 어려울 것이다.
- 아래는 간단하게 docker에 들어가기 전에, 간단하게 인프라 지식을 찍먹하는 시간을 가진 후에 Docker로 들어가겠다.
Network
- 인프라를 구성하는데 중요한 역할을 하는
Network
파트 입니다.
IP
보통은 ip address 즉, ip 주소 라고 표현을 많이 한다.
위키 백과에서 보게 된다면, 컴퓨터 네트워크에서 장치들이 서로를 인식하고 통신을 하기 위해서 사용하는 특수한 번호라고 합니다.
말 그대로 주소 입니다.
보통 예시를 들 때는 택배의 예시를 듭니다.
만약 저희가 택배를 시킨다고 가정을 합니다.
만약 택배를 시킬때 제가 사는 지역이 서울 이라고 한다면, 주소란에 서울만 작성하면 택배가 올바르게 올까요?
당연히 아닐겁니다.
그러면 어떻게 해야할까요?
뭐 다들 아시다 싶이 도로명 주소까지 자세히 동, 호수까지 적어주고 해야지 택배가 오겠죠?
IP도 그러한 경우 입니다.
왜 이런 복잡한 수가 탄생이 됐을까 생각을 해보면 주소를 생각하면 됩니다.
정확한 주소를 알기위해서는 최대한 자세하게 쓰는 것이 원칙입니다.
그렇기에 숫자가 많은 것이고, 인간은 문자를 쓰지만, 컴퓨터는 그냥 이진수를 이용해서 쓰는거에 불과합니다.
동적 IP, 고정 IP
고정 IP
말 그대로 IP주소가 고정 되어있다는 얘기 입니다.
음,,얘를 들어보자면, 다들 잘 아시는 롯데타워로 예를 들다면, 롯데타워가 부서지지 않는 이상, 도로명 주소에 롯데 타워를 검색하면
주소가 똑같이 나옵니다.
즉, 정말 특별한 일이 아닌 이상 건물은 그 자리에서 이동하지 않습니다.
이동하지 않는 대신 자리세를 내야하죠, 그 대가로 땅 값을 지불하고 건물을 짓는거죠
고정 IP도 이와 같은 개념입니다.
한 고정된 주소를 자리세를 내고 사용을 하는 거죠.
동적 IP
동적 IP는 그러면 무엇이될까요?
비유를 들면 우리 같은 사람들 입니다
사람들 중에서는 한 자리에 오래 머무르는 사람이 있을 수 있고, 어떤 사람들은 매년마다 이사를 나아가는 사람들이 있습니다.
즉, 내부적 요인, 외부적 요인에 의해서 사람들이 사는 주소는 지속적으로 변경이 되거나 변경 될 가능성이 있죠.
그래서 저희는 집을 구할 때 매매, 전세, 월세 라는 걸로 집을 구합니다.
매매(동적IP)처럼 처음에 거금을 구하고 사는 것도 있지만, 보통은 이사할 것을 생각하여 전세, 월세(동적 IP)를 생각합니다.
일정기간 동안 계약을 하고 계약이 끝나면 계속 살지, 아니면, 이사를 갈지를 결정하죠.
이처럼 동적 IP도 마찬가지로, 매매보다 저렴하기 때문에, 일반 서민들에게 랜선을 할당할 때 이러한 동작 IP를 제공하게 됩니다.
IMAGE
- Docker를 다루게 된다면 가장 많이 듣게 되는 말 중에 한 개 입니다.
- 보통 컴퓨터에서 이미지란, ISO 이미지를 의미합니다.
- 국제 표준화기구(ISO)가 제정한 광학 디스크의 압축 파일을 의미합니다.
- 이와 같은 이미지와 같이 나오는 개념인 스냅샷이 있습니다
스냅샷
스냅샷?
- 스냅샷이란 쉬운 의미로는 Disk 백업 기능을 말합니다.
- 서버에 있는 Disk들을 백업하는 것으로 전체 혹은 원하는 Disk만 백업이 가능합니다.
스냅샷과 이미지의 차이
- 쉽게 말해서 SnapShot은 disk 백업이고, Image는 Full 백업이다.
- 즉, Image는 OS 데이터까지 모두 복사하므로, 이미지만, 있으면 서버의 소프트웨어를 재 설치 할 수 있다.
Docker
Docker CLI
- Docker CLI는 말 그대로 Docker의 Command Line Interface 버전입니다.
- Docker CLI로 왠만한 컨테이너를 제어할 수 있습니다.
- 한, 두개 정도의 Container를 다루거나, log를 보거나 할 때 알아야하는 docker 명령어들입니다.
- 이를 선언적 형태라고 합니다, 기록이 남지 않아서, 해당 명령어로 직접 container를 구성해서 시키는 경우는 많이 없습니다.
- 이유인 즉, 위와 같이 가독성이 떨어지기 때문입니다.
docker run --name nexus -d -p 5050:5050 -p 8081:8081 -v /nexus-data:/nexus-data -u root sonatype/nexus3
Docker install
우선 docker를 설치하기 전에 자신의 컴퓨터가 무슨 운영체제, x86, arm 인지 알아야합니다. 각자마다의 환경에 맞게 Docker를 설치하면 됩니다.
Docker Desktop - Docker
Docker Desktop의 유료화
- Docker Desktop이 상업적인 환경에서는 유료화 됐습니다.
- 그렇기 때문에 linux 설치와 유사하게 설치해주셔야 합니다.
- 만약 docker desktop으로 설치 하셨다면, docker-compose, docker-swarm은 자동 설치 되므로, 따로 설치할 필요가 없습니다.
Docker 설치가 완료 되시면, 이제 Docker가 제대로 설치가 되어있는지 확인을 해봐야겠죠.
Mac은 terimal을 Window는 powershell을 키셔서 아래 코드를 입력했을 때, 오류가 나지 않으면 성공적으로 설치가 된 것 입니다.
docker --version
후에 우선 실습을 위해서 실습하기 좋은 was인 apache를 설치하려고 합니다. 위의 개념에서 나왔듯이 코드로는
docker pull httpd
를 사용하여, apache를 다운받으면 됩니다.
(git pull과 기능이 비슷하다고 생각하시면 됩니다.)
후에 해당 image를 이용해서 docker를 실행하고 싶다면, run을 작성하면된다.
docker 실행
docker run --name ws2 httpd
docker run —name [컨테이너명] [사용image]
를 입력하면 설정한 컨테이너명으로 해당 이미지를 이용해서 실행한다.
당연하게도 컨테이너이기에 여러 개의 터미널을 켜서 run이 가능하다.
docker 모니터링
만약 docker conatiner가 돌아갈 가는 것을 보고 싶다면,
docker ps
docker ps -a
해당 코드를 작성하면 된다.docker ps
는 현재 실행 중인 container만 보여 주고,
docker ps -a
는 실행 중, 정지 한 모든 container를 보여준다.
docker log
docker logs ws2
docker logs -f ws2
docker logs -f ws2 --tail 500
ws2의 로그가 보고 싶으면 이런 식으로 실행 하면 된다.
만약 실시간으로 보고싶다면, -f
옵션을 붙이면 된다.
컨테이너 삭제
docker rm ws2
docker rm --force
ws2를 삭제하고 싶다면, rm을 넣으면 된다.
모든 컨테이너를 한꺼번에 삭제하고 싶으면 —force라고 하면 된다.
docker rmi httpd
docker에 설치했던 이미지를 삭제하는 명령어 이다.
docker의 Port forwarding
- port forwading을 이용해서 웹서버를 실행해보겠습니다.
docker run --name ws3 -p 8080:80 httpd
터미널에 이렇게 입력을 하게 된다면, localhost:8080 으로 접속을 하게 된다면,
It’s Work!
라고 뜨면 성공이다.
docker shell
- docker도 결국 linux기반으로 돌아가기 때문에, linux에서 사용하는 명령어가 ==어느 정도==는 적용이 된다.
- 어느 순간은 docker내부를 들여다 봐야할 순간이 생길지 모르기 때문에, 익혀두면 도움이 될 수 있다.
- 우선, docker에 linux 명령어를 사용하려면,
docker exec ws3 ls
docker exec ws3 pwd
docker exec ws3 ls -al
docker exec [컨테이너명] [명령어]
하지만, 일일이 docker exec 컨테이명 명령어, 이런식으로 작성하는건 너무 힘들기 때문에 docker container shell
을 작동시키는 방법이 있다.
docker shell/bash shell
docker exec -it ws3 /bin/sh
docker exec -it ws3 /bin/bash
- 위의 코드는 docker 자체 shell 프로그램을 지속적으로(
-it
) 실행하게 하는 코드이다. - 즉, exec ws3 다음명령어 일때 다음 명령어만 치면 그대로 출력된다.
- 아래에 사이트에 자세한 명령어 모음이 있다.
Docker run reference
DockerFile
- 많이들 오해 할 수 있는 부분이 Docker CLI == Dockerfile 이라고 오해를 한다. -> 이건 오해다
- Dockerfile의 같은 경우에는 해당 Container의 이미지를 만드는데 필요한 구성요소(설치해야할 패키지 목록, Container에 필요한 CMD 등)을 넣어놓는 것이다.
- 즉, container를 좀 더 구체적으로 쓰기 위해, 해당 Dockerfile을 만들고 나면, Docker를 실행하기 위해서는 결국 Docker CLI를 이용해서 Docker를 실행합니다.
- 그렇기 때문에 Docker CLI와 Dockerfile은 범주가 다른 것이라고 이해하셔야 합니다.
# 어떤 종류의 이미지를 바탕으로 만들 것인지
FROM node:16-alpine
# 어떤 디렉토리를 메인 work 디렉토리로 사용할 것인지, 없으면 생성함
WORKDIR app
# 왼쪽은 호스트, 오른쪽은 docker를 의미하며, 호스트와 도커를 동기화시키고 없으면 복사한다는 것이다.
COPY package*.json ./
# run 명령을 통해 cli를 실행합니다.
RUN npm install
# 현 호스트의 디렉토리와 도커의 디렉토리를 동기화 시킵니다. 없으면 복사합니다.
COPY . .
# 3000 번 포트로 개방한다고 표현합니다(별다른 기능은 없습니다, 단지 명시적으로 해당 docker가 어느 포트로 개방할 건지 표기하는 겁니다.)
EXPOSE 3000
# command를 입력합니다. 보통 마지막에는 CMD, ENTRYPOINT를 사용합니다.
CMD [ "npm", "start" ]
- dockerfile은 사용하는 실질적으로 문법이 어렵지 않고, 사용하는 명령어들이 많지 않기 때문에
- 예시를 들어서 설명하겠습니다.
Docker-Compose
docker-compose까지 와야지 비로소 Docker CLI를 대체할 수 있습니다.
- Docker CLI를 자세히 보시게 된다면, 옵션이 다양합니다.
-p -> Port, -v -> Volume, -u -> user
- 등등 실 서버를 구성하기 위해서는 구성해야하는 요소들이 꽤 많이 있습니다. (Volume은 휘발성을 없애기 위한 요소로 추후에 자세히 설명해드리겠습니다.)
- 물론 CLI에
docker-compose up -d
라는 명령어를 써야하긴 하지만, 위의 CLI처럼 복잡한 명령어는 아니기에 Docker CLI를 대체할 수 있다고 할 수 있습니다. - Container에 대해서 외부적인 것들과 network에 대한 모든 설정은 이
docker-compose.yaml
에서 제어합니다. - 아래는 저희 동아리에서 사용하는 Node 서버와 MariaDB 서버에 대한 docker-compose 파일의 예시입니다.
version: '1.0.0'
services:
node-server:
# container 이름 생성
container_name: back_node
# container가 강제 종료될 때, 취할 재스쳐
restart:
always
# 이미지 이름 생성
image:
back
# image build 할 위치
build: ./backend
environment:
TZ: Asia/Seoul
# 포트 설정
ports:
- "3000:3000"
# 네트워크 설정
networks:
- import_network
# mariadb가 뜨기 전에 node가 뜨게 된다면, 죽기 때문에 mariadb가 뜨면 node가 뜨게끔 설정
depends_on:
- mariadb
mariadb:
# container 이름 생성
container_name: mariadb
# 이미지 이름(만약 이미지 빌드할 것이 없다면, 자동으로 다운로드)
image: mariadb:latest
# container가 강제 종료될 때, 취할 재스쳐
restart: always
# 환경에 따라 변경
ports:
- "3306"
volumes:
- ./db/mysql.sql:/docker-entrypoint-initdb.d/mysql.sql
# DB 데이터 저장 디렉터리
- ./data:/var/lib/mysql
# 설정 파일 저장될 위치
- ./config:/etc/mysql/conf.d
environment:
MYSQL_DATABAS: import
# 정의하지 않으면 실행 시, 에러가 발생합니다.
MYSQL_ROOT_PASSWORD: import1015
# 컨테이너 내의 시스템 타임존을 우리나라에 맞게 설정합니다.
TZ: Asia/Seoul
command:
# 위 명령어를 사용하지 않으면, 일부 설정이 latin으로 설정됩니다.
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
networks:
- import_network
# 네트워크 생성
networks:
import_network:
driver: bridge