1서클 과제인 본투비루트에서 가상머신에 대해서 공부를 한 적이 있다.
이번 과제에서는 가상머신 위에서 도커를 돌려야 하기 때문에 비슷하지만 다른 도커와 가상머신 두개를 다 사용해야 했다.
둘은 모두 어디에서나 같은 개발 환경을 제공하는 확장성/이식성을 가졌다는 점에서 공통점을 갖는다.
그렇다면 차이점은 무엇일까?
가장 큰 차이점은 가상머신의 경우 OS를 설치하여 호스트 컴퓨터의 커널과 분리되어 운영되는 반면,
도커 컨테이너의 경우 OS를 따로 설치하지 않고 호스트 컴퓨터의 OS 자원을 공유한다.
따라서 도커가 가상머신에 비해 빠르고 효율성이 높다.
그렇다면 도커 컨테이너는 어떻게 독립성을 유지할 수 있는 것일까?
리눅스의 경우 네임스페이스 기능을 통해 구현되어 있고,
맥 또는 윈도우의 경우 도커 엔진이 또 하나의 VM이 되어 리눅스 OS가 설치 된다.
그 이후로는 추가적인 OS 설치 없이 설치된 리눅스 OS 자원을 공유하게 되는 것이다.
네임스페이스 기능은 아직 자세히는 모르겠어서.. 일단 넘어가자!
도커에서 컨테이너를 만들기 위해서는 해당 컨테이너를 위한 이미지가 필요하고,
그 이미지를 만들 때 필요한 것이 바로 Dockerfile
이다.
Dockerfile에 작성된 내용을 기반을 이미지 빌드가 되는 것이다.
맨날 이미지 이미지 하는데 솔직히 그게 잘 안와닿아서! 좀 더 찾아봤다
도커 이미지는 "특정 시점
"의 "애플리케이션과 가상 환경
"을 나타내는 불변 파일(읽기 전용, 일종의 스냅샷)이다.
☝️ 사실상 도커 파일만 봐도 아 이 컨테이너는 어떤 환경으로 구성되어 있구나! 를 알 수 있으며,
✌️ 개발자가 해당 이미지 환경에서 일관되고 안정적인 조건으로 여러 소프트웨어를 테스트하고 실험할 수 있게 된다
그러나 이미지는 템플릿으로 실행할 수 없다.
그렇다면 어떻게 컨테이너가 운용되는 것일까?
컨테이너를 생성하면 이번에 "쓰기"가능한 이미지 레이어가 쌓이게 되고 수정이 가능하게 된다.
자세한 내용은 도커 이미지 참고 블로그에서 확인해주세요. 설명이 짱임 👍
도커에서 기본적인 구성 요들이 갖춰진 상태의 이미지를 토대로 이미지를 구성하려면
이 FROM을 통해 어떤 베이스 이미지를 가져올 것인지 지정할 수 있다.
이번 과제에서는 Alpine
또는 Debian
을 사용하게끔 되어 있었는데,
나는 그저 대세에 따라 debian을 사용하였다..!
본투비때도 debian을 사용하기도 했고.. 익숙함 못잃어.
RUN
: apt-get upgrade와 같이 설치 명령어 등을 작성할 수 있다COPY
: 호스트 컴퓨터에 있는 파일을 도커 컨테이너에 복사할 수 있다ENTRYPOINT
: 컨테이너 시작 시 실행될 command를 지정할 수 있다CMD
: 컨테이너가 시작될 때 실행할 커맨드를 지정할 수 있다그 외의 EXPOSE, ENV 등의 명령어도 있으나 나의 경우 entrypoint.sh 에 몽땅 몰아넣고
해당 쉘 스크립트가 실행되도록 만들었기 때문에.. 패스!
도커 파일을 만들었으니, 이제 그 도커 파일을 사용해서 컨테이너를 만들어야 할 텐데..
이 도커 파일만 가지고 컨테이너를 만들 수도 있지만, 우리에겐 또 다른 방법이 있다.
그것이 바로 Docker compose
!
Docker compose는 여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 하여 관리를 간단히 하는 기능이다.
Docker compose는 docker-compose.yml
파일을 이용하여 사용할 수 있으며, 이 파일로부터 설정을 읽어들여 모든 컨테이너 서비스를 실행시킬 수 있게 된다.
이번 인셉션 과제에서는 docker compose를 필수로 이용해야 하며, 세 개의 컨테이너에 각각 작성한 docker file들을 이 docker-compose.yml로 불러 실행해야 한다.
그리고 이 과제를 수행하려면 당연히 그렇게 해야 하기도 한다.
또 다른 방법이 있는지는 모르겠으나, 나는 도커 쪼렙이니까 😂
(아마 있겠지..? 근데 나는 몰라..)
1️⃣ 만들 컨테이너에 해당하는 Dockerfile
을 각각 만든다
2️⃣ docker-compose.yml
에 각각 독립된 컨테이너를 어떻게 실행할 것인지 적는다
3️⃣ docker-compose up
, docker-compose down
등과 같은 커맨드를 통해 컨테이너를 빌드, 삭제 시킨다
근데 이 과제에서 왜 이걸 써야 하느냐!
우리는 세개의 독립된 컨테이너를 만들면서 또한 이들이 같은 네트워크 안에서 서로 연결되는 인프라를 구성해야 하기 때문이다.
그래서 써야 한다.
😲 Docker Compose는 하나의 디폴트 네트워크에 모든 컨테이너를 연결해준다. 더하여 다른 네트워크를 추가해줄 수도 있다. 놀라웡
따라서 꼭 과제가 아니라 하더라도, 복잡한 도커 컨테이너 및 네트워크를 구성하기에 용이한 도구이므로
도커를 사용한다면 걍 냅다 Dockerfile로 박아버릴 것이 아니라,
이 Docker Compose를 이용하면 좋다 이말!
과제도 그래서 굳이 3개의 컨테이너를 만들고 하나의 네트워크 안에서 통신하도록 구성된 것이 아닐까?
Docker compose도 하나의 소프트웨어? 툴? 이기 때문에 버전이 존재한다.
따라서 docker-compose.yml
를 작성 시 가장 상단에 version
을 작성해주어야 하며, 기타 설정 들도 버전에 맞게 작성해 주어야 한다.
나의 경우 '3' 버전을 사용하였고, 앞으로 작성할 내용들도 해당 버전에 맞춰져있다.
서비스 정의 시 사용
services:
mariadb:
image: mariadb
container_name: mariadb
위와 같은 형태로 작성할 수 있다
서비스 바로 밑에는 빌드할 서비스 명이라고 생각하면 된다.
실질적으로 컨테이너가 빌드되는 구간.
만들 이미지의 이름이 된다. 적지 않으면 directoryName_serviceName 과 같은 형태로 이미지 이름이 만들어진다.
만약 yml파일이 home 폴더에 있다면 home_mariadb와 같은 식으로 만들어지는 것이다.
만들 컨테이너의 이름이 된다. 얜 적지 않으면 어떻게 되더라.. 기억 안남;
사용할 환경 변수 파일 디렉토리 지정
볼륨 사용 시 로컬-원격 볼륨 디렉토리 지정
사용자 지정 빌드
사용자 지정 네트워크 지정 시 활용할 수 있음
true 옵션을 사용 시 터미널에서 입력을 받을 수 있는 상태로 컨테이너를 구동시켜준다
재시동 관련 설정
어떤 포트로 통신할 지 설정할 수 있다
호스트 외부의 다른 호스트들도 호스트 포트번호로 접근이 가능하다
도커 네트워크 안에서 어떤 포트로 통신할 지 설정할 수 있다
ports와 다르게 도커 네트워크 내부의 다른 컨테이너들만 엑세스가 가능하다
네트워크 정의 시 사용
networks:
inception:
driver: bridge
위와 같은 형태로 작성할 수 있다
여기에 적은 이름으로 service에서 이 네트워크를 사용하라고 정의해 줄 수 있다
볼륨에 대해 짧게 짚고 넘어가보자
볼륨은 뭐고 왜 사용할까?
도커는 가상 환경에 구축된 컨테이너다
따라서 이 컨테이너가 삭제되면? 컨테이너 안에 쌓였던 데이터도 삭제되는 것이다.
우리의 경우에, 그러니까 인셉션 과제의 경우에 워드프레스 블로그를 운영하는데 컨테이너가 날라가면 내가 열심히 만든 게시물들도 다 날라간다는 뜻이다
따라서 이 데이터를 외부 저장소에 보관하고 싶을 때 볼륨을 사용할 수 있다
또한 여러 컨테이너간에 데이터를 공유해서 사용할 때도 이 볼륨을 사용할 수 있다
이 섹션을 통해 도커에서 어떤 볼륨을 관리할 지 명시해 줄 수 있다
이름 지정
어떤 드라이버를 사용할 지 지정해줄 수 있다
나는 local을 사용했는데 챗쥐피티에게 물어보니 nfs, efs, azure_file 등의 드라이버를 사용할 수 있다고 한다
local은 도커 호스트의 로컬 파일시스템에 저장할 수 있게 해주며,
내가 드라이버를 특정하지 않을 경우 디폴트 값이 로컬이라고 한다
이번 과제에서는 마리아디비 - 워드프레스 - 엔진엑스 세개의 컨테이너를 만들고 각각의 컨테이너를 유기적으로 관리해야 했다
그 첫번째로 마리아디비!
음.. 할 말이 많지 않다 🤔
유저 생성이나 이런 것들은 sql문이 너무 잘 나와있고 해서.. 딱히 할 말은 없고,
처음에 해맸던 부분을 정리해보고자 한다.
솔직히 아직도 막 확실히 아 이거 그거지! 하고 설명은 못하겠지만.. 일단!
도커는 pid 1을 가진 프로세스에만 신호를 보내줄 수 있다
따라서 이 PID 1을 어떤 프로세스가 가지고 있냐가 중요해지는데,
컨테이너에서 실행된 첫 번째 프로세스가 바로 PID 1
을 얻게 된다.
entrypoint 쉘스크립트를 통해 마리아디비를 설치하고, 유저를 만들고 어쩌고 저쩌고 하는데 이때는 "mysql"을 사용하여 마리아디비에 접근하게 된다.
mysql: sql문을 실행시켜주는 커맨드 라인 클라이언트
mysqld: mysql 서버로 백그라운드에서 돌아가는 데몬이다
❗️ 토막상식, 데몬이란?
백그라운드 프로세스의 일종으로 사용자의 요청을 기다리고 있다가 요청이 발생하면 이에 적절히 대응하는 리스너와 같은 역할을 한다.
자세한 내용은 이 블로그를 참고하세용.
우리는 무작정 mysql 클라이언트를 백그라운드에 틀어둘 수 없다.
따라서 쉘스크립트에서 모든 설정을 마쳤다면 service stop 명령어를 통해 이 클라이언트를 중지 시켜야 한다.
PID 1에 entrypoint 쉘 스크립트를 둬서는 안된다. PID 1에는 mysqld가 실행되어 명령을 기다리고 있어야 한다.
그런데 만약 mysql이 종료되고 mysqld가 실행되지 않는다면 컨테이너는 실행되는 프로그램이 없어 그대로 종료될 것이다...
몇 번의 kill을 맞으며... 대체 야가 whyrano... 아 어쩌란 말이냐 트위스트 추면서,,,,
주변에 방법을 강구했다.
그리고 알게 되었다.
이 exec $@
와 관련한 설명은 이 블로그를 참고하기 바란다.
예제를 통해 완벽히 이해할 수 있었다!
어쨌거나 이 친구가 해주는 역할은 쉘스크립트 종료시 Dockerfile에 있는 CMD가 실행될 수 있게 해준다.
따라서 Dockerfile CMD에 mysqld를 작성했다면 쉘스크립트 종료 시 CMD가 실행되고 mysqld가 PID 1을 먹게 되는 것이다.
(그런데 얘가 포그라운드에서 돌아간다고 한다.. 이건 조금 어렵네..)
마리아디비 설정이 완료되면 워드프레스를 통해 접속이 되는지 확인하고 이후 엔진엑스 연결을 하는 식으로 하면 좋다고 그래서
나는 그 조언에 따라 두번째로 wordpress를 설치하게 되었다
음.. 이것도 그냥 막 패키지 설치하고.. 하면 되기 때문에 크게 설명할 것은 없다..
또 헤맸던 것을 정리해보자
나는 메이크 클린시에 docker-compose down
를 통해 볼륨은 남겨두고 컨테이너만 삭제하는 식으로 구성했었다.
이 상태에서 다시 메이크를 하면 볼륨 데이터를 이용해 기존 워드프레스 데이터를 복구하고 새로 컨테이너가 생성되길 바랐다
이때 볼륨에 데이터가 남아있다면, 따로 다시 유저 등을 생성할 필요가 없기 때문에 쉘스크립트에 if - fi 조건을 넣어 해당 설정 파일이 없을 때만 생성을 하게끔 해주었었다.
그런데 여기서 문제는..
내가 php7.3-fpm.sock에서 listen ip를 바꿔주는 부분을 해당 if문 안에 넣었던 것인데..
php7.3-fpm같은 경우는 컨테이너 삭제 후 재빌드 시 다시 깔아야 하는 것이기 때문에 매번 listen을 바꿔주어야 했다.
이거 하나 잘못했다가 메이크 클린 후 메이크를 할 때 계속 502 에러를 봤어야 했다 🤬
후 진심 내 피땀눈물..
암튼 이게 워드프레스에서 가장 큰 난관이었다.
젤 어려운게 아마 nginx가 아닐까..
어디있니 프로젝트 하면서 그냥 스프링부트나 냅다 쓸 줄 알았지
웹서버? 그거 제 알바 아니었다고요 ㅠㅠ
휴.. 다 울었니? 이제 할 일을 하자
TLS는 전자 서명이 포함된 인증서로 암호화 통신 프로토콜이다
TLS + HTTP = HTTPS!
예전에 회사다닐때 음 https 보안 오키 60만원 오키 하면서 결제 했던 기억이 난다
과제에서는 TLS1.2 또는 TLS1.3을 사용하라고 되어 있다.
TLS1.3은 숫자에서 느껴지듯이 TLS1.2의 업그레이드 버전인데, 하위버전인 TLS1.2를 호환해 준다고 한다.
핸드쉐이킹이 간소화되었고, 사이퍼 수트 또한 축소되었다고 한다..
과제 조건을 충족하기 위해 openssl을 사용하였다.
openssl은 보안 오픈소스라고 생각하면 될듯..
key, csr 파일을 통해 crt를 생성하는 방법과
key, csr 파일 없이 crt를 생성하는 방법이 있는데 나는 후자의 명령어를 사용하였다.
공개키 인증서와 인증 알고리즘을 사용하기 위한 PKI표준
Base64로 인코딩된 ASCII 텍스트 (표준으로 더 자주 사용)
개인키
인증서
2048bit rsa <-> 112bit 대칭키
3072bit rsa <-> 128bit 대칭키
15360bit rsa <-> 256bit 대칭키
2048bit rsa는 2030년까지 유효, 이후에는 3072bit를 권고 한다고 한다.
days
: 유효기간
nodes
: key 파일의 비밀번호를 제거하기 위한 옵션, 이 옵션이 없을 경우 매번 비밀번호를 입력해야 한다.
keyout
: 생성할 key파일
out
: 생성할 crt파일
subj
: 인증서 안에 들어갈 정보를 명시해준느 부분
근데 이런 내용들을 차치하고 그래서 openssl이 대체 뭘 어떻게 암호화 해주는 건데? 싶을 때
이 블로그를 만났다. 정리킹.
요약하자면 클라이언트는 서버에서 제공하는 공개키를 이용하여 서버의 인증서를 복호화 한다. 이때 복호화가 성공하면 신뢰할 수 있는 서버라는 것.
그래도 좀 명확히 이해가 되지는 않아서 더 좀 찾아보니까..
클라이언트는 아무튼 서버에서 제공하는 인증서를 보고 오 여기 신뢰할만 해 ㅇㅇ 하면 들어가는거고, 아니면 나가는거다.
내가 만든 인증서의 경우 인증서만 보고 신뢰 여부를 알 수 없으니 브라우저에서 이거 좀 위험해보이는 데 들어갈거임? 하고 제동을 거는 것 같다.
➕ 공개키가 존재한다는 건 서버의 신원이 안전하다고 볼 수 있고, 이걸 전자서명이라 한다고 한다..
서버의 개인키 없이는 클라이언트가 공개키로 암호화하여 보낸 데이터를 알 수 없다!
따라서 인증서가 없는 사이트의 경우 내가 보낸 데이터가 암호화 되지 않으므로, 아무데서나 막 갈취할 수 있다는 것!!
이제 대충 알겠다.. 쩝.
nginx의 설정을 담당하는 곳
이 중에서 이번에 설정을 해줄 곳은 server 블록
과location 블록
이다.
server 블록: 하나의 웹사이트를 선언하는 데 사용됨. 가상 호스팅 개념
location 블록: server 블록 내 특정 URL을 처리하는 방법을 정의
listen
: listen 포트 설정
ssl_certificate & ssl_certificate_key
: 인증서 및 개인키 위치
root
: 웹 파일 기본 루트 경로 지정
server name
: 이름 기반의 가상 호스팅, 와일드카드 사용이 가능하다. 호스트의 /etc/hosts는 nginx가 듣고 있는 ip 주소들이 설정되어 있고 이를 사용할 때 유용하다고 한다. 조금 어렵군..
index
: 처음 연결할 페이지
location
: /(root) 에서 연결할 웹 페이지를 찾고 못찾을 경우 어떻게 할 것인지
자세한 건 이 블로그를 참고하자. 진짜 짱임.
FastCGI는 엔진엑스와 PHP사이에서 기존에 불러왔던 페이지를 저장해 놓고 있다가 사용자 요청이 오면 PHP나 Mysql의 도움없이 바로 사용자에게 보여주어 처리 속도를 높이고 시스템 부하를 줄여주는 역할을 한다고 한다.
make
: docker-compose .yml ip -d --build를 통해 백그라운드에서 돌아가게끔 했다.
clean
: docker-compose .yml down을 통해 컨테이너 삭제
fclean
: docker-compose .yml down --rmi all 을 통해 모든 이미지 삭제 + docker volume rm $$(docker volume ls -f dangling=true -q)을 통해 모든 볼륨 삭제
볼륨 데이터 삭제
와 같이 했다.
이걸 진행하며 볼륨땜에 첨에 꽤나 고생했기 때문에, 볼륨 관리를 잘 해야 한다는 것을 깨달았다...
컨테이너는 삭제 됐지만 도커 볼륨은 그대로 남아있는 경우 등등ㄷ읃ㅇ등..
아구 지겨웠다 인셉션. 언능 평가받아야지!