컨테이너 격리 & 도커 네트워크
Kubernetes Advanced Networking Study(이하 KANG) 첫번째 시간에 내용을 정리 하였습니다.
도커(Docker)란?
도커(Docker)는 가상실행 환경
을 제공해주는 오픈소스 플랫폼입니다. 도커에서는 이 가상실행 환경을 컨테이너(Container)
라고 부릅니다.
- 정확히 표현하는 용어는 ‘컨테이너화된 프로세스(Containerized Process)’
- 도커 플랫폼이 설치된 곳이라면 컨테이너로 묶인 애플리케이션을 어디서든 실행할 수 있음
컨테이너 VS Virtual Machine(VM)
hypervisor를 이용한 Virtual Machine
과프로세스를 이용한 컨테이너의
차이를 비교 합니다.
컨테이너
는 운영체제를 제외한 나머지 애플리케이션 실행에 필요한 모든 파일을 패키징한다는 점에서 OS레벨 가상화
를 지원하는 1개 이상의 프로세스 세트
입니다 컨테이너는 프로세스
가 지정된 리소스 요청에만 액세스할 수 있도록 허용
합니다. 이러한 리소스 제한은 컨테이너가 용량이 충분한 노드에서 구동될 수 있도록 합니다.
- 컨테이너는 호스트의 커널을 공유하지만, 개별적인 ‘사용자 공간(user space)’ 를 가집니다.
- 가상화된 공간을 생성하기 위해 리눅스 기능
pivot-root
,네임스페이스(namespace)
,cgroup
를 사용함으로써 프로세스 단위의 격리 환경과 리소스을 제공합니다.
VM
은 자체 운영 체제(Operating System, OS)를 포함
하고 있어 여러 리소스 집약적인 기능을 한 번에 수행할 수 있습니다. VM에서 사용할 수 있는 리소스가 늘어남에 따라 전체 서버, OS, 데스크톱, 데이터베이스, 네트워크를 추상화, 분할, 복제, 에뮬레이션할 수 있습니다.
- 개별 VM은 독립된 OS를 사용하여 컨테이너 방식에 비해 고립성(보안)은 더 좋지만, 오버헤드가 크고 무겁고 느리다는 단점을 가짐
컨테이너
와VM
은 유사하다고 볼 수 있습니다. 중요한 차이점은확장 방식
과이식성
입니다.컨테이너
는게스트OS
와하이버파이저
가 없기 때문에 이로 인한오버헤드를 줄임
으로써훨씬 더 가볍게 프로세스를 실행
할 수 있고 컨테이너에 대한 복제와 배포가 더 용이합니다.
docker 아키텍처
#1 vagrant로 docker 사용해보기
작업을 시작하려고 하는 빈 디렉토리에서 아래 파일을 생성합니다.
Vagrantfile
파일
Vagrant.configure("2") do |config|
config.vm.boot_timeout = 1800
config.vm.box = "ubuntu/focal64"
config.vm.box_version = "20211026.0.0"
config.vm.provision "shell", inline: "echo 'sudo su -' >> .bashrc"
config.vm.provision "shell", inline: "apt update"
config.vm.provision "shell", inline: "apt install -y conntrack bridge-utils net-tools resolvconf jq tree"
config.vm.provision "shell", inline: "echo 'nameserver 8.8.8.8' > /etc/resolvconf/resolv.conf.d/head"
config.vm.provision "shell", inline: "resolvconf -u"
config.vm.network "private_network", ip: "192.168.50.10"
config.vm.network "forwarded_port", guest: 22, host: 60510, auto_correct: true, id: "ssh"
config.vm.synced_folder "./", "/vagrant", disabled: true
config.vm.provider "virtualbox" do |spec|
spec.memory = "2048"
spec.cpus = "2"
spec.linked_clone = true
spec.customize [ "modifyvm", :id, "--uartmode1", "disconnected" ]
end
end
준비가 되었으면, vagrant
명령어로 VM을 실행합니다.
# vagrant 프로비저닝
$ vagrant up
# Ubuntu SSH 접속
$ vagrant ssh
-----------
# Ubuntu Shell 에서 Ubuntu 종료
$ poweroff
-----------
# Ubuntu 재시작 후 Ubuntu SSH 접속
$ vagrant reload
$ vagrant ssh
프로비저닝(provisioning)
은 사용자의 요구에 맞게 시스템 자원을 할당, 배치, 배포해 두었다가 필요 시 시스템을 즉시 사용할 수 있는 상태로 미리 준비해 두는 것을 말한다. 서버 자원 프로비저닝, OS 프로비저닝, 소프트웨어 프로비저닝, 스토리지 프로비저닝, 계정 프로비저닝 등이 있다. 수동으로 처리하는 ‘수동 프로비저닝’과 자동화 툴을 이용해 처리하는 ‘자동 프로비저닝’이 있다
추가 TIP
lahuman@HP:/mnt/c/Users/lahum/projects/KANS/1week/1.docker$ vagrant reload
==> default: Checking if box 'ubuntu/focal64' version '20211026.0.0' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: hostonly
==> default: Forwarding ports...
default: 22 (guest) => 60510 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 172.29.0.1:60510
default: SSH username: vagrant
default: SSH auth method: private key
Timed out while waiting for the machine to boot. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.
If you look above, you should be able to see the error(s) that
Vagrant had when attempting to connect to the machine. These errors
are usually good hints as to what may be wrong.
If you're using a custom box, make sure that networking is properly
working and you're able to connect to the machine. It is a common
problem that networking isn't setup properly in these boxes.
Verify that authentication configurations are also setup properly,
as well.
If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.
위와 같이 timout
이 발생하여서 다시 기동시에 reload
를 하지 말고 up
으로 요청하면 VM 서버를 재기동 하지 않고 연결합니다.
# VM이 재기동 되어 오랜 시간이 걸림
lahuman@HP:/mnt/c/Users/lahum/projects/KANS/1week/1.docker$ vagrant reload
==> default: Attempting graceful shutdown of VM...
==> default: Checking if box 'ubuntu/focal64' version '20211026.0.0' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
default: Adapter 2: hostonly
==> default: Forwarding ports...
default: 22 (guest) => 60510 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 172.29.0.1:60510
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection reset. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.
# VM 기동 완료되어서 바로 시작
lahuman@HP:/mnt/c/Users/lahum/projects/KANS/1week/1.docker$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'ubuntu/focal64' version '20211026.0.0' is up to date...
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.
Virtualbox 네트워크 구성 정보
Host PC에서 ssh 접근시
vagrant ssh 접속 시 기본적으로 호스트에 127.0.0.1(60510)를 목적지로 접속 → 이후 포트포워딩(SNAT + DNAT)을 통해서 내부에 VM로 SSH 연결됨
Ubuntu에서 외부 인터넷 접속시
docker 설치
다음 명령어로 docker를 설치합니다.
# 도커 설치
$ curl -fsSL https://get.docker.com | sh
# 도커 정보 확인
$ docker info
$ docker version
# 도커 서비스 상태 확인
$ systemctl status docker
# 'q' 입력으로 빠져나오기
# 모든 서비스의 상태 표시 - 링크
$ systemctl list-units --type=service
# 도커 루트 디렉터리 확인
$ tree -L 3 /var/lib/docker
# 결과
/var/lib/docker
├── buildkit
│ ├── cache.db
│ ├── containerdmeta.db
│ ├── content
│ │ └── ingest
│ ├── executor
│ ├── metadata_v2.db
│ └── snapshots.db
├── containers
├── image
│ └── overlay2
│ ├── distribution
│ ├── imagedb
│ ├── layerdb
│ └── repositories.json
├── network
│ └── files
│ └── local-kv.db
├── overlay2
│ └── l
├── plugins
│ ├── storage
│ │ └── ingest
│ └── tmp
├── runtimes
├── swarm
├── tmp
├── trust
└── volumes
├── backingFsBlockDev
└── metadata.db
23 directories, 8 files
docker 설치 후 기본 정보 확인
# 프로세스 확인 - 셸변수
$ ps -ef
$ pstree -p
# 시스템에 (마운트 된) disk free 디스크 여유 공간 확인
$ df -hT
# 네트워크 정보 확인 >> docker0 네트워크 인터페이스가 추가됨, 현재는 DOWN 상태
$ ip -br -c addr
$ ip -c addr
$ ip -c link
$ ip -br -c link
$ ip -c route
# 이더넷 브리지 정보 확인
$ brctl show
# iptables 정책 확인
$ iptables -t filter -S
$ iptables -t nat -S
iptables
명령어의 결과를 자세히 보면, docker를 설치하기 전과 후가 다릅니다.
# filter 에 FORWARD 가 기존 ACCEPT 에서 DROP 로 변경됨
# filter 에 FORWARD 에 docker0 에서 docker0 혹은 외부로 전달 허용 정책이 추가됨
$ iptables -t filter -S
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
# nat POSTROUTING 에 172.17.0.0/16 에서 외부로 전달 시 매스커레이딩(SNAT) 정책이 추가됨
iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
#2 컨테이너 실행 및 확인
Ubuntu 호스트 VM 에서 동작하는 컨테이너의 네트워크 정보 샘플
# nginx 이미지를 컨테이너 백그라운드로 실행
# -d 는 Detached 모드로 컨테이너를 실행. 컨테이너를 백그라운드에서 동작하는 애플리케이션으로써 실행하도록 설정.
# Detached 모드인 컨테이너는 반드시 컨테이너에서 프로그램이 실행돼야 하며 프로그램이 실행되지 않으면 컨테이너는 종료됩니다.
$ docker run -d nginx
$ docker ps
# 실행중인 컨테이너의 ID만 확인
$ docker ps -q
# 컨테이너 상세 정보 확인
# docker inspect '<NAME> 혹은 <ID>'
$ docker inspect $(docker ps -q)
# 컨테이너(=Instance)의 IP 정보 확인(JSON) - 링크
# docker inspect --format='' $INSTANCE_ID
$ docker inspect -f '' $(docker ps -q)
$ ping 172.17.0.2
# 호스트 네트워크 인터페이스 정보 확인
$ ip -c a
$ brctl show
# curl 로 http 접속 테스트 - 링크 링크2
$ curl `docker inspect -f '' $(docker ps -q)` | grep -o '<title>.*</title>'
$ curl -s 172.17.0.2 | grep -o '<title>.*</title>'
# 컨테이너의 log 확인
$ docker logs -f $(docker ps -q)
# 컨테이너에 명령 실행
# nginx 컨테이너의 index.html 파일의 위치는 /usr/share/nginx/html/index.html 입니다
$ docker exec $(docker ps -q) ls /usr/share/nginx/html
$ docker exec $(docker ps -q) cat /usr/share/nginx/html/index.html
# 실행 및 종료된 컨테이너까지 전부삭제
$ docker rm -f $(docker ps -a -q)
ubuntu:16.04 이미지에 bash 쉘 실행
# 호스트 Ubuntu 버전 확인
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
# ubuntu 16.04 컨테이너 실행하면서 bash 쉘 실행 → 컨테이너 내부로 진입
$ docker run --rm -it ubuntu:16.04 bash
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.7 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.7 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 09:56 pts/0 00:00:00 bash
root 12 1 0 09:56 pts/0 00:00:00 ps -ef
$ exit
# 컨테이너 상태 확인
docker ps
Host 리눅스 배포판과 다른 centos 이미지를 실행하며 bash 쉘 실행!
$ docker run --rm -it centos bash
$ cat /etc/redhat-release
CentOS Linux release 8.4.2105
$ exit
TIP 도커 호스트의 ‘리눅스 배포판’과 컨테이너의 ‘커널 버전’이 달라도 컨테이너가 동작하는 이유는?
LBS(Linux Base Standart)
는 소스 코드를 컴파일한 시점에서 호환성 있는 머신 코드를 생성하도록 ISO 규격으로 표준화되어 있다.- 리눅스 ABI(Application Binary Interface)로 인해 리눅스 커널의 버전이 올라가도 유저 공간에서 동작하는
바이너리(머신 코드) 레벨의 호환성
은 유지된다. - 참고 링크
스터디에서 토론한 내용을 추가 합니다.
[홀스]님 : 컨테이너가 다른버전 다른 os가 동작하는게 지금까지 알아본 정보는 CPU이 기계어 명령어 셋인 ISA가 각각 아키텍쳐 마다 다르고, OS에는 이 ISA와 연동되는 ABI가 있는데 이 부분이 호환되는거라 가능한걸로 알고 있습니다. 이 ABI는 제조사에서 커널에 개발해서 넣는 경우가 많다고 하고요. 이 커널의 경우는 linux foudation에서만 개발하기에 대부분 리눅스는 호환되고요. 그리고 ABI가 레드햇이라던가에서 따로 개발해서 넣는 경우도 있습니다. 만약 라이브러리나 어플리케이션이 이러한 ABI를 사용하게 될 경우 버전에 따라 동작 안할 수도 있습니다.
[가우]님 : linux syscall r3->r0 (calling convention, asm 호환) 호환 및 아키텍쳐가 동일하다면 라이브러리에서 호환성을 가져갈수 있을것 같네요. 음 그런데 호스트 커널 버전이 낮고 도커이미지 버전이 높으면 일부 동작안하는 기능이 있을 것도 같군요
단, 호스트와 CPU 아키텍처
가 다른 컨테이너 이미지는 동작 불가합니다.
# Host가 AMD CPU 일때
$ cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 23
model : 96
model name : AMD Ryzen 5 4500U with Radeon Graphics
stepping : 1
microcode : 0xffffffff
cpu MHz : 2370.554
cache size : 512 KB
...
# riscv64로 CPU 아키텍처로 실행하려고 하면 아래와 같이 오류가 발생합니다.
$ docker run --rm -it riscv64/ubuntu bash
Unable to find image 'riscv64/ubuntu:latest' locally
latest: Pulling from riscv64/ubuntu
8c703baf60b6: Pull complete
Digest: sha256:bc700522fdbb6d8fa43a6800954e3f12c6990df7e344649c05eafac375aa4dcf
Status: Downloaded newer image for riscv64/ubuntu:latest
WARNING: The requested image's platform (linux/riscv64) 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
#3 컨테이너 격리에 대하여
컨테이너의 시작은 1979년 chroot
에서로 부터 시작했습니다.
리눅스의 파일 시스템은
root(/)
로 부터 시작합니다. 따라서 특정 디렉토리를root(/)
로 지정할수 있으면 해당 경로에 프로세스를 가두는 점에서 착안되었습니다. FTP(원격 유저)를 특정 디렉토리 경로에 가두기 위한 용도로 사용됩니다.
chroot
를 사용하기 위해서는 필요한 프로그램들을 하나하나 복사해서 새로운 root(/)
디렉토리 밑으로 넣어두어야 합니다.
이렇게 필요한 파일들을 미리 넣어두어서 만들어두는 것을 이미지
라고 하며, 흔히 도커 이미지
라고 합니다
하지만 chroot
는 큰 취약점이 있습니다. 바로 탈옥
이 가능하다는 것입니다. 이외에도 호스트와 격리 문제, 호스트 리소스를 제한 없이 사용이 가능하고, root 권한 및 다양한 보안 문제를 가지고 있습니다.
탈옥
은root(/)
디렉토리를 벗어나는 행위를 이야기 합니다. 이를 해결한 방법이pivot_root
와Namespace
입니다. 또한 리소스에 대한 제한을 위해서는Cgroup
을 사용합니다. 더욱 자세한 내용은 도커 없이 컨테이너 만들기를 참조해주세요. :)
Docker
를 이용할 경우 위의 문제점을 해결한 독립된 리눅스 환경을 보장받는 프로세스가 생성됩니다. 단, Host 프로세스에서 컨테이너(프로세스)를 종료할 수 있습니다. VM 환경에서는 Host에서 프로세스에 접근이 기본적으로 어렵습니다.
아래는 Host에서 컨테이너의 파일에 접근하고 삭제하는 실습입니다.
# 터미널1 (Ubuntu 컨테이너)
## Ubuntu 컨테이너 bash 접속 후 명령어 실행
docker run --rm -it ubuntu bash
## echo $$ : 현재 bash 쉘의 프로세스 ID - 링크
$ echo $$
1
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:03 pts/0 00:00:00 bash
root 11 1 0 14:03 pts/0 00:00:00 ps -ef
$ ps afxuwww
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 4108 3680 pts/0 Ss 14:03 0:00 bash
root 12 0.0 0.1 5896 2948 pts/0 R+ 14:03 0:00 ps afxuwww
## 현재 프로세스의 네임스페이스 정보 : 호스트와 컨테이너의 Namespace 중 ipc, mnt, net, pid, uts 가 다르다
$ ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 Jan 13 14:04 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 ipc -> 'ipc:[4026532258]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 mnt -> 'mnt:[4026532256]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 net -> 'net:[4026532261]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 pid -> 'pid:[4026532259]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 pid_for_children -> 'pid:[4026532259]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Jan 13 14:04 uts -> 'uts:[4026532257]'
# 터미널2 (호스트 Shell)
$ echo $$
1424
$ ps -ef | grep bash
vagrant 1412 1411 0 08:46 pts/0 00:00:00 -bash
root 1424 1423 0 08:46 pts/0 00:00:00 -bash
root 12330 1424 0 14:00 pts/0 00:00:00 grep --color=auto bash
# 모든 프로세스 확인
$ ps afxuwww
# 전체 프로세스가 표출됨
# 네임 스페이스 확인
$ ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 Jan 13 14:01 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 net -> 'net:[4026531992]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Jan 13 14:01 uts -> 'uts:[4026531838]'
# UTS(호스트네임, 도메인네임)이 다르다!
## 터미널1 (Ubuntu 컨테이너)
$ hostname
$ cat /etc/hostname
a1c2d8316afb
## 터미널2 (호스트 Shell)
$ hostname
$ cat /etc/hostname
ubuntu-focal
# PID(프로세스ID)가 다르다!
## 터미널1 (Ubuntu 컨테이너)
$ ps -eaf
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:03 pts/0 00:00:00 bash
root 16 1 0 14:05 pts/0 00:00:00 ps -eaf
$ ps afxuwww
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 4108 3680 pts/0 Ss 14:03 0:00 bash
root 17 0.0 0.1 5896 3128 pts/0 R+ 14:05 0:00 ps afxuwww
## 터미널2 (호스트 Shell)
$ ps -eaf
$ ps afxuwww
# 모든 프로세스 표출
# NET(네트워크 환경)이 다르다!
## 터미널1 (Ubuntu 컨테이너)
$ sed -i 's/archive.ubuntu.com/ftp.daum.net/g' /etc/apt/sources.list
$ apt update && apt -y install net-tools
# 설치 됨
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)
RX packets 7736 bytes 21137301 (21.1 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3899 bytes 215690 (215.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
## 터미널2 (호스트 Shell)
$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:9ff:fe51:ba05 prefixlen 64 scopeid 0x20<link>
ether 02:42:09:51:ba:05 txqueuelen 0 (Ethernet)
RX packets 3913 bytes 163570 (163.5 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7747 bytes 21138259 (21.1 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255
inet6 fe80::31:14ff:fe45:3203 prefixlen 64 scopeid 0x20<link>
ether 02:31:14:45:32:03 txqueuelen 1000 (Ethernet)
RX packets 251806 bytes 373931304 (373.9 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 52954 bytes 3428495 (3.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.50.10 netmask 255.255.255.0 broadcast 192.168.50.255
inet6 fe80::a00:27ff:fe41:3ff2 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:41:3f:f2 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 33 bytes 2486 (2.4 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 2 bytes 124 (124.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 124 (124.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth2e41a0a: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::2811:75ff:feb8:4ab prefixlen 64 scopeid 0x20<link>
ether 2a:11:75:b8:04:ab txqueuelen 0 (Ethernet)
RX packets 14 bytes 2662 (2.6 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 40 bytes 3152 (3.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.2.2 0.0.0.0 UG 100 0 0 enp0s3
10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 enp0s3
10.0.2.2 0.0.0.0 255.255.255.255 UH 100 0 0 enp0s3
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.50.0 0.0.0.0 255.255.255.0 U 0 0 0 enp0s8
# MNT(마운트 파일시스템 구조)가 다르다!
## 터미널1 (Ubuntu 컨테이너) 파일 생성
$ ls /
$ for i in {1..100}; do touch /deleteme.$i; done;
$ echo '1q2w3e' > /secret.txt
$ ls /
## 터미널2 (호스트 Shell)
$ tree -L 1 /
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib32 -> usr/lib32
├── lib64 -> usr/lib64
├── libx32 -> usr/libx32
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── snap
├── srv
├── sys
├── tmp
├── usr
└── var
$ findmnt -t overlay
TARGET SOURCE FSTYPE OPTIONS
/var/lib/docker/overlay2/05bb70b4b6bb1c325a01ce9d9bf4c11053b2c73e136556717b1a65caa113d688/merged overlay overla rw,relat
$ ls -a $(findmnt -t overlay | grep -v TARGET | awk '{print $1}')
/var/lib/docker/overlay2/05bb70b4b6bb1c325a01ce9d9bf4c11053b2c73e136556717b1a65caa113d688/merged:
. deleteme.17 deleteme.3 deleteme.42 deleteme.55 deleteme.68 deleteme.80 deleteme.93 media
.. deleteme.18 deleteme.30 deleteme.43 deleteme.56 deleteme.69 deleteme.81 deleteme.94 mnt
.dockerenv deleteme.19 deleteme.31 deleteme.44 deleteme.57 deleteme.7 deleteme.82 deleteme.95 opt
bin deleteme.2 deleteme.32 deleteme.45 deleteme.58 deleteme.70 deleteme.83 deleteme.96 proc
boot deleteme.20 deleteme.33 deleteme.46 deleteme.59 deleteme.71 deleteme.84 deleteme.97 root
deleteme.1 deleteme.21 deleteme.34 deleteme.47 deleteme.6 deleteme.72 deleteme.85 deleteme.98 run
deleteme.10 deleteme.22 deleteme.35 deleteme.48 deleteme.60 deleteme.73 deleteme.86 deleteme.99 sbin
deleteme.100 deleteme.23 deleteme.36 deleteme.49 deleteme.61 deleteme.74 deleteme.87 dev secret.txt
deleteme.11 deleteme.24 deleteme.37 deleteme.5 deleteme.62 deleteme.75 deleteme.88 etc srv
deleteme.12 deleteme.25 deleteme.38 deleteme.50 deleteme.63 deleteme.76 deleteme.89 home sys
deleteme.13 deleteme.26 deleteme.39 deleteme.51 deleteme.64 deleteme.77 deleteme.9 lib tmp
deleteme.14 deleteme.27 deleteme.4 deleteme.52 deleteme.65 deleteme.78 deleteme.90 lib32 usr
deleteme.15 deleteme.28 deleteme.40 deleteme.53 deleteme.66 deleteme.79 deleteme.91 lib64 var
deleteme.16 deleteme.29 deleteme.41 deleteme.54 deleteme.67 deleteme.8 deleteme.92 libx32
$ echo $(findmnt -t overlay | grep -v TARGET | awk '{print $1}')
/var/lib/docker/overlay2/05bb70b4b6bb1c325a01ce9d9bf4c11053b2c73e136556717b1a65caa113d688/merged
$ cat $(findmnt -t overlay | grep -v TARGET | awk '{print $1}')/secret.txt
1q2w3e
$ rm -rf $(findmnt -t overlay | grep -v TARGET | awk '{print $1}')/deleteme.*
$ ls -a $(findmnt -t overlay | grep -v TARGET | awk '{print $1}')
. .dockerenv boot etc lib lib64 media opt root sbin srv tmp var
.. bin dev home lib32 libx32 mnt proc run secret.txt sys usr