容器核心知识

239 阅读3分钟

1.什么是容器

首先介绍几个基本概念:

  • 容器进行时runtime:容器真正运行的地方(就好比java运行在JVM上)。低阶运行时(low-level runtime)关注如何与操作系统交互,创建并运行容器,常见的低阶运行时有runc、rkt等。高阶运行时(high-level runtime)关注于将容器镜像解压并传递到低阶运行时中,常见的高阶运行时有:docker、containerd、rkt。
  • 容器引擎:主要是准备运行容器的资源以及管理容器的声明周期,docker使用docker engine作为管理docker的引擎,kubernetes为了兼容多种容器,引入CRI来调用容器引擎(通信协议是gRPC)。
  • 容器仓库:统一存放镜像的地方,常见的有docker hub,私人搭建的harbor仓库。

2.安装运行容器

安装docker脚本:

#!/bin/sh
echo "Remove Old Docker..."
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
echo "Start install docker..."
sudo yum install -y yum-utils
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
sudo yum -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl start docker
sudo systemctl enable docker

3.docker镜像

base镜像:一种是不依赖其他镜像,从scratch构建;一种是各种Linux发行版的镜像。
为什么容器镜像会比虚拟镜像小:linux刚启动时会加载内核空间的bootfs文件系统,之后将其卸载掉,而容器镜像只需要准备用户空间的rootfs文件系统即可。rootfs只需要包括最基本的命令、工具和程序库就可以了。也就是说容器使用的是宿主机的内核。

3.1 构建镜像

一种方式是将运行时的容器通过docker commit保存为镜像
一种方式是通过编写Dockerfile构造镜像(也是通过docker commit一层一层构建镜像的)

3.2 Dockerfile

  • From 指定base镜像
  • MANITAINER 镜像作者
  • COPY 将文件复制到镜像层
  • ADD 与COPY的不同点在于归档文件会自动解压
  • ENV 设置环境变量
  • EXPOSE 暴露端口
  • VOLUME 设置存储卷
  • WORKDIE 设置镜像当前的工作目录
  • RUN 在容器中运行指定命令,常用来安装应用和软件包
  • CMD 指定容器的默认执行命令,可以被docker run后面的命令行参数替换
  • ENTRYPOINT 让容器以服务的形式运行,不会被忽略,一定会执行

4.docker技术栈

docker底层使用了namespace做视图隔离,cgroup做资源限制。

4.1 namespace

一共有六种:PID namespace, net namespace, IPC namespace, Mount namespace, UTS namespace, USR namespace. 提供了不同视图视角。

4.2 Cgroups

对CPU、内存、磁盘IO等进程所需要资源进行管控 可配额:cpu、memory

4.3 Union FS生成文件系统

常用的有AUFS,overlayFS等
写特性:Copy-on-write

5. docker实验

5.1 network namespace

fork一个net namespace并进入这个namespace查看ip

$ unshare -fn sleep 120 # unshare 启动了一个新的网络namespace的子进程
   NS       TYPE    NPROCS  PID    USER    NETNSID NSFS                         COMMAND
4026537700   net       2   2698215  root     unassigned                          unshare 
$ nsenter -t <pid> -n ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

5.2 cgroup限制cpu资源

我们设置一个busyloop的死循环go程序

$ vi busyloop.go
package main

func main() {
	go func() {
		for {
		}
	}()
	for {
	}
}
$ go build busyloop.go

我们设置开启一个限制busyloop的cgroup树

cd /sys/fs/cgroup/cpu
mkdir cpudemo

首先运行该程序,并查看cpu占用情况

$ ./busyloop
$ top # cpu占用率为197%,因为我这里是两个cpu
$ echo 2830119 > cgroup.procs # 将要管理的进程ID写如cgroup.procs中
$ echo 100000 > cpu.cfs_quota_us # 将分配的时间片设置为一个CPU的大小,发现CPU占用率变为100%
$ echo 10000 > cpu.cfs_quota_us # cpu占用率变为10%左右,说明限制了进程的资源

tips

推荐几个常见的开源容器监控工具:Weave Scope,cAdvisor,Prometheus 日志管理工具:ELK:Elasticsearch、logstash、Kibana