📌 공부 계기

추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 

 

목차

 

📍10-1. 빌드에서 운영까지 : 이론

1️⃣ 도커 컴포즈가 뭐에요?

여러 컨테이너를 일괄적으로 정의하고 실행할 수 있는 툴.

하나의 서비스를 운영하기 위해 여러개의 애플리케이션을 동작해야 할 때가 있다. 이때 애플리케이션을 컨테이너화 시켜 통합 관리할 수 있다.

 

지금까지 여러 명령어를 하나하나 실행해주었는데

YAML(야믈)파일 하나로 도커 컴포즈에 요청하면 이 yaml 파일을 명령어로 해석해 컨테이너를 관리한다. 

 

또한 이 compose로 연결되어 있는 컨테이너들을  

docker-compose 툴로 한꺼번에 상태를 보고, 관리하고, 운영할 수 있다. 

 

 

The Compose file

 

docs.docker.com

🚩 도커 컴파일 구성

더보기

여기 포스팅에도 정리해 놓긴 했었는데 

 

원티드 챌린지 Docker 2] 로컬환경에서 도커를 활용해보자!

📌 공부 계기 원티드 챌린지가 이번 달 제공하는 강의는 Docker! Docker 강의 총 4번 중 2번째 정리해보려고 합니다. Docker 활용 목차 📍이론편 : Docker Compose 1️⃣ Docker Compose 란? 도커 파일은 하나의

littlezero48.tistory.com

* version 

도커 컴포즈의 버전을 의미.
현재(230409 기준) version 3 이상을 사용

 

* services

실행하려는 컨테이너들을 정의하는 영역
컨테이너에 대한 이름, 이미지, 포트 매핑, 환경변수, 볼륨 등의 정보를 가지고 컨테이너를 생성하고 관리

 

    - image : 컨테이너의 베이스 이미지

    - build : 정의된 도커파일에서 이미지 빌드하고 서비스 컨테이너 생성

    - environment :  컨테이너에 적용할 환경변수 설정 (run 명령어의 --env, -e 옵션과 동일)

    - command :  컨테이너가 실행될 때 수행할 명령어 (run 명령어의 서브 command에 적용하는 것과 동일)

    - depends_on : 컨테이너 간의 의존성 주입. 여기에 적힌 컨테이너가 먼저 생성되야한다. 

    - ports : 개방할 포트 지정 (run 명령어의 -p 와 동일)

    - expose : 링크로 연계된 컨테이너에게만 공개할 포트 설정

    - volumes : 컨테이너에 볼륨 마운트

    - restart : 컨테이너가 종료될 때 재시작 정책

          - no : 재시작 되지 않음

          - always : 외부에 영향에 의해 종료 되었을 때 항상 재시작 (수동으로 끄기 전까지 항상 재시작)

          - on-failure : 오류가 있을 시 재시작

 

📢 참고

  • yaml 파일은 2칸씩 들여쓰기(indent) 해야함

 


 

2️⃣ 도커 컴포즈로 컨테이너 실행할 수 있나요?

1) 도커 컴포즈가 사용할 서비스 디렉토리 생성

webserver 디렉토리를 생성하고(mkdir = make directory), webserver 로 이동 (cd = change directory)  

mkdir webserver
cd webserver

 

2) docker-compose.yml 생성

도커컴포즈  yml(=yaml)파일 생성

cat > docker-compose.yml

그 안에 아래 처럼 작성 (*yaml 파일은 2인덴트(들여쓰기) 기준!!) 

version: '3'

services:
  web:
    image: httpd:latest
    ports: 
      - "80:80"
    links:
      - mysql:db
    command: apachectl -DFOREGROUND
    
  mysql:
    imge: mysql:latest
    command: mysqld
    environment:
      MYSQL_ROOT_PASSWORD: pass

 

 

3) docker-compose 명령어

# start : 시작, up : 생성 및 실행 , d 옵션 : detach모드 즉, 백그라운드 실행
docker compose up [-d]  

# 지금 위치한 디렉토리 대상 도커컴포즈 파일 기준으로 프로세스 목록 조회
docker compose ps

# 개수 설정
docker compose scale mysql=2

# stop : 중지, down : =rm, 중지 및 삭제
docker compose down

 

 

명령어 설명
up 컨테이너 생성/시작
ps 컨테이너 목록 표시
logs 컨테이너 로그 출력
run 컨테이너 실행
start 컨테이너 시작
stop 컨테이너 정지
restart 컨테이너 재시작
pause 컨테이너 일시 정지
unpause 컨테이너 재개
port 공개 포트 번호 표시
config 구성 확인 (yaml 파일 문법 체크
kill 실행 중인 컨테이너 강제 정지
rm 컨테이너 삭제
down 리소스 삭제
-f 다른 폴더에 있는 yaml파일을 실행하고 싶을 때 사용하는 옵션
scale 서비스이름=개수 해당 서비스 개수를 설정

 

 

 


📍10-2. 빌드에서 운영까지 : 실습

 

 

0️⃣ 도커 컴포즈 플러그인 설치

 

Install the Compose plugin

 

docs.docker.com

sudo apt-get update
sudo apt-get install docker-compose-plugin

 

 


 

여기 실습 부분은 도커에서 제공하는 자료와 함께 실습

 

Try Docker Compose

 

docs.docker.com

 

 

 

1️⃣ 서비스 디렉토리 생성 및 파일 생성 

서비스 디렉토리 생성

mkdir composetest
cd composetest

 

실습용 예시 파일 app.py

cat > app.py
import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)

끝에 ^C는 종료로 눌리는 것으로 내용에는 포함되지 않음

 

실습용 파일 requirements.txt

끝에 ^C는 종료로 눌리는 것으로 내용에는 포함되지 않음

 

 


2️⃣ 빌드를 위한 dockerfile 생성

파일 생성

cat > Dockerfile

파일 작성

FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask","run"]
# 다음줄에서 crtl+c하면 저장 및 종료

파일 조회

# > 리다이렉션이 들어가면 덮어쓰기가 되므로 빼주면 조회가능
cat Dockerfile

명령어 분석

명령어 설명
FROM python:3.7-alpine python:3.7-alpine 이미지를 베이스로 사용
WORKDIR /code 작업 디렉토리는 현재위치의 code라는 폴더를 사용
ENV FLASK_APP=app.py 환경변수 FLASK_APP 에 app.py할당
ENV FLASK_RUN_HOST=0.0.0.0 환경변수 FLASK_RUN_HOST에 0.0.0.0 할당
RUN apk add --no-cache gcc musl-dev linux-headers  
COPY requirements.txt requirements.txt 호스트의 requirements.txt 파일을 컨테이너 작업 디렉토리인 code 에 복사
RUN pip install -r requirements.txt requirements.txt 내부 요소를 읽어 pip 인스톨을 진행
EXPOSE 5000 5000포트를 개방
COPY . . 현재 . 디렉토리를 컨테이너의 . 디렉토리로 모두 복사
CMD ["flask","run"] 복사한 코드를 flask로 실행하는 명령어 

 

 


3️⃣ docker-compose.yml 생성

docker-compose.yml 생성

cat > docker-compose.yml

 

내용 작성

version: "3"
services:
  web:
    build: .
    ports:
      - "5000:5000"
  
  redis:
    image: "redis:alpine"

 

 


4️⃣ docker-compose 명령어 

컴포즈를 실행 (** 컴포즈 파일명이 docker-compose.yml 아니라면 -f 옵션을 통해 파일 이름을 정확하게 적어야함)

docker compose up

6번 들어갔더니 6번 카운팅 됨

 

 


5️⃣ docker-compose 확인

# 현재 컴포즈파일로 인해 실행된 프로세스 목록 조회
docker compose ps

 


6️⃣기존 docker-compose를 중간에 수정하려면

일단 기존 컨테이너들을 중지하고 삭제

docker compose down

 

비쥬얼 에디터로 compose 파일 수정

컨테이너에 있는 파일을 호스트랑 볼륨마운트해서 호스트에서 수정해보기 위한 볼륨 마운트

version: "3"
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  
  redis:
    image: "redis:alpine"

수정하고 다시 up

 

그리고 호스트의 디렉토리에 마운트했으니 호스트의 app.py를 바로 수정해서 적용되는 지를 확인해보자

World > Docker로 변경
이전
이후

 


7️⃣ 개수를 조절해보자

 

# 현재 scale 명령어는 비활성화 되었고
docker compose scale redis=3

# up의 옵션으로 사용해야한다
docker compose up --scale redis=3

redis 서비스가 3개로 늘어난걸 볼 수있다

이 명령어를 통해 그때그때 사용자의 수에 따라 scale out, scale in을 해줄 수 있다. 

 

📢 다만, 포트포워딩된 경우는 정해진 포트를 쓰기 때문에 확장이 불가능, 다른 포트 사용해야함

 


8️⃣ 추가 명령어

 

  • run을 이용하면 서브 명령어 전달 가능

아래는 web 컨테이너에 env 명령어로 환경변수 보여달라는 의미

# docker compose run [OPTIONS] SERVICE [COMMAND] [ARGS...]
docker compose run web env

 

  • 해당 컨테이너 로그 보기
docker compose logs web

 


9️⃣ 종료 및 삭제

# 종료
docker compose stop

# 종료 및 삭제
docker compose down

# --volumes 옵션까지 넣으면 컴포즈로 인해 생성된 볼륨까지도 모두 삭제
docker compose down --volumes

 


🔟 또 다른 예시

워드프레스랑 mysql이랑 연동해보는 예시

 

WordPress samples

 

docs.docker.com

 

1) 서비스 디렉토리 생성

2) docker-compose.yml 생성

3) compose 실행 확인

 

📌 공부 계기

추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 

 

목차

 

📍9-1. 컨테이너 간 통신 (네트워크) : 이론

1️⃣ 컨테이너는 어떻게 통신하나요?

 

* 컨테이너를 생성하게 되면 컨테이너는 Net namespace[각주:1]라는 기술을 통해서 구현된 가상화로 각자 독립된 네트워크 공간을 할당 받는다. 

 

 

  • 컨테이너의 네트워크 모델 

 

① 컨테이너를 생성시 eth0라는 네트워크 인터페이스를 컨테이너에 할당

② 그와 동시에 호스트에도 veth(virtual ethernet)라는 네트워크 인터페이스가 할당

③ 이 veth를 통해 컨테이너의 eth0 인터페이스와 서로 통신

 

④ 그리고 호스트 veth는 docker0과 바인딩되고 

docker0는 호스트의 eth0 인터페이스 연결되어 

⑥ 외부로부터 들어온 요청을 연결 

 

 

* ethernet 이란?

컴퓨터 네트워크 방식으로 가정이나 건물과 같은 로컬 환경(LAN)에서 가장 많이 활용되는 기술 규격이다.

이더넷은 OSI 모델의 물리 계층에서 신호와 배선, 데이터 링크 계층에서 MAC(media access control)패킷과 프로토콜의 형식을 정의한다. 

네트워크에 연결된 각 기기들이 48비트 길이의 고유의 MAC 주소를 가지고 이 주소를 이용해 상호간에 데이터를 주고 받을 수 있도록 만들어져 있다.

 

* docker0 란?

docker0 인터페이스는 호스트의 eth0 인터페이스와 컨테이너 eth0 사이의 중재자 역할, 연결 다리 역할을 하는 가상 브릿지로 도커를 설치하면 도커 내부로직에 의해 자동으로 설정되며, 자동으로 IP를 할당받게 된다. 

(기본 172.17.X.X로 시작하며 netmask는 255.255.0.0으로 설정

 

* veth (virtual ethenet) 란?

컨테이너 생성시 도커가 자동으로 생성해주는 가상의 네트워크 인터페이스로, 항상 쌍으로 생성된다.

하나는 vethxxxx 라는 이름으로 호스트에 생성되어 docker0에 바인딩 되는 것 하나와

eth0라는 이름으로 컨테이너 내부에 생성되어 veth와 연결하는 것 하나를 생성한다. 

 

 

  • 그래서 컨테이너 네트워크는 

- virtual ethernet bridge : 172.17.0.0/16

- L2[각주:2] 통신기반

- container 생성 시 veth 인터페이스 생성 (sandbox)

- 모든 컨테이너는 외부 통신을 docker0 통해 진행

- container running시 172.17.X.Y로 IP 주소할당

 

 

 

1) 이더넷 ip 주소 조회

ip address

docker0에 컨테이너 돌리니까 veth까지 보인다

** wsl2 환경에서는 별도로 bridge 기능을 활성화 하지 않으면 docker0이 보이지 않는다고 한다.

 

 


2️⃣ 컨테이너 포트를 외부로 노출할 수 있어요?

 

Port Forwarding 을 통해 포트를 외부로 노출시킬 수 있다. 

 

docker run [-p 호스트포트:컨테이너포트] <이미지명:태그>

 

iptables rule을 통해 포트 노출이 가능한데 포트포워딩을 하면 방화벽 룰이 만들어져 연결 가능

아래 명령어로 포트포워딩 된거 확인 가능

iptables -t nat -L -n -v

 

* 80포트를 열고있는 컨테이너들이 여러개인 것은 가능 하나 호스트의 eth0 에 80포트로 연결될 수 있는 건 하나. 컨테이너 끼리는 ip가 달라서 포트가 80포트로 같아도 각자의 포트라 상관없지만 연결되는 호스트의 포트 80은 단 하나만 존재하기 때문이다. 그러므로 nginx를 여러개 연결해주고 싶다면, 80포트가 아닌 다른 포트로 연결시키면 된다. 

* 포트끼리는 꼭 같은 포트로 일치시킬 필요 없다.

 

* 호스트 포트 중 사용하지 않고 있는 포트 중에 랜덤으로 부여하고 싶다면

# 호스트포트는 랜덤으로 지정
docker run [-p 컨테이너포트] <이미지명:태그>

만약 대문자 P만 한다면 dockerfile에서 expose로 정의하고 있는 포트에 맞춰 랜덤 포트를 설정하게 된다. 

docker run -P <이미지명:태그>

 

 


3️⃣ 컨테이너 네트워크를 추가할 수 있나요?

docker0에 할당되는 ip는 원하는대로 static할당이 불가능하다 

그럼 static으로 할당하거나 원하는 ip대역대에 할당하고 싶다면 

docker0의 대역대를 바꾸거나 유저 정의의 네트워크를 생성하면 가능하다 

 

1) 네트워크 생성 

# docker network create [--driver 방식] [--subnet 대역대/사이더] [--gateway ip주소설정] <네트워크명>
docker network create --driver bridge --subnet 192.168.100.0/24 --gateway 192.168.100.254 mynet

 

* driver : bridge 형태의 네트워크나 호스트 또는 non base의 네트워크를 할 것인지 설정 가능

* subnet : 서브넷 대역대 설정. 생략하게 되면 docker0에 따른 순서적인 대역대가 설정된다. 

* gateway : 컴퓨터 네트워크에서 서로 다른 통신망, 프로토콜을 사용하는 네트워크 간의 통신을 가능하게 하는 컴퓨터나 소프트웨어를 두루 일컫는 말로, 즉 다른 네트워크로 들어가는 입구 역할

 

 

🧐❓ IP주소 뒤 /숫자는 뭐지? CIDR (사이더)야! 사이더는 또 뭔데!?

더보기

정의로 하자면 Classless Inter-Domain Routing 으로 클래스 없는 도메인간 라우팅 기법이라고 한다.

(이게 무슨말이야)

 

IP에도 클래스가 있단 말이야?
사이더를 알기 전에 먼저 IP클래스가 어떻게 나뉘는 지 부터 보자.

 

1️⃣ A클래스

맨앞자리 수가 항상 0인 경우로 2진수로 표현하면 0xxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx 이다. 

범위는 00000000.00000000.00000000.00000000 (0.0.0.0) ~ 01111111.11111111.11111111.11111111 (127.255.255.255) 이다.

 

A클래스는 하나의 네트워크가 가장 많은 호스트 수를 가질 수 있는 클래스이며, 

ip주소 첫 옥테드[각주:3] 까지를 네트워크 범위로 한다

 

첫 옥테드 붉은 자리는 네트워크 범위, 뒤의 3개의 옥테드 파랑 부분은 호스트 범위

00000000 00000000 00000000 00000000

네트워크는 첫자리 0은 고정이라 이를 제외하면 2^7개 까지 가능하지만, 127은 루프백주소[각주:4] 라 제외되야해서 네트워크 번호는 1~126까지 가능하다.

 

만약 13.0.0.0의 네트워크를 할당 받으면 13부분이 네트워크, 나머지 0.0.0은 호스트 IP로 할당 가능한데

이 경우 13.0.0.0은 네트워크 주소 표현을 위해, 13.255.255.255는 브로드캐스트 주소로 사용하기 위해 빠지게 되고 이를 제외한 나머지 주소들은 전부 할당할 수 있어서 ip개수의 식이

(2^(호스트 2진수 수))-2 개로 위에서는 (2^24)-2개가 된다.  

 

네트워크 개수 호스트 개수
2^7 - 1 (앞이 0고정에, 127제외) 2^24 - 2
(네트워크 주소 0.0.0과 브로드캐스트 주소 255.255.255 제외)

 


2️⃣ B클래스

 

B클래스는 반드시 10으로 시작하며 2진수로 표현하면 10xxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx 된다.

128.0.0.0 ~ 191.255.255.255까지의 범위를 지닌다

앞이 10으로 고정되어 127 이후의 128 부터 네트워크 범위가 시작.

 

네트워크 범위가 두번째 옥테드 까지이다

 

00000000 00000000 00000000 00000000
네트워크 개수 호스트 개수
2^14 (앞의 10이 고정) 2^16 - 2
(네트워크 주소 0.0.0과 브로드캐스트 주소 255.255.255 제외)

 


 3️⃣ C클래스

 

C클래스는 반드시 110으로 시작하며 2진수로 표현하면 110xxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx  이며

앞이 110으로 고정되어 192.0.0.0 ~ 223.255.255.255 까지의 범위를 갖는다고 한다. 

 

네트워크 범위가 세번째 옥테드 까지이다

네트워크 범위가 가장 크므로 상대적으로 호스트 개수를 가장 적게 가질수 있는 클래스이기도 하다. 

 

00000000 00000000 00000000 00000000
네트워크 개수 호스트 개수
2^21 (앞의 110이 고정) 2^8 - 2
(네트워크 주소 0.0.0과 브로드캐스트 주소 255.255.255 제외)

 


클래스가 어떻게 나뉘는지 알아 보았다면 이제 다시 사이더로 돌아와 보자. 

 

IP주소를 2진수로 된 8비트 4개 블록으로 나누면 총 32개의 자리수가 생긴다

사이더는 32까지의 수를 사용하는 데 이 말인 즉슨 이 아래 자릿수들을 해당 수 만큼 고정하여 그룹핑하게 된다.

00000000 00000000 00000000 00000000

/24를 예로 들자면 아래 붉은 숫자 24개까지 같은 IP주소를 사이더 그룹으로 만들게 된다. 

00000000 00000000 00000000 00000000

예시로 192.168.100.0 에서 24 사이더를 설정해주게 되면 아래와 같은 수가 고정 ip가 되고 나머지가 호스트로 배정된다. 

11000000 10101000 01100100 00000000

C클래스와 범위가 같아서 뭐가 다르냐?! 싶지만

 

기존 클래스는 옥테드 단위로만 그룹을 나눌 수 있었다면! 

사이더를 사용하게 되면 /16, /24, /32 옥테드 기준이 아닌 그 외의 숫자로도 사이더 블록으로 그룹핑이 가능해서 

클래스와 상관없이 라우팅이 가능하기 때문에 사이더를 클래스 없는 도메인간 라우팅 기법이라고 한다.

 

기존의 Network Class 방식에 비해 유연하게 동작할 수 있고 그룹들을 계층적으로 관리가능 해 IP 주소 체계를 보다 효율화할 수 있게 해준다.

 

2) 네트워크 조회 

docker network ls

 

3) 컨테이너 생성시 네트워크 설정 

net 옵션으로 네트워크를 설정하지 않으면 기본 docker0로 설정된다. 

ip옵션도 설정해주지 않는다면 설정되는 네트워크 대역폭에서 순차적으로 배정된다.

(docker0로 네트워크가 설정되어 있다면 ip옵션을 사용해 static ip 할당이 불가능하다. 유저 정의 네트워크만 가능)

# docker run [-d] [--name 컨테이너명] [--net 네트워크이름] [--ip ip주소] [-p 호스트포트:컨테이너포트] <이미지명:태그>
docker run -d --name web --net mynet --ip 192.168.100.100 -p 80:80 nginx:1.14

 

 

 


 

4️⃣ 컨테이너끼리 통신은 어떻게 하나요?

컨테이너 간의 통신을 이용해 프론트 서버와 백 서버를 연결하여 사용할 수도 있다. 

 

1) 연결할 컨테이너 하나 생성 

예시로 mysql의 컨테이너를 생성할 건데 mysql의 컨테이너는 생성시 환경변수 설정이 필요하다.

e옵션으로 environment 환경변수를 사용해 mysql 계정 비밀번호를 설정

(v옵션으로 호스트에 데이터 저장할 수 있도록 볼륨마운트)

# e옵션 (environment 환경변수)
docker run -d --name mysql -v /dbdata:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=wordpress \
-e MYSQL_PASSWORD=wordpress \
mysql

 

2) 연결할 다른 컨테이너 하나 생성 

여기서 다른 컨테이너와 연결하려면 link 옵션을 사용해야 한다. 

# --link 연결할컨테이너명:임의명칭
docker run -d --name wordpress --link mysql:mysql \
-e WORDPRESS_DB_PASSWORD=wordpress \
-p 80:80 wordpress:4

 

 

 

 

 


📍9-2. 컨테이너 간 통신 (네트워크) : 실습

1️⃣ 컨테이너 네트워크 사용하기 & 컨테이너 포트 외부로 노출하기

 

1) 도커 bridge, eth0 주소 확인 

ip address

도커 0에 할당된 ip확인

 

 

brctl은 이더넷 브리지 관리 도구로 bridge-utils 패키지에 포함되어 있다. 

apt-get을 업데이트하고 apt-get install bridge-utils 해서 설치해주면 사용할 수 있다. 

 

아래 명령어를 쳐보면 docker0가 브리지 인터페이스임을 확인할 수 있다. 

brctl show

 

 

 

2) 컨테이너 하나를 생성하여 할당된 아이피를 확인해보자 

docker run -it --name c1 busybox

c1을 종료하지 말고 다른 세션으로 접속해 또하나의 busybox를 돌려보면

그 다음 아이피를 할당 받은 것을 확인할 수 있다.

다른 컨테이너로 웹서버를 하나 돌려봐도 그 다음 아이피가 할당 된 걸 확인 할 수 있다. 

 

그리고 이러한 컨테이너들은 docker0를 통해 외부로 나간다.

 

 

3) 좀 더 자세하게 보기

docker inspect c1

* sandbox : 컨테이너의 네트워크 환경

* endpoint : veth, 네트워크 인터페이스 

 

만약 컨테이너에서 신호가 나가려면 gateway를 통해 나간다 

이걸 받는 브리지 인터페이스는 자신의 ip주소를 호스트 ip address로 바꾸어 외부로 보내는 Masquerade 서비스 (마스커레이드), nat 서비스 (Network Address Translation) 를 지원하게 된다. 

 

 

아래 명령어로 nat 테이블을 보면 docker0에서 나가는 것은 어디로든 마스커레이드를 해준다는 게 표시가 되어 있다. 

iptables -t nat -L -v

 

 


2️⃣ 컨테이너 포트 외부로 노출하기

 

  • 포트포워딩 옵션들
# 호스트포트:컨테이너포트
docker run --name web1 -d -p 80:80 nginx:1.14
# 컨테이너포트
docker run --name web2 -d -p 80 nginx:1.14
# 대문자 P, expose 설정된 포트에 맞추는 옵션
docker run --name web3 -d -P nginx:1.14

 

1) 호스트 포트와 컨테이너 포트 둘다 설정 

docker run -p 80:80 -d --name web1 nginx

외부에서 컨테이너로 접근까지 확인!

 

2) 컨테이너 포트만 설정

호스트에서 사용하지 않는 포트 중 하나가 랜덤으로 컨테이너 80포트와 연결됨

docker run -p 80 -d --name web2 nginx

랜덤으로 32768 할당

 

3) 대문자 P 옵션 : dockerfile에 설정된 expose되어 있는 포트만큼 설정

허브에서 다운 받은 이미지들은 허브 상세 dockerfile에서 어느 포트에 설정되어 있는지 확인 할 수 있다. 

테스트해보려는 nginx 공식 dockerfile에는 expose로 80이 설정되어 있으므로 대문자 P 옵션 사용시 80으로 설정된다. 

이미 80이 있다면 랜덤포트로 설정하게 된다. 

여러개 expose되어 있다면 여러개 모두 설정된다. 여러개가 중복이라면 이또한 랜덤포트로 설정

docker run -P -d --name web3 nginx

중복된 80포트를 피해, 또 임의로 중복될 수 있는 그다음 포트를 피해 32769로 할당된 걸 볼 수 있다. 

 

 

 

📢 이렇게 3가지로 포트포워딩해 외부로 부터 커넥션하여 서비스 할 수 있게 된다. 

 


3️⃣ 유저 정의 (user-defined) 네트워크 구성하기

 

1) 네트워크 조회

docker network ls

여기서 bridge을 쓰고 있는게 docker0 이다

 

 

2) 네트워크 생성

docker network create --driver bridge --subnet 192.168.100.0/24 --gateway 192.168.100.254 mynet

* driver 설정 안해도 기본 설정이 bridge

* subnet 설정을 안하면 기본 도커가 쓰는 대역폭이 172.17 부터 시작하므로 그 이후로 설정된다. 

* 게이트웨이를 설정 안하면 대역폭 네트워크 주소를 제외하고 가장 첫번째 아이피를 사용한다.  

 

3) 네트워크 상세 조회

# docker network inspect <네트워크명>
docker network inspect mynet

 

 

4) 네트워크 사용 컨테이너 생성

# --net 네트워크명
docker run -it --name c1 --net mynet busybox

설정한 ip를 사용하는 것을 확인!

 

 


4️⃣ 컨테이너 서비스 운영

컨테이너를 통해 서버와 클라이언트 서비스를 운영해보자 

 

1) mysql 컨테이너 생성 및 실행

docker run -d --name mysql -v /dbdata:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=wordpress \
-e MYSQL_DATABASE=wordpress \ 
-e MYSQL_USER=wordpress \
-e MYSQL_PASSWORD=wordpress \
mysql

 

2) wordpress 컨테이너 생성 및 실행

docker run -d --name wordpress --link mysql:mysql \
-e WORDPRESS_DB_HOST=db \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=wordpress \
-e WORDPRESS_DB_NAME=wordpress \
-p 80:80 wordpress

 

흠... wsl로 하면 db 연결 실패했다하고

버박으로하면 Failed to connect to localhost port 80 뜨고....

마지막 연결 부분에 있어서 이슈가 있는 데 이부분은 해결하면 추가예정!

 

 


도커 네트워크 구조 참조

 

[Docker] Docker Network (docker0와 veth)

Docker Network 컨테이너를 생성하게 되면 컨테이너는 NET namespace라는 기술을 통해 구현된 가상화 기법을 사용하여 각자 독립된 네트워크 공간을 할당 받습니다. 그렇다면 이 독립된 네트워크 공간

yoo11052.tistory.com

 

  1. Net namespace
    Network interface, iptables 등 네트워크 리소스와 관련된 정보를 분할하여 각각의 다른 namespace에 할당 [본문으로]
  2. L2 (Layer 2)
    OSI계층의 2번째 레이어인 데이터 링크 계층 통신을 말한다 [본문으로]
  3. 옥테드 octet
    2진수 8자리를 옥테드라고 한다. [본문으로]
  4. 루프백주소
    네트워크상에서 자신을 나타내는 가상적인 주소이며, 자신에게 다시 네트워크 입력이 들어온다고 하여 루프백(Loopback) 주소라 한다 [본문으로]

📌 공부 계기

추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 

목차

 



📍8-1. Docker Container Storage : 이론

1️⃣ 컨테이너 볼륨이 뭐에요?

 

컨테이너 이미지는 readonly이다

컨테이너 이미지를 컨테이너로 돌리게 되면 RW (ReadWrite) 레이어가 추가되고 컨테이너에 추가되는 데이터들이 이곳에 저장되게 된다. 

이처럼 기존의 readonly 레이어에 readwrite 레이어를 올려 마치 하나인 것처럼 관리하고 보여주게 되는데

이를 union file system(다른말로 overlay) 이라고 한다.

 

이렇게 하나처럼 운영되는 컨테이너는 컨테이너를 삭제하면 rw레이어 데이터까지 지워버리게 된다. 

데이터를 보존해야하는데!

그래서 컨테이너가 제공하는 기능이 바로 볼륨이다. 

컨테이너 rw 레이어의 디렉토리 경로와 호스트 저장소 디렉토리를 연결하여 rw레이어에 쌓일 데이터를 호스트 컴퓨터 저장소에 쌓이게 함으로써 컨테이너 삭제시에도 데이터를 보존할 수 있게 한다. 

이렇게 연결하는 걸 볼륨 마운트라고 한다. 명령어로는 run시 v옵션으로 가능하다.

docker run [-v 호스트디렉토리:컨테이너디렉토리] <이미지명:태그>

 


2️⃣ 데이터를 보존하고 싶어요

 

-volume 옵션 사용

-v <host path> : <container mount path>   기본 방식
-v <host path> : <container mount path> : <read write mode> ***
-v <container mount path> 호스트의 /var/lib/docker 밑에 UUID 디렉토리 아래로 저장시켜준다. 

*** 보안을 위해 컨테이너는 오직 호스트 경로의 데이터만 읽어오고 컨테이너에 쌓이는 게 호스트에 영향이 가지 않게 하는 것은 read write mode 자리에 ro를 (readonly)를 써주면 된다. 

 

 


3️⃣ 컨테이너끼리 데이터 공유 가능한가요?

 

하나의 컨테이너 디렉토리와 호스트 디렉토리를 연결하여 데이터를 쌓고,

또 다른 컨테이너 디렉토리와 그 호스트 디렉토리를 연결하여 데이터를 공유하면 

두 컨테이너가 같은 호스트 디렉토리를 바라보게 되어 컨테이너끼리 데이터 공유가 가능하다.  

 

ex)

컨테이너가 web content를 만들어 저장하면 다른 webserver 컨테이너가 그 생성한 web content 파일을 가지고 실행을 할 수가 있다. 클라이언트는 webserver 컨테이너에 접속하는 것 만으로도 web content 컨테이너가 제공하는 것과 webserver가 제공하는 것을 다 누릴 수 있게 된다. 

 

 

 


📍8-2. Docker Container Storage : 실습

1️⃣ mysql DB data 영구 보존하기

 

1) MySQL 컨테이너 생성 및 실행하기

*** MySQL DB 실행할 때는 관리자의 패스워드를 함께 지정해줘야한다. 

해당 경로가 없으면 디렉토리를 자동으로 생성함

# docker run [-d] [--name 컨테이너명] [-v 호스트경로:컨테이너경로] [-e 환경변수=값] <이미지:태그>
docker run -d --name db -v /dbdata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=pass mysql:latest

2) 컨테이너 안의 MySQL에 접속해서 데이터베이스 생성해보기

컨테이너를 터미널로 연결해서 mysql에 접속 

그리고 데이터베이스 확인까지!

DB생성 및 확인

컨테이너 안에 ttabae라는 DB를 생성했으니 호스트 연결된 경로에도 ttabae가 연결됬는 지 확인하면 된다. 

호스트 경로에 들어가 조회하니 ttabae가 있는 것을 확인! 

 

3) 컨테이너를 삭제했을 때도 남았는지 확인

남아있다!

 

4) 호스트 경로 없이 컨테이너 경로만 설정하게 되면?

# docker run [-d] [--name 컨테이너명] [-v 컨테이너경로] [-e 환경변수=값] <이미지:태그>
docker run -d --name db -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=pass mysql:latest

inspect로 컨테이너 조회하면 마운트 정보에 호스트 소스는 /var/lib/docker/volumes/uuid/_data에 저장된걸 확인할 수 있다.

 

이 역시도 컨테이너를 삭제한 후에 데이터가 남는 걸 확인 할 수 있다.

/var/ 폴더는 root 계정으로 접근 가능!

 

5) docker volume 관리 명령어

 

  • 볼륨 조회
docker volume ls

 

  • 볼륨 제거
docker volume rm 볼륨UUID

해당 디렉토리가 사라져있는 걸 확인할 수 있다

 


2️⃣ 웹데이터 readonly 서비스로 지원하기

웹 컨텐츠를 생성하고 그걸 nginx로 운영하는 webserver로 서비스 할 수 있게 하는 실습

 

📢 여기서부터는 버츄얼박스와의 ip연결 문제로 이슈가 생겨서 wsl로 진행

 

1) 웹 컨텐츠 생성하기

폴더 하나 만들고 그 안에 단순 태그를 출력해 index.html을 하나 생성한다

 

2) 웹서버 서비스할 index.html을 호스트 파일로 교체

# docker run [-d] [--name 컨테이너명] [-v 호스트경로:컨테이너경로:읽기쓰기모드] /
# [-p 호스트포트:컨테이터포트] <이미지명:태그>
docker run -d --name web -v /webdata:/usr/share/nginx/html:ro -p 80:80 nginx:1.14

 


3️⃣ 컨테이너간 데이터 공유하기

 

디스크 사용량의 결과를 주기적으로 만들어내는 컨테이너를 만들어

 

* 디스크 사용량 모니터링

디스트 모니터링 할 때 사용하는 df 명령어 (disk free) 에 h옵션 (human/사람이 보기좋은 크기단위표시) 로 디스크 사용량을 모니터링 

df -h /

 

🚩 일단 이걸 실습하기 위한 파일 생성

① mkdir로 lab8이라는 폴더 생성

② lab8로 이동

③ vi로 비쥬얼에디터 열어 df.sh 파일 생성

그 안에 쉘스크립트 내용을 작성

스크립트 설명
#! /bin/bash #!은 스크립트를 실행할 쉘을 지정하는 선언문
이 스크립트는 /bin/bash라는 bash쉘을 실행한다고 하는 것
mkdir -p /webdata mkdir(make directory)로 디렉토리 생성
p옵션 (parents)은  기존 디렉토리가 존재해도 에러가 발생하지 않고 필요경우 부모 디렉토리를 생성한다. 
while true 반복문으로 조건을 true로 했기에 무한 반복
do 반복될 부분의 시작 표시
df -h / > /webdata/index.html df 명령어로 (disk free) 디스크 사용량을 보며 
h옵션(human)으로 사람이 보기 좋은 크기단위로 표시한다
> (리다이렉션)은 보통 command > filename과 같은 형태로 사용하며, 표준 입력을 전달 또는 표준 출력을 파일로 저장
따라서 디스크 사용량을 저 경로의 index.html파일로 저장한다는 뜻
sleep 10  10초 일시정지
done 반복문 중 하나로 do와 짝을 이루어 반복될 부분 닫는 역할

④ cat으로 df.sh 내용 다시 확인

⑤ dockerfile도 vi로 생성하고 cat으로 확인

스크립트 설명
FROM ubuntu:20.04 베이스이미지를 ubuntu:20.04에서
ADD df.sh /bin/df.sh 컨테이너 빌드시 호스트의 df.sh 파일을 컨테이너 /bin/df.sh로 복사 
RUN chmod +x /bin/df.sh /bin/df.sh에 권한 설정하는 chmod (change mode) 명령어로 +x 속성(executable/실행가능) 을 주는 명령어를 실행
ENTRYPOINT["/bin/df.sh"] /bin/df.sh 실행

⑥ 도커 이미지 빌드 및 확인

 


🚩 생성한 파일과 이미지를 가지고 컨테이너를 돌려 아래 구조로 연결

 

① index.html을 주기적으로 만드는 컨테이너 df 생성 및 실행

docker run -d -v /webdata:/webdata --name df df:latest

② 생성된 index.html을 클라이언트로 연결할 web server 컨테이너 web 생성 및 실행 

docker run -d --name web -v /webdata:/usr/share/nginx/html:ro -p 80:80 nginx:1.14

③ 결과

📌 공부 계기

추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 

목차

 



📍7-1. 컨테이너 관리하기 : 이론

공식문서 링크

 

Docker run reference

 

docs.docker.com

 

 

1️⃣ 컨테이너 하드웨어 리소스 제한 어떻게 해요?

 

컨테이너는 호스트 하드웨어 리소스의 사용 제한을 받지 않는다. (호스트의 전부 사용가능)

효율적으로 사용하기 위해서 리소스 제한을 걸어야한다.

 

Docker 명령어를 통해 제한 할 수 있는 리소스

- CPU, Memory, Disk I/O 

 

$ docker run --help

명령어에서 그 종류를 확인 할 수 있다. 

 

  •  Memory 리소스 제한 

제한단위 b (바이트), k(키로바이트), m(메가바이트), g(기가바이트)로 할당

옵션 의미
--memory, -m 컨테이너가 사용할 최대 메모리 설정, 그 이상 쓰게되면 컨테이너가 스스로 킬함
--memory-swap 컨테이너의 스왑메모리[각주:1] 영역 설정
설정시 주의)
이 옵션뒤의 메모리 크기는 메모리 + 스왑메모리의 크기를 넣는다.
스왑메모리를 사용하지 않으려면 이 옵션뒤에 메모리 크기와 동일하게 적어주면 되며
만약 스왑 메모리를 설정을 따로 안하면 메모리의 2배가 설정된다.
--memory-reservation --memory 값보다 적은 값으로 구성하는 소프트 제한 값 설정 
--oom-kill-disable OOM Killer[각주:2]가 프로세스 kill하지 못하도록 보호
$ docker run -d -m 512m nginx:1.14
      메모리 512 메가 바이트로 설정  이미지명:태그
      -m 1g --memory-reservation 500m  
      해당 컨테이너는 최소 500메가 바이트를 보장받고 최대 1기가바이트 사용가능   
      -m 200m --memory-swap 300m  
      메모리는 200메가바이트 할당하고 스왑 뒤에 300메가 바이트를 써놨으니
200m + 300m = 500m 일까? ❌
뒤의 300m는 앞의 200m를 포함하고 있어 실제 스왑메모리는 100m에 해당
 
      -m 200m --oom-kill-disable  
      메모리는 200m 할당하고 물리메모리가 부족해서 oom killer가 실행됬을 때에도 이 컨테이너는 강제 종료되지 않고 실행을 보장받는다.   

 

 

  •  CPU 리소스 제한 
옵션 의미
--cpus 컨테이너에 할당할 최대 CPI core를 지정. 어떤 core를 쓸지는 지정되지 않는다
--cpuset-cpus 컨테이너가 사용할 수 있는 CPU나 코어를 할당. CPU index는 0부터 시작.
--cpu--share 컨테이너가 사용하는 CPU의 상대 가중치 설정.
말그대로 CPU를 상대적으로 얼마나 사용할 수 있는지를 설정한다. 기본은 1024이다.
$ docker run -d -cpus=".5" ubuntu:20.04
      이 컨테이너는 최대 0.5개의 CPU파워 사용가능 이미지명:태그
      -cpuset-cpus 0-3  
      이 컨테이너는 인덱스 0부터 3까지 해당하는 CPU가 할당  
      -cpu-shares 2048  
      컨테이너가 사용하는 CPU 상대 가중치를 2048로 설정
만약 다른 컨테이너가 1024라면 이 컨테이너는 다른 컨테이너에 비해 2배 사용가능
 

 

옵션 의미
--blkio-weight
--blkio-weight-device
모든 컨테이너가 동작시 block I/O에 I/O 스케쥴링을 받게 되는데 여기서 Quota(쿼터/몫)를 설정할 수 있으며 100-1000까지 선택가능하다
기본은  500
weight는 일단 상대적 가중치를 의미하며 만약 다른 컨테이너가 500이고 한 컨테이너만 1000일시 I/O 스케쥴링을 다른 컨테이너에 비해 2배더 할당 받을 수 있다. 
-devide가 붙은 옵션은 특정 디바이스에 대해서만 가중치를 부여한다. 
--device-read-bps
--device-write-bps
특정 디바이스에 대한 읽기와 쓰기 작업의 초당 제한은 kb, mb, gb 단위로 설정
--device-read-iops
--device-write-iops
컨테이너의 read/write 속도의 쿼터를 설정한다
초당 쿼터를 제한해서 I/O를 발생시킨다. 설정시 0 이상의 정수로 표기하며 이 수는 아래 식의 iops 값에 해당한다. 
초당 데이터 전송량 = IOPS * 블럭크기 (단위 데이터 용량)
$ docker run  -it --rm  --blkio-weight 100 ubuntu:latest /bin/bash
      (다른 컨테이너들이 전부 500이면) 이 컨테이너의 Block IO의 쿼터를 100으로 하여 500보다 상대적으로 적게 리소스를 할당 받겠다    
      --device-write-bps /dev/vda:1mb    
      디바이스 vda에 write해줄때는 최대 1메가바이트로 설정    
      --device-write-iops /dev/vda:100    
      디바이스 vda에 iops값 100을 할당    

 


2️⃣ 컨테이너 사용 리소스를 확인하는 모니터링 툴이 있나요?

 

  • 도커 모니터링 명령어

1) 실행중인 컨테이너의 런타임 통계 확인

docker stats [옵션] [컨테이너]

 

2) 도커 호스트의 실시간 event 정보 수집 및 출력

docker events -f container=<컨테이너명>
docker image -f container=<컨테이너명>

 

  • cAdvisor

구글에서 만든 도커 모니터링 툴

 

GitHub - google/cadvisor: Analyzes resource usage and performance characteristics of running containers.

Analyzes resource usage and performance characteristics of running containers. - GitHub - google/cadvisor: Analyzes resource usage and performance characteristics of running containers.

github.com

 

 


📍7-2. 컨테이너 관리하기 : 실습

 

➕ 이 실습 전에 추가로 알아둘 내용

리눅스의 부하 테스트 프로그램 중 하나 Stress

더보기

부하 테스트 프로그램 stress를 이용한 dockerfile 생성

비쥬얼 에디터로 dockerfile 생성

 

컨테이너 빌드하고 

 

아래 명령어를 치면 2개의 cpu에 작업부하를 발생시킴

stress --cpu 2

아래는 메모리 부하 테스트로 프로세스 2개와 사용할 메모리 만큼을 부하 발생시킴

stress --vm 2 --vm-bytes <사용할 크기>

 

1️⃣ 컨테이너 리소스 제한

  •  메모리 리소스 제한 
$ docke run [-m 메모리크기] [--memory-wap 메모리+스왑크기] <이미지명> [명령어]
# $ docke run -m 100m --memory-swap 100m stress:latest stress --vm 1 --vm-bytes 90m -t 5s
$ docker run -m 100m --memory-swap 100m stress:latest stress --vm 1 --vm-bytes 90m -t 5s
    물리메모리 물리메모리+스왑메모리 이미지 명령어 stress 90mb의 메모리 부하를 5초간

성공

100mb의 메모리를 90mb만 사용했으므로 성공적으로 실행 

하지만 만약 90mb가 아니라 150mb를 준다면?

실패

최대 메모리를 오버하여 실패가 되어 바로 컨테이너가 kill된걸 확인할 수 있다.

 

여기서 스왑메모리 옵션을 지워준다면?

성공!

왜냐하면 스왑메모리를 명령어로 설정해주지 않으면 물리메모리의 2배로 기본 설정이 되기 때문에 

--memory-swap 200m를 설정해준 것처럼 되어 정상 작동한다. 

 

🚩 트러블 (해결은 아직이고 일단 체크)

더보기

또잉?? oom killer로 테스트 해보려고 하니 당신의 kernel에서 지원을 안해 oom killer 내용을 삭제했다는 메시지가 나온다.

docker run -d -m 100m --name m4 --oom-kill-disable=true nginx
inspect로 봐도 안되어 있음

 

ubuntu 전체가 그런건 아닌거 같고 .. 검색해보니 현재 나랑 같은 22.04 LTS에서 이런 문제를 겪었다는 글을 찾을 수 있었다. 원인과 해결책은 아직이라 좀 더 조사해봐야겠다.

 

 


 일단 20.04 LTS에서는 정상작동하는 것 확인

docker inspect --format '{{.HostConfig.OomKillDisable}}' m4

 

또 다른 파일을 조회하여 확인 가능하다. 

cat /sys/fs/cgroup/memory/docker/컨테이너fullID/memory.oom_control

 

한데 이것도 22.04에서 시스템 디렉토리 구조가 바뀌었고, 컨테이너에 memory.oom_control이라는 파일도 없다. 

 


  •  CPU 리소스 제한 실습 

1) cpu 확인

lscpu

버추얼박스에서 cpu2개 설정해놨기 때문에 2개 조회

 

2) CPU 할당해보기

인덱스 1인 CPU 할당하고(--cpuset-cpus 1), stress 이미지에 cpu가 2개 돌아가게 되어있어서 cpu를 1개도 바꿔주고(stress --cpu 1), 이름 c1이라는 컨테이너를 생성해(--name c1) 백그라운드(-d)로 러닝시키는 명령어 

# docker run [--cpuset-cpus cpu인덱스] [--name 컨테이너이름] [-d] <이미지명:태그> [명령어]
docker run --cpuset-cpus 1 --name c1 -d stress:latest stress --cpu 1

 

3) 확인

htop
# 이 명령어 쓰려면 아래 명령어로 htop 설치해야함
# sudo apt install htop

보면 프로세스로 stress --cpu 1이 실행되는 걸 확인할 수 있고, cpu 1번이 100퍼센트로 돌고 있는 걸 확인할 수 있다. 

으로 0번도 100퍼센트 돌아가게 하니

아까의 컨테이너랑 같이 0번과 1번 모두 100프로 돌고 있다. 

 

만약 --cpuser-cpus를 0부터 1까지로 설정하고 cpu 실행을 1개로만 설정했다면 0부터 1사이에서 그때그때 상황마다 1개만 선택해서 돌아간다.

docker run --cpuset-cpus 0-1 --name c1 -d stress:latest stress --cpu 1

 

4) cpu-share로 가중치를 줘보자

각각 cload1에 2048, cload2에 기본, cload3,4에 512 가중치를 주었다. 

# docker run [-c 가중치] [--name 컨테이너명] [-d] <이미지명:태그>

# 가중치 설정 케이스
docker run -c 2048 --name cload1 -d stress:latest
# 가중치 설정 따로 안한 기본 케이스
docker run --name cload2 -d stress:latest
# 가중치 설정 케이스
docker run -c 512 --name cload3 -d stress:latest
# 가중치 설정 케이스 (3이랑 똑같이)
docker run -c 512 --name cload4 -d stress:latest

이거 실제 가중치를 받은 만큼 알아보고 싶다!

그럼 모니터링 툴로 ㄱㄱ

 

 


  •  Block I/O 제한 

1) block I/O 조회

lsblk

하늘색 부분이 device 이름이다

 

2) 디바이스 별 iops 설정

# docker run [-it] [--rm] [--device-write-iops /dev/디바이스이름:쿼터] <이미지명:태그> [명령어]
docker run -it --rm --device-write-iops /dev/sda:10 ubuntu:latest /bin/bash

여기서 --rm 은 컨테이너를 일회성으로 쓸때 사용하며, 컨테이너가 종료되면 컨테이너와 컨테이너 관련 리소스까지 깨끗하게 삭제하는 옵션이다. 

 

위의 명령어로  쿼터 10으로 할당된 우분투를 실행시킨 후

아래 명령어를 실행해보자

dd if=/dev/zero of=file1 bs=1M count=10 oflag=direct

* dd : data duplicator

* if : 지정한 파일(위에서는 /dev/zero)를 입력 대상으로 설정

* of : 지정한 파일(file1)을 출력 대상으로 설정

* bs : 바이트를 기준으로 하며 한번에 읽고 쓸 최대 바이트 크기 지정 

* count : 지정한 블록 수 만큼 복사

* oflag : 테스트 파일을 쓸때 사용하는 file flag를 설정, direct 경우 O_DIRECT플래그를 켜고 write()를 호출하게 되는데 이 플러그를 이용하면 파일시스템에 캐시 영역을 사용하지 않고 바로 디스크를 쓰기때문에 입출력 성능 측정할때 필요하다.[각주:4]

10개 복사한 결과와 걸린 시간등을 알 수 있다.

쿼터를 100으로 할당해서 다시 해보면

쿼터 10일때 5.5 MB/s 밖에 안나오던게 쿼터 100이 되니 93.2MB/s 나 나온걸 확인 할 수 있다. 

 

 


2️⃣ 컨테이너 모니터링하기

 

1) 컨테이너 런타임 통계

컨테이너 설정 안하면 실행중인 모든 컨테이너 대상 조회

docker stats [옵션] [컨테이너]

이렇게 런타임으로 돌아가는 걸 볼 수 있다

그런데 상대적 비율로 돌아간다고 하셨는데 CPU 비율이 가중치처럼 안돌아가는 데.. 왜지.. 오히려 기본설정인 cload2가 더 많은 비율을 보인다. 

 

cpu를 하나로 고정해봐도... cload2가 더 많은 퍼센트를 차지.. 기본 설정이 뭔가 달라진걸까?

확실히 기본 설정이 달라진 듯

cload5로 가중치를 1024를 명시해주고 돌려보니 확실히 맞는 비율이 나온다. 

 

다시 cpu를 하나로 고정하지말고 테스트 해보자

cpu를 여러개 사용하면 하나로 고정했을때 보다 안정정으로 비율이 나오지 않는다. 그래도 꽤 비율이 맞는 편

 

 


3️⃣ cAdvisor 설치해서 사용하기

 

그리고 cAdvisor 깃헙의 명령어를 적용

 

명령어 적용해 돌리고 해당 포트로 연결하면 아래와 같은 UI로 컨테이너를 모니터링 할 수 있다. 

  1.  Swap Memory
    RAM 즉 물리 메모리가 다 차게 되어 프로세스가 작업을 이어 나가지 못하고 종료되는 것을 방지하기 위해 하드디스크 공간을 이용하여 부족한 메모리를 대체할 수 있는 메모리 [본문으로]
  2. OOM Killer (Out Of Memory Killer)
    리눅스 기능 중 하나로 메모리가 부족할 경우 특정 프로세스를 강제로 종료하여 메모리를 확보하는 기능 [본문으로]
  3. Block I/O
    블록 장치는 개별 바이트 단위가 아닌 일정 크기(block) 단위로 접근하는 장치
    간단히 말하면 하드 디스크와 같은 대용량 저장 장치를 말한다. [본문으로]
  4. 출처: https://hbase.tistory.com/21 [본문으로]

📌 공부 계기

추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 

목차



📍6-1. 컨테이너 사용하기 : 이론

* 명령어 표 참고사항 -  [ ] : 선택사항 ,  <>: 필수사항, | : 둘중 하나

 

몇가지를 정리해뒀지만 역시 제일 좋은 건 공식문서다. 😘

 

Docker run reference

 

docs.docker.com

 

1️⃣ 컨테이너 이미지를 어떻게 사용해요?

명령어 설명
$ docker search [옵션] <이미지이름:태그명> 이미지 검색
$ docker pull [옵션] <이미지이름:태그명> 이미지 다운로드 (태그 안쓰면 기본 latest)
$ docker images [옵션] 다운받은 이미지 목록 출력
$ docker inspect [옵션] <이미지이름:태그명> 다운받은 이미지 상세보기
$ docker rmi [옵션] <이미지이름> 이미지이름

 

 

2️⃣ 컨테이너를 실행하고 종료하는 명령을 알고싶어요

  • 컨테이너 실행 라이프 사이클

출처: https://techmormo.com/posts/docker-made-easy-3-container-lifecycle/

 

명령어 설명
$ docker create [옵션] <이미지명:태그> 이미지를 가지고 컨테이너 생성 (run과 다르게 러닝은 X)
$ docker start [옵션] <컨테이너명|컨테이너ID> 컨테이너 실행(running) 
$ docker run [옵션] <이미지명:태그> pull + create + start : 이미지 다운받고 컨테이너를 생성하고 running 시킴, 이미지가 다운받았다면 create + start 만
$ docker stop [옵션] <컨테이너명|컨테이너ID> 동작중인 컨테이너 중지
$ docker rm [옵션] <컨테이너명|컨테이너ID> remove로 컨테이너 삭제

 

 

3️⃣ 동작중인 컨테이너를 관리 명령어가 궁금해요

명령어 설명
$ docker ps [옵션] ps(프로세스) 조회
$ docker inspect [옵션] <컨테이너명|컨테이너ID> 이미지명이 아니라 컨테이너를 쓰면 컨테이너에 대한 상세보기가 가능하다
$ docker top <컨테이너명|컨테이너ID> [ps 옵션] 해당 컨테이너에서 동작중인 프로세스 정보 확인
$ docker logs [옵션] <컨테이너명|컨테이너ID> 러닝중인 해당 컨테이너가 만들어낸 로그 정보 확인
$ docker exec [옵션] <컨테이너명|컨테이너ID> /bin/bash 러닝중인 해당 컨테이너에 명령어를 추가하고 싶을때 해당 컨테이너의 bash 연결
$ docker attach [옵션] <컨테이너명|컨테이너ID> FOREGROUND로 실행중인 컨테이너에 연결

 


📍6-2. 컨테이너 사용하기 : 실습

1️⃣ 컨테이너 이미지 관리 명령어 사용하기

 

1) 이미지 검색 

docker search [옵션] <이미지이름:태그명>

허브에 존재하는 nginx 키워들을 가진 이미지들 모두 조회

name description stars official automated
이미지 이름 설명 사람들이 준 별 수 공식 이미지 여부 자동 빌드 되는지

 

2)  이미지 다운로드 

docker pull [옵션] <이미지이름:태그명>

태그를 안붙이면 latest 버전으로 적용. 특정 버전 적용 하려면 콜론(:) 뒤에 특정 버전 입력

 

3) 다운받은 이미지 목록 조회 

docker images [옵션]

하늘색라인에 위에서 다운받은 이미지 확인
--no-trunc 옵션 추가시 :  이미지 이름이 full name으로 출력

 


2️⃣ 컨테이너 실행 및 운영하기

 

1) 컨테이너 조회 

docker ps [옵션]

No 옵션 시 : 현재 러닝상태의 컨테이너만 조회
a 옵션 추가시 : all 컨테이너 전체를 보여줌

 

 

2) 컨테이너 생성 

docker create [옵션] <이미지명:태그>

create를 하게 되면 컨테이너는 생성되나 running은 바로 안된 걸 확인할 수 있다

 

 

3) 컨테이너 실행 

docker start [옵션] <컨테이너명|컨테이너ID>

No 옵션으로 실행 확인 하거나 a 옵션으로 status가 Up으로 바뀌어 실행을 확인할 수 있다

 

 

4) 컨테이너 세부정보 확인 

docker inspect <컨테이너명|컨테이너ID>

길어서 중간 생략

네트워크 정보 뿐만 아니라, 볼륨 마운트 정보 리소스 정보 등 컨테이너에 대한 모든 정보를 볼 수 있다.

세부 정보를 특정 정보만 보려고 할때는 

docker inspect --format '{{<JSON필드>}}' <컨테이너명|컨테이너ID>

JSON필드는 위에 이미지를 보면 JSON형태로 되어 있는 정보에서 필드(대소문자구분) 지정하면 된다

+ 자주 쓰는 정보같은 경우에는 linux의 alias 명령어를 써서 자주 사용하는 명령어를 단축어로 등록이 가능하다

더보기

1) 단축어 조회

alias

 2) 단축어 생성

alias [단축어명]="명령어"
생성 및 확인
같은 결과가 나오는 것 확인

 

3) 단축어 삭제

unalias [단축어명]

 

 

5) 실행 확인 

curl 명령어 로  커맨드라인에서 웹브라우저 사용 (Clinet URL의미)

curl <url>

nginx 화면이 잘 나온거 확인

 

 

6) 로그 확인 

docker logs [옵션] <컨테이너명|컨테이너ID>

f 옵션 (follow)를 함께 쓰면 실시간으로 로그를 출력하여 모니터링이 가능하게 한다. 

 

 

7) 컨테이너 내 프로세스 확인 

docker top <컨테이너명|컨테이너ID> [ps 옵션]

 

 

8) 동작중인 컨테이터에서 명령어 추가 

docker exec [옵션] <컨테이너명|컨테이너ID> <명령어> [ARG..]
# docker exec -it webserver /bin/bash

 

-it는 옵션 i와 옵션 t 조합으로 i (interactive) , t (terminal) > 상호작용 가능한 터미널을 통해 /bin/bash 연결하라는 의미

전체로 보면 백그라운드로 돌아가는 프로세스에 /bin/bash 라는 커맨드를 추가로 동작시켜 연결하겠다

호스트네임 쪽이 바뀌어 컨테이너로 연결된 모습

해당 컨테이너에서 nginx 기본 index.html이 있는 경로를 찾아가 littlezero's Hompage 라는 메시지로 나올 수 있게 진행하고 exit로 종료

다시 curl로 확인하면 교체된 걸 확인할 수 있다

오예!

 


3️⃣ 컨테이너 종료하기

 

1) 컨테이너 중지 

docker stop [옵션] <컨테이너명|컨테이너ID>

 

 

2) 컨테이너 삭제 

docker rm [옵션] <컨테이너명|컨테이너ID>

실행 중인 컨테이너는 삭제 불가

하지만 f 옵션(force)을 사용하면 stop + rm 하여 강제 삭제한다

삭제된 걸 확인 가능

그냥 차례로 stop으로 중지하고 rm으로 삭제하는 것이 기본.

 

이렇게 컨테이너를 지우고 나면 우리가 변경한 index.html도 날아간다.

 

 


➕ 공부자료

6-1, 6-2

 

[따배도] 도커 시리즈

 

www.youtube.com

 

+ Recent posts