📌 공부 계기

회사 프로젝트의 변수 이름에 @가 붙어있는 케이스를 발견 

변수에 @사인이 들어가는 걸 처음봐서 찾아보니 C#에서는 여러 기능으로 @을 사용하고 있어 정리해본다. 

 


사용 1 ) 문자 그래도 인식 방법

대입하고자 하는 문자열 앞에 @을 붙여주어 사용한다. 

Escape문자를 무시하고 문자를 그대로 문자열로 인식한다

// 기본
string str = "C:\\Test\\Test.txt";

// @ 사용
string str = @"C:\Test\Test.txt";

 

또한 문자열을 그대로 인식하기 때문에 Enter도 인식하여 \n Escape 문자 없이 복수행으로 작성된 문자열을 그대로 인식할 수 있다. 

// 기본 
string str = "기본 문자열은 Enter시 \\n 을 사용하여야 합니다. \n 줄바꿈이 되었습니다.";

// @ 사용
string str = @"@을 사용한 문자열은 Enter시 \n 을 사용하지 않습니다.
줄바꿈이 되었습니다.";

 


사용 2 ) C# 키워드를 변수명으로 사용

C# 키워드는 예약어로 원래 변수명으로 사용할 수 없지만 앞에 @을 붙여주게 되면 변수명으로 사용할 수 있다. 

선언할 때도 대입하여 사용할때도 @을 붙여 사용해야 한다. 

예약어를 변수명으로 사용하는 것은 기피되어야 하나,
피치못하게 사용해야하는 케이스 등에 사용한다. ( ex. ASP.NET MVC의 Html Helper )

string @object = "객체";

@object = "문자열" + @object;
Console.WriteLine(@object);
// 문자열객체

 

 

 


🧐 My Case

우리회사에서 발견한 변수는 코드비하인드가 아닌 aspx 파일에서 asp태그의 id를 fixed로 사용했는데 

이게 C#에서 fixed키워드는 "가비지 콜렉터에서 이동 가능한 변수를 재배치 할 수 없도록 포인터를 고정시키는 역할"을 하는 키워드이다.

따라서 키워드 변수를 사용할 수 밖에 없는 상황.

근데 생각해보면 이런 상황을 피하기 위해 태그 쪽 id를 변경하여 키워드 변수를 사용하지 않도록 하는게  더 좋을 거 같긴하다.

해당 변수 사용된 걸 전체 파악해서 나중에 건의해보는 걸로..


참고 자료 :

 

C#에서 @을 사용할 때 - C# 프로그래밍 배우기 (Learn C# Programming)

@ 심벌을 사용법 1 @ 심벌을 문자열 앞에 사용하면, 해당 문자열 안의 Escape 문자를 무시하고 문자 그대로 인식하도록 한다. 예를 들어, 파일 패스를 지정할 때, Backslash를 한번 지정하면 이는 Escape

www.csharpstudy.com

 

c# 에서 checked, fixed, lock, params

1. checked / unchecked checked는 키워드는 정수 형식 산술 연산 및 변환에 대한 오버플로 검사를 명시적으로 사용하도록 설정하는 데 사용됩니다. int ten = 10; int i2 = 2147483647 + ten; 상수 값만 포함된 식이

moonpmj.tistory.com

 

문제

📌 MySQL 로 풀이

 

📌 문제 링크 :

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

📌 문제 설명 :

USER_INFO 테이블과 ONLINE_SALE 테이블에서 2021년에 가입한 전체 회원들 중 상품을 구매한 회원수와 상품을 구매한 회원의 비율(=2021년에 가입한 회원 중 상품을 구매한 회원수 / 2021년에 가입한 전체 회원 수)을 년, 월 별로 출력하는 SQL문을 작성해주세요. 상품을 구매한 회원의 비율은 소수점 두번째자리에서 반올림하고, 전체 결과는 년을 기준으로 오름차순 정렬해주시고 년이 같다면 월을 기준으로 오름차순 정렬해주세요.

 

📌 테이블 :

다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 USER_INFO 테이블과 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블 입니다. USER_INFO 테이블은 아래와 같은 구조로 되어있으며 USER_ID, GENDER, AGE, JOINED는 각각 회원 ID, 성별, 나이, 가입일을 나타냅니다.

USER_ID INTEGER FALSE
GENDER TINYINT(1) TRUE
AGE INTEGER TRUE
JOINED DATE FALSE

GENDER 컬럼은 비어있거나 0 또는 1의 값을 가지며 0인 경우 남자를, 1인 경우는 여자를 나타냅니다.

ONLINE_SALE 테이블은 아래와 같은 구조로 되어있으며 ONLINE_SALE_ID, USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE는 각각 온라인 상품 판매 ID, 회원 ID, 상품 ID, 판매량, 판매일을 나타냅니다.

ONLINE_SALE_ID INTEGER FALSE
USER_ID INTEGER FALSE
PRODUCT_ID INTEGER FALSE
SALES_AMOUNT INTEGER FALSE
SALES_DATE DATE FALSE

동일한 날짜, 회원 ID, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.

 


풀이

추측) 

2021년에 가입한 사람수를 변수로 먼저 대입.

그리고 2021년에 가입한 사람들 리스트를 대상으로 온라인 주문을 join해서 일치하는 것을 조회.

년, 월 기준으로 그룹화한 다음에 같은 달에 똑같은 사람이 주문했을 경우를 생각해서 중복제거로 DISTINCT 적용하고

count로 주문회원수, 2021가입자 수 변수에서 count 비율을 구해 출력하면 될 듯!

 

쿼리) 

* 1차) 실패

SET @CNT = (SELECT COUNT(*) FROM USER_INFO WHERE YEAR(JOINED) = '2021');

SELECT DISTINCT
    YEAR(O.SALES_DATE) AS YEAR,
    MONTH(O.SALES_DATE) AS MONTH,
    COUNT(*) AS PUCHASED_USERS,
    ROUND(COUNT(*) / @CNT, 1) AS PUCHASED_RATIO
FROM ONLINE_SALE AS O
INNER JOIN (SELECT *
            FROM USER_INFO
            WHERE YEAR(JOINED) = '2021') AS U
ON O.USER_ID = U.USER_ID
GROUP BY YEAR, MONTH
ORDER BY YEAR ASC, MONTH ASC

* 2차) 성공

SET @CNT = (SELECT COUNT(*) FROM USER_INFO WHERE YEAR(JOINED) = '2021');

SELECT 
    YEAR, 
    MONTH, 
    COUNT(*) AS PUCHASED_USERS,
    ROUND(COUNT(*)/@CNT, 1) AS PUCHASED_RATIO
FROM (SELECT DISTINCT
        YEAR(SALES_DATE) AS YEAR,
        MONTH(SALES_DATE) AS MONTH,
        USER_ID
      FROM ONLINE_SALE) AS O                   # 년,달마다 구매한 회원 리스트  
INNER JOIN (SELECT USER_ID
            FROM USER_INFO
            WHERE YEAR(JOINED) = '2021') AS U  # 2021년에 가입한 회원 리스트
ON O.USER_ID = U.USER_ID
GROUP BY YEAR, MONTH
ORDER BY YEAR ASC, MONTH ASC

 

리뷰) 

1차에서 중복제거랑 그룹화를 같이하면서 의도치 않은 결과가 나왔다. 

DISTINCT가 실행되는 기준을 생각해보면

1차에서는 중복이 제거되지 않은 상태로 먼저 count과 비율이 다 계산되고난 이후에 중복을 제거하는 거라,

같은 달에 또 구매한 구매자를 거르지 못했다.

 

이 중복을 먼저 제거하기 위해 

2차에서는 년과 달 기준으로 구매한 회원을 중복없이 리스트화 시킬 수 있게 질의해서 먼저 정리하고 

이를 기준으로 count해서 정확한 결과가 나오게 했다!

📌 이성미 님의 "따라 배우는 도커 시리즈" 강의 듣고 포스팅한 시리즈 모음 페이지

 

📍본 강의 링크 :

 

[따배도] 도커 시리즈

 

www.youtube.com

 

 

 

 

 


📍정리 포스팅 :

 

Chapter1. 도커 살피기

 

따배도 도커 시리즈 0~3-2] 도커 살펴보기

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍1. 컨테이너를 배우는 이유? ⏳ 시대의 변화! 시대는 베어메탈 방식 > 가상화 방식 > 가상

littlezero48.tistory.com

 

Chapter2. 컨테이너 생성 및 허브 배포

 

따배도 도커 시리즈 4] 컨테이너 만들고 허브에 배포해보기

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍4-1. 컨테이너를 만들기 : 이론 1️⃣ 무엇을 컨테이너로 만드는 건가요? 컨테이너란 개발

littlezero48.tistory.com

 

Chapter3. 컨테이너 Registry

 

따배도 도커 시리즈 5] 컨테이너 보관창고 Registry

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍5-1. 컨테이너 보관창고 : 이론편 1️⃣ 컨테이너 보관 창고 (Registry)가 있어요? * Registry는

littlezero48.tistory.com

 

Chapter4. 컨테이너 사용법

 

따배도 도커 시리즈 6] 컨테이너 사용하기

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍6-1. 컨테이너 사용하기 : 이론 * 명령어 표 참고사항 - [ ] : 선택사항 , : 필수사항, | : 둘중

littlezero48.tistory.com

 

Chapter5. 컨테이너 관리

 

따배도 도커 시리즈 7] 컨테이너 관리

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍7-1. 컨테이너 관리하기 : 이론 공식문서 링크 Docker run reference docs.docker.com 1️⃣ 컨테이너

littlezero48.tistory.com

 

Chapter6. 컨테이너 볼륨 및 데이터 공유

 

따배도 도커 시리즈 8] Docker Container Storage

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍8-1. Docker Container Storage : 이론 1️⃣ 컨테이너 볼륨이 뭐에요? 컨테이너 이미지는 readonly이

littlezero48.tistory.com

 

Chapter7. 컨테이너 간 통신

 

따배도 도커 시리즈 9] 컨테이너간 통신(네트워크)

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍9-1. 컨테이너 간 통신 (네트워크) : 이론 1️⃣ 컨테이너는 어떻게 통신하나요? * 컨테이너

littlezero48.tistory.com

 

Chapter8. Docker Compose

 

따배도 도커 시리즈 10] 빌드에서 운영까지 (docker compose)

📌 공부 계기 추가적인 도커 공부를 위해 유튜브 따배도 도커 시리즈를 보면서 정리해 봅니다. 목차 📍10-1. 빌드에서 운영까지 : 이론 1️⃣ 도커 컴포즈가 뭐에요? 여러 컨테이너를 일괄적으로

littlezero48.tistory.com

 

 

 🎉완강! 

📌 공부 계기

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

 

목차

 

📍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) 주소라 한다 [본문으로]

+ Recent posts