近期Docker 19.03中發佈了一個重要的特性 「Rootless Container支持」。趁着五一假期,快速驗證一下。本文參考了Experimenting with Rootless Docker 一文的內容,而且補充了更多的細節和上手內容。linux
Docker和Kubernetes已經成爲企業IT架構的基礎設施,其自身安全愈來愈被關注。Docker基於Linux操做系統提供了應用虛擬化能力,經過namespace, cgroup實現了資源的隔離和配額約束。Docker Engine是一個典型的 Client-Server 結構:nginx
Docker Client (TCP/Unix Socket) -> Docker Daemon (Parent/Child Processes) -> Containergit
因爲Linux須要特權用戶來建立namespace,掛載分層文件系統等,因此 Docker Daemon 一直以來是以root用戶來運行的。這也致使了有Docker訪問權限的用戶能夠經過鏈接Docker Engine獲取root權限,並且能夠繞開系統的審計能力對系統進行攻擊。這阻礙了容器在某些場景的應用:好比在高性能計算領域,因爲傳統的資源管理和調度系統須要非特權用戶來運行容器,社區實現了另外的容器運行時Singularity 。github
Moby社區的 Akihiro Suda,爲Docker Engine和Buildkit貢獻了rootless容器支持,讓Docker Engine以非特權用戶方式運行,更好地複用Linux的安全體系。docker
注意:安全
Rootless容器有幾個核心技術bash
首先是利用 user namespaces 將容器中的root用戶uid/gid映射到宿主機的非特權用戶範圍內。Docker Engine已經提供了 --userns-remap
標誌支持了相關能力,提高了容器的安全隔離性。Rootless容器在此之上,讓Docker daemon也運行在重映射的用戶名空間中。服務器
其次,雖然Linux中的非特權用戶能夠在用戶名空間中建立網絡名空間,而且執行iptables規則管理和tcpdump等操做,然而非特權用戶沒法在宿主機和容器之間建立veth pairs, 這也意味着容器沒有外網訪問能力。爲了解決這個問題,Akihiro 利用用戶態的網絡「SLiRP」,經過一個TAP設備鏈接到非特權用戶名空間,爲容器提供外網鏈接能力。其架構以下網絡
相關細節請參考,slirp4netns項目架構
本文在一臺 CentOS 7.6的虛擬機上進行的驗證
建立用戶
$ useradd moby $ passwd moby
將新建用戶添加到 sudoers 組
usermod -aG wheel moby
切換到非特權用戶
$ su - moby $ id uid=1000(moby) gid=1000(moby) groups=1000(moby),10(wheel)
進行uid/gid映射配置
echo "moby:100000:65536" | sudo tee /etc/subuid echo "moby:100000:65536" | sudo tee /etc/subgid
安裝Rootless Docker
curl -sSL https://get.docker.com/rootless | sh
若是第一次安裝,須要安裝所需軟件包
$ curl -sSL https://get.docker.com/rootless | sh # Missing system requirements. Please run following commands to # install the requirements and run this installer again. # Alternatively iptables checks can be disabled with SKIP_IPTABLES=1 cat <<EOF | sudo sh -x curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo yum install -y shadow-utils46-newxidmap cat <<EOT > /etc/sysctl.d/51-rootless.conf user.max_user_namespaces = 28633 EOT sysctl --system EOF
(可選)安裝用戶態網絡協議棧實現 slirp4netns :因爲yum 安裝的slirp4netns版本比較老沒法執行,須要從源碼構建。
$ sudo yum install glib2-devel $ sudo yum group install "Development Tools" $ git clone https://github.com/rootless-containers/slirp4netns $ cd slirp4netns $ ./autogen.sh $ ./configure --prefix=/usr $ make $ sudo make install
安裝 Rootless Docker成功以後,會出現以下提示
$ curl -sSL https://get.docker.com/rootless | sh # systemd not detected, dockerd daemon needs to be started manually /home/moby/bin/dockerd-rootless.sh --experimental --storage-driver vfs # Docker binaries are installed in /home/moby/bin # Make sure the following environment variables are set (or add them to ~/.bashrc):\n export XDG_RUNTIME_DIR=/tmp/docker-1000 export DOCKER_HOST=unix:///tmp/docker-1000/docker.sock
執行
$ export XDG_RUNTIME_DIR=/tmp/docker-1000 $ export DOCKER_HOST=unix:///tmp/docker-1000/docker.sock $ /home/moby/bin/dockerd-rootless.sh --experimental --storage-driver vfs
而後在另一個窗口執行
$ export XDG_RUNTIME_DIR=/tmp/docker-1000 $ export DOCKER_HOST=unix:///tmp/docker-1000/docker.sock $ docker version Client: Version: master-dockerproject-2019-04-29 API version: 1.40 Go version: go1.12.4 Git commit: 3273c2e2 Built: Mon Apr 29 23:39:39 2019 OS/Arch: linux/amd64 Experimental: false Server: Engine: Version: master-dockerproject-2019-04-29 API version: 1.40 (minimum version 1.12) Go version: go1.12.4 Git commit: 9a2c263 Built: Mon Apr 29 23:46:23 2019 OS/Arch: linux/amd64 Experimental: true containerd: Version: v1.2.6 GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb runc: Version: 1.0.0-rc7+dev GitCommit: 029124da7af7360afa781a0234d1b083550f797c docker-init: Version: 0.18.0 GitCommit: fec3683 $ docker run -d -p 8080:80 nginx $ curl localhost:8080
利用 iperf3 進行網絡性能測試,啓動服務器端
$ docker run -it --rm --name=iperf3-server -p 5201:5201 networkstatic/iperf3 -s
測試容器之間的網絡帶寬
$ SERVER_IP=$(docker inspect --format "{{ .NetworkSettings.IPAddress }}" iperf3-server) $ echo $SERVER_IP 172.17.0.2 $ docker run -it --rm networkstatic/iperf3 -c $SERVER_IP ... - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.03 sec 29.8 GBytes 25.5 Gbits/sec 0 sender [ 4] 0.00-10.03 sec 29.8 GBytes 25.5 Gbits/sec receiver
測試容器到宿主機之間的網絡帶寬(外網訪問)
$ HOST_IP=$(hostname --ip-address) $ echo $HOST_IP 192.168.1.162 $ docker run -it --rm networkstatic/iperf3 -c $HOST_IP ... - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.00 sec 1011 MBytes 848 Mbits/sec 0 sender [ 4] 0.00-10.00 sec 1008 MBytes 845 Mbits/sec receiver
能夠看到容器之間的通訊帶寬還比較不錯,然而容器和宿主機不一樣網絡名空間之間的通訊性能有較大的損耗。
Rootless容器在提高Docker/Runc容器的安全隔離性和可管理性方面前進了一大步,能夠很好地複用Linux的安全體系,配合seccomp和SELinux等安全配置,能夠減小攻擊面。社區還提供了無需特權用戶的Kubernetes實驗版本,能夠從以下項目得到 https://github.com/rootless-containers/usernetes
然而Rootless容器沒法防範Linux內核的安全風險,目前其網絡、存儲的性能也有待優化,須要在特定場景中進行使用。也期待社區持續提高容器安全能力與效率,讓容器有更加廣闊的應用場景。
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。