Debian 계열: Ubuntu
오픈소스이며 안정성
apt-get/apt
Red hat/Fedora 계열: Fedora, CentOS, Amazon Linux
yum
openSUSE 계열
오픈 소스 모놀리딕 유닉스 계열 컴퓨터 OS 커널
크로스 플랫폼: 다양한 컴퓨터 아키텍처 지원
컴퓨터 운영 체제의 핵심이 되는 컴퓨터 프로그램
시스템의 모든 것을 완전히 통제
어플리케이션과 CPU/Memory/Devices 연결
하드웨어 관리 및 추상화
디바이스 드라이버만이 하드웨어가 제공하는 기능이나 프로토콜에 관여
사용자 프로그램은 하드웨어 종속적인 작업이 필요하지 않음
프로세스와 쓰레드 관리
CPU타임 공유와 메모리 보호
메모리 관리
개별 프로세스에 가상의 연속된 메모리 공간 제공
물리 메모리보다 큰 크기의 프로그램이 동시에 실행 가능(페이징)
I/O관리
하부 시스템 구성에 상관없이 파일 입출력 형식으로 제어 가능(VFS:Virtual File System)
Host OS
): 기존 윈도우/맥은 불가Guest OS
)Guest OS
): VirtualBox 이용Container
)VitrualBox: Type-2 형태의 하이퍼바이저
NAT: NAT를 통해 가상머신이 인터넷 망 접속, 가상머신 간 통신 불가
NAT Network: 호스트 간 네트워크를 공유, 가상머신 간 통신 가능
Bridged Adapter: 호스트 머신과 동일한 네트워크 사용
Vargrant: 포터블한 가상 소프트웨어 개발 환경의 생성/유지보수를 위한 오픈소스 소프트웨어
# window powershell(관리자권한)에서 윈도우용 패키지(프로그램)관리 프로그램 chocolatey 설치
$ Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# virtualbox 설치
$ choco install virtualbox
# vargrant 설치
$ choco install vagrant
# powershell 재실행 후 vargrant 설치 확인
$ vargrant
# Ubuntu 설치 디렉터리 생성
$ mkdir ubuntu && cd ubuntu
# 설정파일 생성
$ vargrant init centos/7
# 가상 os 실행
$ vargrant up --provider=virtualbox
# 터미널 접속
$ vargrant ssh
Vargrant 명령어
# vagrant 설정파일 VagrantFile파일 생성
$ vagrant init
# Vagrantfile을 기반으로 가상 운영체제 실행
$ vagrant up
# 실행한 가상운영체제 종료
$ vagrant halt
# 설치한 가상운영체제 box 삭제
$ vagrant destroy
지금까지 작업했던 ec2 인스턴스를 이용
SSH Client(local) -> SSH Server(AWS remote)
VS Code Client(local OS) -> VS Code Server(AWS Remote)
VS Code/Remote-SSH 플러그인 설치 후 접속(호스트 OS의 .ssh에 key파일 copy)
이후 동일하게. docker/git 등 설치후 환경 구성
$ sudo apt install -y git
$ git clone {url}
컨테이너를 구성하는 3가지 주요 리눅스 기술
cgroups(Control Groups)
프로세스들이 사용하는 시스템 자원의 사용정보를 수집 및 제한시키는 리눅스 커널 기능
제한 대상: CPU, Memory, Network, Device, Block I/O
사용 가능한 서브시스템
Core workload/Non-core services/Ad-hoc에 따라 다르게 관리
stress tool로 cpu로드 생성 -> CPU 사용량 10% 제한
# stress tool 설치
$ sudo apt install -y stress
# root
$ sudo su
# 작업을 위한 디렉토리 생성
$ cd /sys/fs/cgroup
# 그룹으로 이동해 현재 세션을 해당 그룹에 추가
$ mkdir utils && cd utils
# 터미널 자신의 프로세스ID 확인
$ echo $$
1665
# 현재 관리대상은 없음
$ cat cgroup.procs
# 현재 터미널의 프로세스ID를 관리대상으로편입
$ echo $$ > cgroup.procs
# 현재 터미널의 프로세스ID가 관리대상으로 편입되었음
$ cat cgroup.procs
1665
2105
# period 값 확인
$ cat cpu.max
max 100000
# max 설정
$ echo 10000 > cpu.max
# 10,000 / 100,000 = 10% 확인
$ cat cpu.max
10000 100000
# stress test 실행
$ stress -c 1
stress: info: [2551] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
# 커맨드 분할해 확인
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+
2552 root 20 0 3620 384 384 R 10.0 0.0 0:24.82
1217 ubuntu 20 0 1262996 94984 45824 S 0.3 9.7 0:04.87
1254 ubuntu 20 0 1203460 65676 41216 S 0.3 6.7 0:02.21
1465 ubuntu 20 0 15364 7320 4992 S 0.3 0.7 0:00.63
# 다른 쉘로도 확인
$ echo 20000 > cpu.max
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+
4963 root 20 0 3620 384 384 R 20.0 0.0 0:11.66
1217 ubuntu 20 0 1263764 95372 45824 S 0.3 9.7 0:05.58
1254 ubuntu 20 0 1269916 65700 41216 S 0.3 6.7 0:03.59
프로세스가 지속적으로 자신을 복제함으로써 시스템 자원을 고갈시키고, 속도를 떨어트려 충돌을 일으키는 서비스 거부 공격
# cgroup 디렉토리 이동
$ cd /sys/fs/cgroup
# 예제 디렉토리 생성 후 진입. 디렉토리명과 상관없이 내부에는 cgroup config파일이 생성됨(크기는 0)
$ mkdir police && cd police
# 터미널 프로세스를 관리대상으로
$ echo $$ > cgroup.procs
# 프로세스 생성 개수 확인
$ cat pids.max
max
# 최댓값 수정
$ echo 5 > pids.max
# fork bomb 실행
$ :(){ :|:& };:
# 다른 쉘에서 생성 프로세스 확인
$ ps aux | grep "0:00 bash" | wc -l
ubuntu 1373 0.0 0.3 7872 3584 ? Ss 05:23 0:00 bash
root 1740 0.0 0.4 8132 4224 pts/2 S+ 05:23 0:00 bash
root 8927 0.0 0.2 8132 2556 pts/2 S 05:33 0:00 bash
root 8994 0.0 0.2 8132 2560 pts/2 S 05:33 0:00 bash
root 8996 0.0 0.2 8132 2560 pts/2 S 05:33 0:00 bash
root 8997 0.0 0.2 8132 2560 pts/2 S 05:33 0:00 bash
root 8998 0.0 0.2 8132 2560 pts/2 S 05:33 0:00 bash
root 8999 0.0 0.2 8132 2560 pts/2 S 05:33 0:00 bash
root 9209 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9231 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9232 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9244 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9245 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9246 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9247 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9248 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
root 9250 0.0 0.2 8132 2560 pts/2 S 05:34 0:00 bash
20개 가량
프로세스별로 별도의 커널 자원을 분할하는 리눅스 커널의 기능으로 리눅스 컨테이너 기술의 근간
격리대상: 프로세스ID, Network, File system, user정보 등
cgroup how much you can use
namespaces what you can see
새로운Mount 네임스페이스에서 마운트한 위치에 파일 생성
# unshare 명령어 확인
$ man unshare
# 프로세스 확인
$ echo $$
29687
# 새로운 mount namespace 생성
$ unshare -m /bin/bash
# 새로운 쉘 확인
$ echo $$
32123
# 프로세스 확인
$ ps auxf
# /mnt에 tmpfs(메모리에 생성되는 가상 파일 시스템) 마운드하여 임시 스토리지로 사용
$ mount -t tmpfs tmpfs /mnt
$ cd /mnt
$ echo "Hello" > hello.txt
# 새로운 터미널에서 확인하면 namespace가 다르기 때문에 해당파일 접근할 수 없음. 따라서 해당 namespace PID로 접근
$ nsenter -t 32123 -a
$ ls -l /mnt
total 4
-rw-r--r-- 1 root root 6 Sep 4 06:03 hello.txt
PID 네임스페이스 생성 후 프로세스 트리 정보 확인, 독립된 프로세스 환경임을 확인
$ echo $$
29687
# 새로운 PID namespace 생성(순서대로 PID, mount, IPC, child process)
$ unshare -pmif
$ echo $$
1
# 1번 프로세스이므로 상위 5개 확인
$ ps aux | head -n5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 1.3 22096 13204 ? Ss 05:21 0:04 /sbin/init
root 2 0.0 0.0 0 0 ? S 05:21 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 05:21 0:00 [pool_workqueue_release]
root 4 0.0 0.0 0 0 ? I< 05:21 0:00 [kworker/R-rcu_g]
# 해당 정보는 profile 시스템에서 읽어야 하므로 새로운 namespace에 맞는 proc filesystem 마운트
$ mount -t proc none /proc
$ ls /proc
# 프로세스 재확인
$ ps aux | head -n5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.5 9192 5376 pts/4 S 06:19 0:00 -bash
root 17 0.0 0.4 11320 4352 pts/4 R+ 06:24 0:00 ps aux
root 18 0.0 0.1 6124 1792 pts/4 S+ 06:24 0:00 head -n5
새로운 Network 네임스페이스 생성 후 생성된 네임스페이스 간의 네트워크 연결 확인(Docker/Bridge 형태)
VETH(Virtual Ethernet Pair): 로컬 이더넷 터널로 네트워크 네임스페이스 간 연결 가능하게 하며 페어로 구성됨
CETH(Container Ethernet Interface): 컨테이너 내의 가상 네트워크 인터페이스
$ sudo su
# network namespace 생성
$ ip netns add ns0
$ ip netns add ns1
$ ip netns list
ns0
ns1
# net namespace 안에 어떤 link 있는지 확인
$ ip link # root
$ ip netns exec ns0 ip link # ns0
# network namespace 내의 인터페이스 확인(ns0 에서 실행됨)
$ ip netns exec ns0 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 구동
$ ip netns exec ns0 ip link set lo up
$ ip netns exec ns1 ip link set lo up
# bridge 확인
$ ip link show type bridge
# 호스트에 새로운 브릿지 네트워크 br0 생성 후 구동
$ ip link add br0 type bridge
$ ip link set br0 up
$ ip link show type bridge
4: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether d2:38:95:8f:5b:e3 brd ff:ff:ff:ff:ff:ff
# 브릿지 네트워크에 IP 설정
$ ip addr add 192.168.2.1/24 dev br0
$ ip addr
4: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether d2:38:95:8f:5b:e3 brd ff:ff:ff:ff:ff:ff
inet 192.168.2.1/24 scope global br0
valid_lft forever preferred_lft forever
# 확인
$ ping -c 2 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=0.033 ms
--- 192.168.2.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1045ms
rtt min/avg/max/mdev = 0.029/0.031/0.033/0.002 ms
# veth 페어 생성
$ ip link add veth0 type veth peer name ceth0
$ ip link add veth1 type veth peer name ceth1
# veth를 master br0에 연결&구동
$ ip link set veth0 master br0
$ ip link set veth1 master br0
$ ip link set veth0 up
$ ip link set veth1 up
# ceth를 namespace에 연결&구동
$ ip link set ceth0 netns ns0
$ ip link set ceth1 netns ns1
$ ip netns exec ns0 ip link set ceth0 up
$ ip netns exec ns1 ip link set ceth1 up
# 구동 확인
$ ip netns exec ns1 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: ceth1@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 7a:06:0f:4e:51:72 brd ff:ff:ff:ff:ff:ff link-netnsid 0
# IP가 없으므로 지정
$ ip netns exec ns0 ip addr add 192.168.2.2/24 dev ceth0
$ ip netns exec ns1 ip addr add 192.168.2.3/24 dev ceth1
# IP 확인
$ ip netns exec ns0 ip addr
5: ceth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 8e:20:ca:4e:dd:ed brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.2.2/24 scope global ceth0
valid_lft forever preferred_lft forever
# 네임스페이스 간 통신 확인
$ ip netns exec ns0 ping -c 2 192.168.2.3
!!!!!!!!!!!!!!!!!!!!!!!!
# FORWARD 정책 확인
$ iptables -L FORWARD
Chain FORWARD (policy DROP 16 packets, 1344 bytes)
# DROP이므로 ACCEPT로 바꿔줘야함
$ iptables -P FORWARD ACCEPT
Chain FORWARD (policy ACCEPT)
!!!!!!!!!!!!!!!!!!!!!!!!
하나의 디렉토리 위치에 파일 시스템을 마운트하면?
$ mount -t tmpfs tmpfs /home/ubuntu/linux_campus
$ mount | grep tmpfs
tmpfs on /home/ubuntu/linux_campus type tmpfs (rw,relatime,inode64)
$ ls -l linux_campus/
total 0
$ umount /home/ubuntu/linux_campus
$ ls -l linux_campus/
total 20
drwxrwxr-x 4 ubuntu ubuntu 4096 Sep 3 15:46 Part2
Union mount: 하나의 디렉토리 위치에 여러개의 디렉토리를 마운트하면 하나의 통합된 디렉토리처럼 보이게 하는 방법
Image Layer: 마지막 레이어를 제외하고 Read-Only
CoW(Copy-on-write): 변경된 파일만 저장
Docker 적용? 스토리지 드라이버 e.g. overlay
Overlay FS: 하나의 파일 시스템을 다른 파일 시스템 상단에 overlay
lower1, lower2, upper(writable), merged(실제 사용), work(file system에서 관리목적)
$ mkdir /tmp/{lower1,lower2,upper,merged,work}
$ echo "lower1 a" > /tmp/lower1/a.txt
$ echo "lower1 b" > /tmp/lower1/b.txt
$ echo "lower2 a" > /tmp/lower2/a.txt
$ echo "lower2 c" > /tmp/lower2/c.txt
# read only overlay(/tmp/merged)
$ mount -t overlay overlay overlay -o lowerdir=/tmp/lower1:/tmp/lower2 /tmp/merged
$ mount | grep overlay
overlay on /tmp/merged type overlay (ro,relatime,lowerdir=/tmp/lower1:/tmp/lower2,redirect_dir=on,nouserxattr)
$ cat /tmp/merged/a.txt
lower1 a
$ echo "hello ro" > /tmp/merged/d.txt
bash: /tmp/merged/d.txt: Read-only file system
$ umount /tmp/merged
# Read/Write 갖는 uppder지정
$ mount -t overlay overlay -o lowerdir=/tmp/lower1:/tmp/lower2, upperdir=/tmp/upper,workdir=/tmp/work /tmp/merged
# RW 확인
$ mount | grep overlay
overlay on /tmp/merged type overlay (rw,relatime,lowerdir=/tmp/lower1:/tmp/lower2,upperdir=/tmp/upper,workdir=/tmp/work,uuid=on,nouserxattr)
$ echo "Hello World" > /tmp/merged/hello.txt
$ cat /tmp/merged/hello.txt
Hello World
$ ls -l /tmp/upper
total 4
-rw-r--r-- 1 root root 12 Sep 4 09:07 hello.txt
$ umount /tmp/merged
# busy는, 해당 디렉토리에 들어가 있어서 발생함. 빠져나와서 umount
docker union mount test
$ docker pull nginx
# 데몬으로 실행
$ docker run --rm -d nginx
$ mount | grep overlay
# rw, lowerdir에 여러 디렉토리 지정됨을 확인, uppderdir에 하나의 디렉토리 지정 확인, workdir 지정 확인