Docker: 容器与镜像

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: Docker: 容器与镜像

1、docker 环境搭建

1.1、docker 安装

1.1.1、centos 安装

# 安装依赖
 yum install -y yum-utils
 # 设置 stable 镜像仓库(阿里云镜像)
 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 # 更新 yum 安装包索引
 yum makecache fast
 # 安装 docker 引擎
 yum -y install docker-ce docker-ce-cli containerd.io
 # 测试
 docker run hello-world

1.1.2、ubuntu 安装

修改镜像源 /etc/apt/sources.list,设置清华源

基于 apt 包管理器安装

# 安装
 sudo apt install docker.io
 sudo apt install docker-compose
 # 卸载
 sudo apt-get purge docker.io
 sudo rm -rf /var/lib/docker
 sudo rm -rf /var/lib/containerd
 # 测试
 docker run hello-world

基于官方文档安装

# 1、安装依赖
 sudo apt-get update
 sudo apt-get install ca-certificates curl gnupg lsb-release
 # 2、添加 docker 官方的GPG 秘钥
 sudo mkdir -p /etc/apt/keyrings
 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
 # 3、设置一个标准 docker 软件仓库
 echo \
   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
 # 查看 docker 镜像源
 vim /etc/apt/sources.list.d/docker.list
 # 4、更新 apt 包索引并查看docker 可用版本列表
 sudo apt-get update
 apt-cache madison docker-ce
 # 5、安装 docker ce及组件
 sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
 # 卸载
 sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-compose-plugin
 sudo rm -rf /var/lib/docker
 sudo rm -rf /var/lib/containerd
 sudo rm -rf /etc/docker/
 # 测试
 docker run hello-world

docker 启动设置

# 启动 docker
 systemctl start docker 
 # 停止 docker
 systemctl stop docker 
 # 重启 docker
 systemctl restart docker 
 # 查看 docker 状态
 systemctl status docker 
 # 开机启动
 systemctl enable docker

1.2、添加到 docker 组

添加用户到 docker 组后,使用 docker 命令无需 sudo

# 将用户添加到 docker 用户组
 sudo addgroup -a <username> docker
 sudo service docker restart
 # 退出终端,重新连接
 # 查看用户信息
 id <username>
 # 将用户从docker用户组中移除
 gpasswd -d <username> docker

1.3、docker 镜像源

修改 /etc/docker/daemon.json,添加镜像源

{
     "registry-mirrors":[
         "https://hub-mirror.c.163.com",
         "https://docker.mirrors.ustc.edu.cn",
         "https://registry.docker-cn.com"
     ]
 }

重启服务

sudo systemctl daemon-reload
 sudo systemctl start docker

2、docker 概念

2.1、docker 背景

docker 是容器化技术,针对的是应用及应用所依赖的环境做容器化。遵循单一原则,一个容器只运行一个主进程。若多个进程都部署在一个容器中,一个进程出问题所有进程宕掉。

docker 解决的问题

  • 解决了应用程序本地运行环境与生产运行环境不一致的问题
  • 解决了应用程序资源使用的问题,为每个程序指定内存分配和 cpu 分配
  • 快速拓展,弹性伸缩


2.2、docker 架构

docker 架构

  • 镜像 image:创建 docker 容器的模板
  • 容器 container:镜像创建的运行实例,一个容器运行一种服务
  • 仓库 repository:集中存放镜像文件

2.3、docker 与 vm

  • docker:容器运行载体,管理引擎(Go实现),复用本机OS
  • 虚拟机:操作系统虚拟化,硬件虚拟化 DevOps

3、docker 容器隔离

默认情况,容器使用系统的命名空间

# 查看进程命名空间
 sudo lsns -p <pid> --output-all

若希望容器使用 user 命名空间,则修改 /etc/docker/daemon.json,添加

// 开启 docker user 命名空间配置
 "userns-remap":"default"

重启 docker 服务

sudo systemctl daemon-reload
 sudo systemctl start docker

4、docker 命令

4.1、环境信息

# 显示 Docker 系统信息
 docker info
 # 显示 Docker 版本信息
 docker version

4.2、日志信息

# 从服务器获取实时事件
 docker events
 # 获取容器的日志
 docker logs
 # 查看指定镜像的创建历史
 docker history

4.3、容器命令

容器生命周期

# 创建并启动容器
 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 
 --name ' 指定容器名称
 -d     ' 后台运行容器
 -it    ' 前台运行容器,i交互,t终端。退出容器:exit 容器停止,ctrl+p+q 容器不停止
 -p     ' 发布容器端口到主机端口,主机:容器
 -v     ' 绑定数据卷,主机目录:容器目录
 # 启动容器
 docker start [OPTIONS] CONTAINER [CONTAINER...]
 # 重启容器
 docker restart [OPTIONS] CONTAINER [CONTAINER...]
 # 停止容器
 docker stop [OPTIONS] CONTAINER [CONTAINER...]
 # 杀掉容器
 docker kill [OPTIONS] CONTAINER [CONTAINER...]
 # 删除已停止的容器
 docker rm [OPTIONS] CONTAINER [CONTAINER...]
 # 删除停止的所有容器(管道:返回所有退出的容器的id)
 docker rm `docker ps -f status=exited -q`
 # 暂停|恢复容器中的所有进程
 docker pause CONTAINER [CONTAINER...]
 docker unpause CONTAINER [CONTAINER...]

容器运维命令

# 在运行的容器中执行命令
 docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
 -d  ' 后台运行
 -it ' 前台运行
 # 列出容器 
 docker ps [OPTIONS] 
 -a ' 查看所有容器
 -f ' 根据条件过滤显示的内容
 # 查看容器|镜像元数据
 docker inspect [OPTIONS] NAME|ID [NAME|ID...]
 # 查看容器中运行的进程
 docker top [OPTIONS] CONTAINER [ps OPTIONS]
 # 容器拷贝
 docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
 docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
 # 导入和导出容器
 docker export 容器ID > 文件名.tar
 cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
 # 检查容器相较于镜像的变化
 docker diff [OPTIONS] CONTAINER
 # 容器状态
 docker stats CONTAINER

4.4、镜像命令

# 使用 dockerfile 创建镜像,path 指 context
 docker build [OPTIONS] PATH | URL |
 -t '指定镜像名和标签
 -f '指定 dockerfile 路径
 -v '为容器挂载数据卷 主机:容器
 --build-arg '设置镜像创建时的变量
 --cache-from '指定镜像用作当前构建的缓存镜像
 --target '设置要生成的目标生成阶段
 # 列出本地镜像
 docker images 
 'REPOSITORY 仓库源  TAG:版本号  IMAGE ID:镜像ID   CREATED:创建时间  SIZE:大小
 # 虚悬镜像:仓库源和版本号为<none>:<none>
 # 原因:构建新镜像时,打了旧的标签,docker 移除旧镜像的标签
 # 查看所有悬空镜像
 docker images --filter dangling=true
 # 清除所有悬空镜像
 docker image prune
 # 删除镜像
 docker rmi [OPTIONS] IMAGE [IMAGE...]
 # 标记本地镜像,归入仓库
 docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
 # 保存镜像
 docker save [OPTIONS] IMAGE [IMAGE...]  
 docker save -o hello.tar hello-world:latest '-o 输出到文件
 # 导入镜像
 docker load [OPTIONS]
 docker load -i hello.tar 
 # 容器提交为镜像(保留现场)
 docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
 -m '提交描述信息"
 -a '作者

4.5、镜像仓库

# 登录|退出仓库
 docker login [OPTIONS] [SERVER]
 docker logout [OPTIONS] [SERVER]
 # 拉取镜像
 docker pull [OPTIONS] NAME[:TAG|@DIGEST]
 # 推送镜像
 docker push [OPTIONS] NAME[:TAG]
 # 从公共仓库查找镜像(docker hub)
 docker search --limit 5 镜像名

5、docker 镜像

镜像是一个只读的模板,内部是容器的系统运行环境:rootfs (根文件系统 root file system)。

5.1、镜像原理

  • 分层: 镜像采用分层文件系统构建,每一个镜像都由一组镜像组合而成。每一个镜像层都可以被需要的镜像所引用,实现了镜像之间共享镜像层的效果。
  • 写时复制:底层镜像层在多个容器间共享,每个容器启动时将所需要的镜像层以只读的方式挂载到一个挂载点。只读层上再覆盖一层读写层。在容器运行过程中产生的新文件将会写入到读写层,被修改过的底层文件会被复制到读写层并且进行修改,而老文件则被隐藏。
  • 联合挂载:在同一个挂载点同时挂载多个文件系统,从而使得容器的根目录看上去包含了各个镜像层的所有文件。
  • 内容寻址:根据镜像层内容计算校验和,生成一个内容哈希值,并使用该值来充当镜像层ID,索引镜像层。

如图所示,从上往下,对应关系:

  • merged:容器启动后,将镜像层和容器层,一起挂载到容器挂载点,形成一个完整的根目录
  • upperDir:容器层(可写层)
  • lowerDir:镜像层(只读层)

5.2、镜像分享

镜像分享步骤

  • 登录远程仓库: docker login
  • 打 tag: docker tag
  • 推送镜像: docker push

5.2.1、远程仓库

这里使用阿里云

镜像加速

弹性计算-容器镜像服务-镜像工具-镜像加速器

创建镜像仓库

控制台-容器镜像服务-个人实例-命名空间-创建仓库
 控制台-容器镜像服务-个人实例-访问凭证-设置登录密码

登录仓库

docker login --username=... registry.cn-hangzhou.aliyuncs.com

5.2.2、本地仓库

搭建私有注册中心

# 安装私有仓库镜像
 docker pull registry:latest
 mkdir -p $HOME/registry/
 mkdir -p $HOME/registry/auth
 mkdir -p $HOME/registry/data
 # 安装 apache httpd
 sudo apt install apache2-utils
 # 利用命令工具 htpasswd 生成 http 基本认证的密码文件
 htpasswd -Bbn jtz 123 > $HOME/registry/auth/htpasswd
 # 若启用了用户命名空间隔离,则需要修改目录owner和组
 sudo chown 165536:165536 -R registry
 # 开机启动 registry
 docker run -d -p 5000:5000 --name registry --restart=always -v $HOME/registry/data:/var/lib/registry -v $HOME/registry/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry
 # 添加服务信任
 vim /lib/systemd/system/docker.service
 # 修改启动项,添加 --insecure-registry ip:port,指定一个受信任的注册中心
 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.88.132:5000
 # 重启 docker 服务
 sudo systemctl daemon-reload 
 sudo systemctl restart docker
 # 测试
 # 登录
 docker login 192.168.88.132:5000
 # 打标签
 docker tag hello-world:latest 192.168.88.131:5000/hello:1.0.0
 # 推送
 docker push 192.168.88.132:5000/hello:1.0.0

6、dockerfile

dockerfile 是一个创建镜像所有命令的文本文件,每条指令创建一个镜像层,记录了镜像创建的流程。通过 docker build 命令,根据 dockerfile 的内容生成镜像。

6.1、docker build 流程

# 创建镜像,path 上下文路径
 docker build [OPTIONS] PATH
 -t '指定镜像名和标签
 -f '指定 dockerfile 路径
 --build-arg '设置镜像创建时的变量
 --cache-from '指定镜像用作当前构建的缓存镜像
 --target '设置要生成的目标生成阶段

docker build 命令的流程

  • 将 context 中的文件打包传递给 docker daemon
  • 向 docker server 发送 HTTP 请求,请求构建镜像,请求中包含了需要的 context 信息。
  • docker server 收到请求,开始构建镜像
  • 创建一个临时目录,并将 context 中的文件解压到该目录下。
  • 读取并解析 dockerfile,遍历指令,根据指令类型分发到不同的模块去执行。
  • docker 引擎为每条指令创建一个临时容器,在临时容器中执行指令,然后 commit 容器,生成一个新的镜像层。默认缓存已有的镜像层,提升效率。
  • 将所有指令构建出的镜像层合并,形成 build 的最后结果。最后一次 commit 生成的镜像 ID 就是最终的镜像 ID。

6.2、dockerfile 关键字

# 设置使用的基础镜像
 FROM 
 # 设置镜像作者
 MAINTAINER 
 # 指定执行的命令
 RUN         
 # 设置镜像标签
 LABEL   
 # 设置镜像暴露的端口
 EXPOSE      
 # 设置环境变量
 ENV     
 # 指定工作目录
 WORKDIR 
 # 设置容器的挂载卷
 VOLUME
 # 指定执行命令的用户和用户组
 USER 
 # 拷贝上下文。只复制目录内容,不包含目录本身
 ADD <src> <dest>    # 不能用于多阶段构建,此外,解压,url 拷贝文件
 COPY <src> <dest>   # 可用于多阶段构建 
 # 设置容器的启动命令
 CMD ["executable","param1","param2"]
 # 设置容器的入口程序,覆盖 CMD
 ENTRYPOINT ["executable","param1","param2"]
 # 设置编译镜像时加入的参数
 ARG     
 # 延迟构建命令的执行
 # 作为基础镜像,触发指令下游构建的上下文中执行。不影响当前构建,影响下游构建
 ONBUILD

6.3、多阶段构建

多阶段构建指的是一个 dockerfile 中允许出现多条 FROM 指令,每条 FROM 指令是一个构建阶段,前置阶段中的文件可以拷贝到其后的阶段,最终生成的镜像以最后一条 FROM 为准,之前的FROM 被抛弃。适用于分离编译环境和运行环境。

例:多阶段构建镜像

FROM golang:1.18 as stage0
 LABEL hello 1.0.0
 WORKDIR helloworld
 COPY ./helloworld ./
 RUN go env -w GOPROXY="https://proxy.golang.com.cn,https://goproxy.cn,direct"
 RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .
 FROM alpine as stage1
 COPY --from=stage0 /go/helloworld/app ./
 EXPOSE 80
 ENTRYPOINT ["./app""--param1=p1", "--param2=p2"]
 # CMD ["./app", "--param1=p1", "--param2=p2"]

对于多阶段构建,通过 docker build 命令的参数--target 指定需要重新构建的阶段。--cache-from 可以指定一个镜像作为缓存源,当构建过程中 dockerfile 指令与缓存镜像源指令匹配,则直接使用缓存镜像中的镜像层,从而加快构建进程。可以将缓存镜像推送到远程注册中心,提供给不同的构建过程使用,在使用前需要先 pull 到本地。

例:上述例子中的镜像,将第一阶段生成的镜像作为缓存镜像,第二阶段使用第一阶段的缓存镜像生成最终的镜像。

# 生成阶段1:缓存镜像
 docker build -t prehello:1.0.0 --target stage0 .
 # 生成阶段2:最终镜像
 docker build -t hello:1.0.0 --target stage1 --cache-from prehello:1.0.0 .

7、容器数据卷

docker 镜像由只读层(镜像层)+ 读写层(容器层)组合而来,提高了镜像构建、存储和分发的效率。但是产生了主机不方便访问容器中的文件,容器间的数据无法共享,删除容器时丢失数据等问题。为了解决这些问题,docker 引入了数据卷(volume)机制,其存在于容器的特定目录,该目录独立于联合文件系统,在主机中存在,为数据提供共享和持久化。

volume 的特点

  • volume 在容器创建时就会初始化
  • volume 能在不同的容器之间共享和重用
  • volume 对数据的操作会马上生效
  • volume 的生存周期独立于容器的生命周期

7.1、数据卷的命令

# 创建数据卷
 docker volume create
 # 查看数据卷
 docker volume inspect
 # 列出数据卷
 docker volume ls
 # 删除未使用的数据卷
 docker volume prune
 # 删除数据卷
 docker volume rm

7.2、创建数据卷

# 创建数据卷
 docker volume create --name vol_simple
 # 查看数据卷
 docker volume inspect vol_simple

7.3、挂载数据卷

挂载方式:具名挂载、匿名挂载、绑定宿主机目录挂载

# 1、具名挂载
 docker volume create --name vol_simple
 docker run -d -v vol_simple:/data ubuntu /bin/bash
 # 使用 docker inspect 查看挂载的位置信息 Mounts
 # 2、匿名挂载
 docker run -d -v /data ubuntu /bin/bash
 # 3、绑定挂载,绑定宿主机目录挂载(bind)
 docker run -d -v $HOME/data:/data ubuntu /bin/bash

权限:ro 只读,rw 读写(默认)

docker run -it -v $HOME/data:/data:ro -v vol_simple:/data1 -v /data2 ubuntu /bin/bash

通过 dockerfile 指定数据卷挂载

为保证 dockerfile 移植性,采用匿名挂载。volume 独立于 rootfs 的存储,镜像构建过程,临时生成的镜像层不会对挂载的 volume 进行保存。

FROM ubuntu
 # docker commit 提交的临时镜像不会对数据卷进行保存
 # 只有先创建目录,再挂载目录,主机目录的数据被复制到数据卷中
 RUN mkdir /data 
 VOLUME /data
 RUN echo hello >> /data/1.txt

7.4、共享数据卷

创建容器时,使用参数--volumes-from共享数据卷

# 创建带数据卷的容器
 docker run -d -it -v vol_simple:/vol_simple -v $HOME/data:/data -v $HOME/readOlny_data:/readOlny_data:ro --name share_data ubuntu /bin/bash
 # 创建新容器,共享数据卷
 docker run -d -it --volumes-from share_data --name volume_from ubuntu /bin/bash

7.5、删除数据卷

删除容器时不会删除数据卷对应的挂载目录,需要手动删除数据卷。

# 删除数据卷(具名和匿名)
 docker volume rm
 docker volume prune
 # 删除匿名数据卷
 docker rm -v    # 删除容器和挂载的数据卷
 docker run --rm # 容器停止,删除匿名数据卷
 # 绑定挂载
 rm -rf
相关实践学习
通过容器镜像仓库与容器服务快速部署spring-hello应用
本教程主要讲述如何将本地Java代码程序上传并在云端以容器化的构建、传输和运行。
Kubernetes极速入门
Kubernetes(K8S)是Google在2014年发布的一个开源项目,用于自动化容器化应用程序的部署、扩展和管理。Kubernetes通常结合docker容器工作,并且整合多个运行着docker容器的主机集群。 本课程从Kubernetes的简介、功能、架构,集群的概念、工具及部署等各个方面进行了详细的讲解及展示,通过对本课程的学习,可以对Kubernetes有一个较为全面的认识,并初步掌握Kubernetes相关的安装部署及使用技巧。本课程由黑马程序员提供。 &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
27天前
|
监控 NoSQL 时序数据库
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
190 77
|
8天前
|
搜索推荐 安全 数据安全/隐私保护
7 个最能提高生产力的 Docker 容器
7 个最能提高生产力的 Docker 容器
75 35
|
1月前
|
监控 Docker 容器
在Docker容器中运行打包好的应用程序
在Docker容器中运行打包好的应用程序
|
8天前
|
Ubuntu Linux 开发工具
docker 是什么?docker初认识之如何部署docker-优雅草后续将会把产品发布部署至docker容器中-因此会出相关系列文章-优雅草央千澈
Docker 是一个开源的容器化平台,允许开发者将应用程序及其依赖项打包成标准化单元(容器),确保在任何支持 Docker 的操作系统上一致运行。容器共享主机内核,提供轻量级、高效的执行环境。本文介绍如何在 Ubuntu 上安装 Docker,并通过简单步骤验证安装成功。后续文章将探讨使用 Docker 部署开源项目。优雅草央千澈 源、安装 Docker 包、验证安装 - 适用场景:开发、测试、生产环境 通过以上步骤,您可以在 Ubuntu 系统上成功安装并运行 Docker,为后续的应用部署打下基础。
docker 是什么?docker初认识之如何部署docker-优雅草后续将会把产品发布部署至docker容器中-因此会出相关系列文章-优雅草央千澈
|
1月前
|
Docker 容器
将本地的应用程序打包成Docker镜像
将本地的应用程序打包成Docker镜像
|
14天前
|
存储 Kubernetes 开发者
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
Docker 是一种开源的应用容器引擎,允许开发者将应用程序及其依赖打包成可移植的镜像,并在任何支持 Docker 的平台上运行。其核心概念包括镜像、容器和仓库。镜像是只读的文件系统,容器是镜像的运行实例,仓库用于存储和分发镜像。Kubernetes(k8s)则是容器集群管理系统,提供自动化部署、扩展和维护等功能,支持服务发现、负载均衡、自动伸缩等特性。两者结合使用,可以实现高效的容器化应用管理和运维。Docker 主要用于单主机上的容器管理,而 Kubernetes 则专注于跨多主机的容器编排与调度。尽管 k8s 逐渐减少了对 Docker 作为容器运行时的支持,但 Doc
79 5
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
|
19天前
|
NoSQL PHP MongoDB
docker push推送自己搭建的镜像
本文详细介绍了如何搭建和复盘两个Web安全挑战环境:人力资源管理系统和邮件管理系统。首先,通过Docker搭建MongoDB和PHP环境,模拟人力资源管理系统的漏洞,包括nosql注入和文件写入等。接着,复盘了如何利用这些漏洞获取flag。邮件管理系统部分,通过目录遍历、文件恢复和字符串比较等技术,逐步绕过验证并最终获取flag。文章提供了详细的步骤和代码示例,适合安全研究人员学习和实践。
44 3
docker push推送自己搭建的镜像
|
19天前
|
关系型数据库 应用服务中间件 PHP
实战~如何组织一个多容器项目docker-compose
本文介绍了如何使用Docker搭建Nginx、PHP和MySQL的环境。首先启动Nginx容器并查看IP地址,接着启动Alpine容器并安装curl测试连通性。通过`--link`方式或`docker-compose`配置文件实现服务间的通信。最后展示了Nginx配置文件和PHP代码示例,验证了各服务的正常运行。
44 3
实战~如何组织一个多容器项目docker-compose
|
14天前
|
Unix Linux Docker
CentOS停更沉寂,RHEL巨变限制源代:Docker容器化技术的兴起助力操作系统新格局
操作系统是计算机系统的核心软件,管理和控制硬件与软件资源,为用户和应用程序提供高效、安全的运行环境。Linux作为开源、跨平台的操作系统,具有高度可定制性、稳定性和安全性,广泛应用于服务器、云计算、物联网等领域。其发展得益于庞大的社区支持,多种发行版如Ubuntu、Debian、Fedora等满足不同需求。
40 4
|
23天前
|
Docker 容器