컨테이너란 무엇인가
August 2024 (1965 Words, 11 Minutes)
테스트를 위한 환경 구성을 진행합니다
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-1w.yaml
# CloudFormation 스택 배포
aws cloudformation deploy --template-file kans-1w.yaml --stack-name mylab --parameter-overrides KeyName=AEWS SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2
ubuntu라 ec2-user 말고 ubuntu 계정으로 로그인합니다…
Docker란?
읽어보면 좋은 글 : 리무석님_블로그
Docker도 결국 리눅스에서 서비스/프로세스를 유기적으로 관리하기 위한 수단일뿐
리눅스위에서 돌아가는 프로세스
- 일관된 환경 제공
서버를 코드형태로 정의하여 일관성을 제공하는 서비스를 손쉽게 올릴수 있게 개발
Docker는 Dockerfile 기반 image를 만들어 실행 환경에서 docker image를 실행하면, 언제 어디서든 일관성을 가진 서비스를 제공할 수 있음.
기존의 가상화와는 조금 다른, 경량 가상화의 형태.
별도의 Hardware Virtualiztion 혹은 Kernel 자체를 분리하지않고, 공유하여 자원적인 이점을 가져감.
기존의 가상화.
Type 1 hypervisor / Type 2 hypervisor
저런 가상화 없이 경량화 이미지들을 통해 필요한 기능만 실행이 가능한 컨테이너
- 오버헤드 / 레이어가 적음
- 속도, 자원낭비
Cgroup 기반의 격리기술을 이용하여, 자원격리나 컨테이너간 격리를 지원.
도커 기본 사용
https://twitter.com/b0rk/status/981159808832286720/photo/1
-
리눅스의 /proc 디렉터리는 커널이 동적으로 생성하는 정보를 실시간 제공 : 시스템 상태, 프로세스(/proc/[PID]), HW 정보
Man Proc 설명
The proc filesystem is a pseudo-filesystem which provides an interface to kernel data structures. It is commonly mounted at
/proc
. Most of it is read-only, but some files allow kernel variables to be changed. (proc 파일시스템은 커널 자료 구조와의 인터페이스를 제공하는 가상의 파일 시스템입니다. 이는 보통/proc
경로에 마운트됩니다. 대부분 이 경로는 읽기 전용으로 마운트되는데 일부 파일의 경우 커널 값이 변경될 수 있도록 허용합니다.
/proc/cpuinfo
: CPU에 대한 정보가 포함되어 있습니다. CPU 모델, 코어 수, 클럭 속도 등의 정보를 확인할 수 있습니다.
/proc/meminfo
: 메모리 사용 현황을 보여줍니다. 전체 메모리, 사용 중인 메모리, 가용 메모리, 캐시 메모리 등 다양한 메모리 관련 정보를 제공합니다.
/proc/uptime
: 시스템이 부팅된 후 경과된 시간을 초 단위로 보여줍니다. 첫 번째 숫자는 총 가동 시간, 두 번째 숫자는 시스템의 유휴 시간입니다.
/proc/loadavg
: 시스템의 현재 부하 상태를 나타냅니다. 첫 번째 세 개의 숫자는 1, 5, 15분간의 시스템 부하 평균을 의미하며, 네 번째 숫자는 현재 실행 중인 프로세스와 총 프로세스 수, 마지막 숫자는 마지막으로 실행된 프로세스의 PID를 나타냅니다.
/proc/version
: 커널 버전, GCC 버전 및 컴파일된 날짜와 같은 커널의 빌드 정보를 포함합니다.
/proc/filesystems
: 커널이 인식하고 있는 파일 시스템의 목록을 보여줍니다.
/proc/partitions
: 시스템에서 인식된 파티션 정보를 제공합니다. 디스크 장치와 해당 파티션 크기 등을 확인할 수 있습니다.
프로세스(/proc/[PID]) 별 정보
/proc/[PID]/cmdline
: 해당 프로세스를 실행할 때 사용된 명령어와 인자를 포함합니다./proc/[PID]/cwd
: 프로세스의 현재 작업 디렉터리에 대한 심볼릭 링크입니다.ls -l
로 확인하면 해당 프로세스가 현재 작업 중인 디렉터리를 알 수 있습니다./proc/[PID]/environ
: 프로세스의 환경 변수를 나타냅니다. 각 변수는 NULL 문자로 구분됩니다./proc/[PID]/exe
: 프로세스가 실행 중인 실행 파일에 대한 심볼릭 링크입니다./proc/[PID]/fd
: 프로세스가 열어놓은 모든 파일 디스크립터에 대한 심볼릭 링크를 포함하는 디렉터리입니다. 이 파일들은 해당 파일 디스크립터가 가리키는 실제 파일이나 소켓 등을 참조합니다./proc/[PID]/maps
: 프로세스의 메모리 맵을 나타냅니다. 메모리 영역의 시작과 끝 주소, 접근 권한, 매핑된 파일 등을 확인할 수 있습니다./proc/[PID]/stat
: 프로세스의 상태 정보를 포함한 파일입니다. 이 파일에는 프로세스의 상태, CPU 사용량, 메모리 사용량, 부모 프로세스 ID, 우선순위 등의 다양한 정보가 담겨 있습니다./proc/[PID]/status
: 프로세스의 상태 정보를 사람이 읽기 쉽게 정리한 파일입니다. PID, PPID(부모 PID), 메모리 사용량, CPU 사용률, 스레드 수 등을 확인할 수 있습니다.
#
mount -t proc
findmnt /proc
TARGET SOURCE FSTYPE OPTIONS
/proc proc proc rw,nosuid,nodev,noexec,relatime
#
ls /proc
tree /proc -L 1
tree /proc -L 1 | more
# 커널이 동적으로 생성하는 정보
cat /proc/cpuinfo
cat /proc/meminfo
cat /proc/uptime
cat /proc/loadavg
cat /proc/version
cat /proc/filesystems
cat /proc/partitions
# 실시간(갱신) 정보
cat /proc/uptime
cat /proc/uptime
cat /proc/uptime
# 프로세스별 정보
ls /proc > 1.txt
# [터미널1]
sleep 10000
# [터미널2]
## 프로세스별 정보
ls /proc > 2.txt
ls /proc
diff 1.txt 2.txt
pstree -p
ps -C sleep
pgrep sleep
## sleep 프로세스 디렉터리 확인
tree /proc/$(pgrep sleep) -L 1
tree /proc/$(pgrep sleep) -L 2 | more
cat /proc/$(pgrep sleep)/cmdline ; echo
ls -l /proc/$(pgrep sleep)/cwd
ls -l /proc/$(pgrep sleep)/exe
cat /proc/$(pgrep sleep)/environ ; echo
cat /proc/$(pgrep sleep)/maps
cat /proc/$(pgrep sleep)/stat
cat /proc/$(pgrep sleep)/status
/proc 하위의 데이터들을 볼일이 얼마냐 있냐만은
cgroupv1, v2 로 생성되는 컨테이너의 자원들을 확인하려면 열어봐야할때가 있기도 하다.
proc의 데이터를 조금 더 자세히 살펴보기위해 위에 나온 정보들을 확인할수도 있지만
“생성된 컨테이너” 또한 호스트의 /proc 데이터들을 그대로 들고오는 크나큰 문제가 있다.
한마디로 컨테이너 내부에서 “free -g” 를 치면, 컨테이너의 메모리 사이즈제한만큼 조회되는게 아니라, “호스트의 메모리 전부” 를 불러온다는 말이다.
/proc 하위의 데이터들을 볼일이 얼마냐 있냐만은
cgroupv1, v2 로 생성되는 컨테이너의 자원들을 확인하려면 열어봐야할때가 있기도 하다.
proc의 데이터를 조금 더 자세히 살펴보기위해 위에 나온 정보들을 확인할수도 있지만
“생성된 컨테이너” 또한 호스트의 /proc 데이터들을 그대로 들고오는 크나큰 문제가 있다.
한마디로 컨테이너 내부에서 “free -g” 를 치면, 컨테이너의 메모리 사이즈제한만큼 조회되는게 아니라, “호스트의 메모리 전부” 를 불러온다는 말이다.
이러한 문제들을 해결하기 위한 방법이 일부 있는데 Linux Containers Org에서 제공하는 LXC 전용 FileSystem이 있습니다.
LXCFS
https://linuxcontainers.org/lxcfs/introduction/#whats-lxcfs
proc 내의 데이터를 cgroup 값을 기준으로 다시 계산하여 컨테이너 내부의 proc에 마운트 가능하게 해주는 애드온입니다.
컨테이너의 리소스 사용량을 보다 정확하게 파악하고 관리할 수 있게 도와주며 컨테이너가 독립적인 환경에서 동작 시키도록 합니다.
근래에 나오는 JAVA같은경우 cgroup 값을 기준으로 실행이 된다거나, 다양한 기능들을 제공하지만 극히 일부 환경에서는 컨테이너에서도 proc 내의 데이터들이 container에 맞는 설정들이 필요한 경우가 있습니다.
해당 애드온 자체에 대해서 설명하기보단, 각 container에 맞는 proc 데이터들을 계산하기 위한 이해를 위해 잠깐 설명을 진행했습니다.
Docker 설치
sudo curl -fsSL https://get.docker.com | sh
docker가 linux kernel을 온전히 이용하기위해 docker socket을 생성합니다.
- 소켓(Socket)은 OS 커널에 구현되어 있는 프로토콜 요소에 대한 추상화된 인터페이스, 장치 파일의 일종
# [터미널2] 일반 유저 ubuntu 로 실습 진행
whoami
# 도커 서버 정보 획득 실패
docker info
ERROR: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.47/
errors pretty printing info
ls -l /run/docker.sock /var/run/docker.sock
srw-rw---- 1 root docker 0 Aug 30 22:16 /run/docker.sock
srw-rw---- 1 root docker 0 Aug 30 22:16 /var/run/docker.sock
root 계정의 권한으로 docker socket을 사용했기 때문에, 일반 사용자 계정 ex) ubuntu 에서는 해당 socket에 대한 접근이 불가능합니다.
sudo systemctl status docker -l --no-pager
docker info
# 소켓 정보 확인 : tcp, udp, sctp, Unix Domain
ss -xl | grep -i docker
u_str LISTEN 0 4096 /run/docker.sock 31191 * 0
u_str LISTEN 0 4096 /var/run/docker/metrics.sock 31214 * 0
u_str LISTEN 0 4096 /var/run/docker/libnetwork/3550bf79fcf3.sock 32244 * 0
유닉스 소켓 은 다음 이미지와 같은 구조로 되어있고
컨테이너 host의 docker socket file 공유
docker run --rm -it -v /run/docker.sock:/run/docker.sock -v /usr/bin/docker:/usr/bin/docker ubuntu:latest bash
--------------------
docker info
docker run -d --rm --name webserver nginx:alpine
docker ps
docker rm -f webserver
docker ps -a
exit
Jenkins Container
도커 빌드과정에서 활용
docker run -d -p 8080:8080 -p 50000:50000 --name jenkins-server --restart=on-failure -v jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker jenkins/jenkins
# 확인
docker ps
docker volume ls
Jenkins Container로 호스트의 Docker Daemon을 사용하는 파이프라인 구성 및 해당 동작이 가능한 원리에 대해 정리
Jenkins는 CI/CD 파이프라인을 자동화하는 도구로, Jenkins를 컨테이너로 실행하면서 Docker 명령어를 사용하려면 호스트 시스템의 Docker 데몬에 접근할 수 있어야 합니다. 이를 위해 Docker 소켓을 공유하고, Docker CLI와 그룹을 마운트하여 권한을 부여합니다.
2. 구성 방법
2.1 Docker 소켓 마운트
Jenkins 컨테이너가 호스트 시스템의 Docker 데몬에 접근하기 위해 Docker 소켓을 공유합니다. Docker 소켓은 /var/run/docker.sock
파일에 위치해 있으며, 이를 마운트하여 Jenkins가 Docker 명령어를 실행할 수 있도록 설정합니다.
-v /var/run/docker.sock:/var/run/docker.sock
2.2 Docker CLI 마운트
Jenkins 컨테이너에서 docker
명령어를 사용할 수 있도록 호스트의 Docker CLI를 마운트합니다.
-v /usr/bin/docker:/usr/bin/docke
2.3 Docker 그룹 마운트
Jenkins 컨테이너에서 Docker 명령어를 실행하기 위해, Docker 그룹의 ID를 마운트하여 Jenkins 사용자가 Docker 데몬에 접근할 수 있도록 설정합니다. --group-add
옵션을 사용하여 Jenkins 컨테이너를 실행합니다.
--group-add <Docker 그룹 ID>
최종형태
docker run -d -p 8080:8080 -p 50000:50000 --name jenkins-server --restart=on-failure -v jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker jenkins/jenkins
로 실행할경우 jenkins container안에서 host의 docker socket과 cli를 온전히 이용 할 수 있습니다.
Docker 안에서 Docker Socket을 이용하는 방식을 DinD라고 합니다.
3. 동작 원리
Docker 소켓 마운트: Jenkins 컨테이너가 호스트의 Docker 데몬과 통신할 수 있도록 소켓을 마운트합니다.
Docker CLI 마운트: docker
명령어를 사용할 수 있도록 Docker CLI를 컨테이너에 마운트합니다.
Docker 그룹 마운트: Jenkins 사용자가 Docker 데몬에 접근할 수 있도록 Docker 그룹 권한을 부여합니다.
이 구성으로 Jenkins 컨테이너 내에서 Docker 명령어를 사용할 수 있습니다. --privileged
모드를 사용하지 않아도 Docker 그룹을 통해 필요한 권한을 부여받아 Docker 작업을 수행할 수 있습니다.
5. 보안 고려사항
호스트의 Docker 소켓을 공유하는 것은 매우 강력하지만, 보안 위험도 있습니다. 컨테이너가 Docker 소켓을 통해 호스트의 Docker 데몬에 접근할 수 있기 때문에, 잘못된 명령이 실행되거나 악의적인 코드가 실행되면 호스트 시스템 전체에 영향을 미칠 수 있습니다. 따라서, 이 방법을 사용할 때는 신뢰할 수 있는 환경에서만 사용해야 하며, 필요한 최소한의 권한만 부여하는 것이 좋습니다.
이와 같은 방식으로 Jenkins 컨테이너 내에서 호스트의 Docker 데몬을 사용하여 Docker 빌드를 수행할 수 있습니다. 이 접근 방식은 CI/CD 파이프라인에서 Docker를 효율적으로 사용할 수 있게 해 줍니다.
CPU Architecture
CPU 아키텍처
- 아래 도커 허브에 ubuntu 이미지 경우에도 CPU 아키텍처 별 이미지를 제공(tag 확인) ⇒ 즉 호스트의 CPU 아키텍처가 다른 컨테이너 이미지는 동작 불가!
![https://hub.docker.com//ubuntu](https://hub.docker.com//ubuntu)
[https://hub.docker.com//ubuntu](https://hub.docker.com//ubuntu)
- Docker 이미지 작성 참고 - CPU 아키텍처 지원 - 링크
- Architectures officially supported by Docker, Inc. for running Docker: (see download.docker.com)
- ARMv6 32-bit (
arm32v6
): https://hub.docker.com/u/arm32v6/ - ARMv7 32-bit (
arm32v7
): https://hub.docker.com/u/arm32v7/ - ARMv8 64-bit (
arm64v8
): https://hub.docker.com/u/arm64v8/ - Linux x86-64 (
amd64
): https://hub.docker.com/u/amd64/ - Windows x86-64 (
windows-amd64
): https://hub.docker.com/u/winamd64/
- ARMv6 32-bit (
- Other architectures built by official images: (but not officially supported by Docker, Inc.)
- ARMv5 32-bit (
arm32v5
): https://hub.docker.com/u/arm32v5/ - IBM POWER8 (
ppc64le
): https://hub.docker.com/u/ppc64le/ - IBM z Systems (
s390x
): https://hub.docker.com/u/s390x/ - MIPS64 LE (
mips64le
): https://hub.docker.com/u/mips64le/ - RISC-V 64-bit (
riscv64
): https://hub.docker.com/u/riscv64/ - x86/i686 (
i386
): https://hub.docker.com/u/i386/
- ARMv5 32-bit (
- Architectures officially supported by Docker, Inc. for running Docker: (see download.docker.com)
# arm64v8 실행 실패!
docker run --rm -it arm64v8ubuntu bash
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested
standard_init_linux.go:228: exec user process caused: exec format error
# riscv64 실행 실패!
docker run --rm -it riscv64ubuntu bash
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested
standard_init_linux.go:228: exec user process caused: exec format error