在数字化转型大潮中,容器技术以其轻量化、高效启动、标准化及高利用率等优势,成为现代应用部署与运维的基石。其本质是一种操作系统级别的虚拟化技术,通过打包应用程序及其环境为可移植的标准容器,实现“一次构建,处处运行”,显著提升开发、测试和部署效率,相比传统虚拟机技术更为高效。
本文将深入剖析容器核心技术原理,涵盖命名空间、控制组(Cgroups)等关键点,并详细解读主流容器引擎Docker的运行机制。同时,我们也将探讨Kubernetes(简称K8s)如何作为容器编排系统,有效管理和调度大规模容器集群。
此外,文章还将涉及容器安全策略设定、网络配置优化、存储方案选择等实践层面内容,旨在指导在实际环境中合理且安全地运用容器技术。最后,我们将揭示容器化对于DevOps流程改进、微服务架构落地以及CI/CD实践的重要推动价值。
A.容器技术概述
Container(容器)是一种便携式、轻量级的操作系统级虚拟化技术,它使用NameSpace隔离不同的软件运行环境,并通过镜像自包含软件的运行环境,从而使得容器可以很方便的在任何地方运行,由于容器体积小且启动快,因此可以在每个容器镜像中打包一个应用程序,这种一对一的应用镜像关系拥有很多好处,使用容器不需要与外部的基础架构环境绑定,因为每一个应用程序都不需要外部依赖,更不需要与外部的基础架构环境依赖,完美解决了从开发到生产环境的一致性问题。
容器技术需要解决的核心问题之一是运行时的环境隔离。容器的运行时环境隔离,目标是给容器构造一个无差别的运行时环境,用以在任意时间、任意位置运行容器镜像,这也是技术萌芽期的核心问题。
容器技术近 20 年的发展历史,大致可以将其分为四个历史阶段:
容器技术的整体表现为如下架构:
B.Docker起源与优势
Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。Docker 项目后来还加入了 Linux 基金会,并成立推动 开放容器联盟(OCI)。
进入技术迸发期后,Docker 核心创新——容器镜像(docker image),一种新型的应用打包、分发和运行机制。
容器镜像将应用运行环境,包括代码、依赖库、工具、资源文件和元信息等,打包成一种操作系统发行版无关的不可变更软件包。容器镜像打包了整个容器运行依赖的环境,以避免依赖运行容器的服务器的操作系统,从而实现 “build once,run anywhere”。
容器镜像一旦构建完成,就变成 read only,成为不可变基础设施的一份子。操作系统发行版无关,核心解决的是容器进程对操作系统包含的库、工具、配置的依赖,但是容器镜像无法解决容器进程对内核特性的特殊依赖。这个在实际使用容器的过程中也经常跳进这个大坑。
从 2017 年开始,各大云厂商开始试水容器服务及进步的云原生服务。从目前的商业形态看,容器相关的公共云服务大致可以划分为三种形态:
-
通用容器编排服务。在容器编排系统三国杀结果出来以前,基于多方下注策略构建的容器编排服务系统。其中 AWS 是自研的编排系统,Azure 的 ACS 同时支持 Docker Swarm、DC/OS 和 Kubernetes,阿里云 ACS 则是支持 Docker swarm 和 Kubernetes。Google 和华为则是坚定支持 Kubernetes 而未推出支持其它容器编排系统的容器服务。随着 Kubernetes 容器编排出现江湖,这条路线的容器服务日渐式微,Azure 更是在今年初直接终止了 ACS 服务。
-
Kubernetes 容器编排服务。Google 是理所当然最早试水 Kubernetes 容器编排服务的大厂,也较早开展了 K8s 容器编排服务。随着 2017 年各大厂在 CNCF 这张谈判桌上达成了 Kubernetes 兼容性认证流程,Kubernetes 编排服务市场迎来一轮大爆发,到 2018 年各大云厂商的 K8s 容器编排服务就完整就位了。
-
Serverless 容器实例服务。从 2017 年开始,行业开始试水 Serverless 容器实例服务,把用户从维护容器基础设施的繁重任务中解放出来从而聚焦业务本身。Google Cloud Run 核心目标是支持 Knative,所以其使用形态上附加了不少约束条件。
从Docke(容器)与虚拟机的对比辩证地看容器优势
容器和虚拟机都是常用的隔离系统,但它们的设计目标和实现方式有所不同。
容器是轻量级虚拟化技术,可以在同一主机上同时运行多个隔离的进程,而不需要为每个进程创建独立的虚拟机实例。容器通常由操作系统内核、进程和文件系统等基础组件构成,这些组件被抽象出来并在共享的内核上运行,因此容器比虚拟机更加轻量、高效和灵活。容器可以通过运行时环境、网络和存储等抽象层进行隔离,这些抽象层可以根据应用程序的需求进行配置,从而提供更好的灵活性和可扩展性。容器的优点包括:
-
高效性:容器是轻量级虚拟化技术,可以在同一主机上同时运行多个隔离的进程,从而提高系统的利用率和资源利用效率。
-
灵活性:容器可以通过运行时环境、网络和存储等抽象层进行隔离,从而提供更好的灵活性和可扩展性。
-
可移植性:容器可以在不同的操作系统和平台上运行,从而提高应用程序的可移植性和跨平台性。
虚拟机是一种更加传统的虚拟化技术,可以在独立的虚拟机实例上运行多个操作系统和应用程序。虚拟机通常包括操作系统内核、虚拟硬件和运行时环境等组件,这些组件在虚拟机实例上独立运行,因此虚拟机比容器更加安全、稳定和可靠。虚拟机的优点包括:
-
安全性:虚拟机提供了更加严格的隔离和安全机制,可以避免不同应用程序之间的数据冲突和交叉污染。
-
稳定性:虚拟机提供了独立的操作系统和硬件环境,可以避免不同应用程序之间的资源冲突和错误,从而提高系统的稳定性和可靠性。
-
可定制性:虚拟机可以通过安装和配置不同的操作系统和应用程序来满足不同的需求,从而提供更好的可定制性和可配置性。
总的来说,容器和虚拟机各有优缺点,应根据实际需求选择适合的隔离技术。容器适合轻量级、高效和可移植的应用程序,而虚拟机适合安全、稳定和可定制的应用程序。
C.Docker基本概念与架构
Docker提供了一个简单的方式来部署和管理应用程序,因为它将应用程序及其依赖项打包在一个独立的、可移植的容器中。以下是Docker的基本概念和架构:
-
Docker镜像:Docker镜像是一个包含应用程序及其依赖项的静态或动态二进制文件,它是Docker容器的基础。一个Docker镜像可以包含一个或多个应用程序及其依赖项,例如文件系统、库和系统工具。
-
Docker容器:Docker容器是一个可执行的运行时环境,它是从一个或多个Docker镜像中创建的。一个Docker容器可以运行一个应用程序及其依赖项,并提供一些附加的功能,例如网络和存储。
-
Docker仓库:Docker仓库是一个公共或私有的数据库,用于存储和管理Docker镜像。一个Docker仓库可以存储大量的镜像,这些镜像可以通过Docker Hub或其他私有仓库来获取。其中Docker Hub就是一个公共的Docker仓库,它是由Docker官方维护的。它是一个中心化的镜像存储库,可以让开发人员从中获取和发布镜像。Docker Hub也提供了一些基本的工具,例如Docker Build、Docker Run和Docker Commit等。
-
Docker命令行工具:Docker命令行工具是用于管理Docker容器的一组命令行工具。它提供了一些常用的操作,例如创建容器、启动容器、停止容器、删除容器等。详情请见第2章节。
-
Docker Compose:Docker Compose是一个用于定义和运行多个Docker容器的工具。它可以帮助开发人员一次性定义多个容器,并且可以管理这些容器的通信和依赖关系。
-
Docker Swarm:Docker Swarm是一个Docker容器的分布式工作负载管理系统。它可以帮助管理多个Docker容器,并提供一些高级功能,例如自动伸缩和负载均衡。
A.Docker的安装与配置
Docker 目前分为 Community Edition (CE) 和 Enterprise Edition (EE) 两个版本。日常学习开发考虑使用CE版本。而 Docker Community Edition (CE) 又分为 Stable / Test / Nightly 三个版本,如果不需要最新的特性,那么 Stable 是比较合适的选择。
Windows安装
Docker Desktop是适用于Windows的Docker桌面,是Docker设计用于在Windows 10上运行。它是一个本地 Windows 应用程序,为构建、交付和运行dockerized应用程序提供易于使用的开发环境。Docker Desktop for Windows 使用 Windows 原生 Hyper-V 虚拟化和网络,是在 Windows 上开发 Docker 应用程序的最快、最可靠的方式。Windows 版 Docker 桌面支持运行 Linux 和 Windows Docker 容器。
官方下载地址:Docker Desktop Installer.exe 下载地址
国内镜像:Windows安装包下载地址
启用Hyper-V以在 Windows 10上创建虚拟机:
详情参考微软官方教程
注意:可以通过多种方式启用 Hyper-V,包括使用 Windows 10 控制面板、PowerShell(Hyper-V 作为可选功能内置于 Windows -- 无需下载 Hyper-V)。
1、使用 PowerShell 启用 Hyper-V
以管理员身份打开 PowerShell 控制台,运行以下命令:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
2、通过控制面板“设置”启用 Hyper-V 角色
-
右键单击 Windows 按钮并选择“应用和功能”。
-
选择相关设置下右侧的“程序和功能”。
-
选择“打开或关闭 Windows 功能”。
-
选择“Hyper-V”,然后单击“确定”。
注意:安装完成后,系统会提示你重新启动计算机。
接着安装docker
Centos安装
1. yum安装docker服务:yum install -y docker
2. 启动docker服务 :
systemctl start docker
systemctl enable docker
systemctl status docker
3. 安装docker-compose
curl -L https://github.com/docker/compose/releases/download/v2.14.1/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
或者: curl -L http://mirror.azure.cn/docker-toolbox/linux/compose/v2.14.1/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
4. 开启你的docker之旅吧!
docker run ...
Docker配置
安装后,还需要进行配置,此处的配置远程访问权限如果存在漏洞则是后文讲解docker未授权访问的来源
docker配置镜像源地址:可参考Dockcer上传hub和配置国内镜像源 - raokun - 博客园 (cnblogs.com)
临时使用指定镜像源地址,可以使用如下命令:
docker pull 镜像名称 -–registry-mirror=国内镜像源地址
以linux环境为例,如果永久配置 Docker 国内镜像源,可以按照以下步骤进行:
-
打开 Docker 配置文件 /etc/docker/daemon.json,如果该文件不存在,则可以创建该文件。
-
在该配置文件中添加以下内容:
{
"registry-mirrors": ["https://hub-mirror.c.163.com"]
}
如果要使用多个镜像源,可以在 "registry-mirrors" 数组中添加多个镜像源地址,以英文逗号分隔。
-
保存配置文件,并重启 Docker 服务,以使配置生效。可以使用以下命令重启 Docker 服务:
sudo systemctl restart docker
如果使用的是 Ubuntu 14.04 等旧版系统,可以使用以下命令重启 Docker 服务:
sudo service docker restart
-
配置完成后,可以使用 docker pull 命令测试是否成功使用了国内镜像源。例如,可以使用以下命令拉取官方的 Ubuntu 镜像:
docker pull ubuntu
如果使用了正确的国内镜像源地址,镜像的下载速度应该比官方源快很多。
docker配置远程访问权限:
1、编辑docker.server文件
vi /usr/lib/systemd/system/docker.service
找到 [Service] 节点,修改 ExecStart 属性,增加
-H tcp://0.0.0.0:2375
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375
这样相当于对外开放的是 2375 端口,当然也可以根据自己情况修改成其他的。
2、重新加载Docker配置生效
systemctl daemon-reload systemctl restart docker
通过浏览器访问 2375 测试一下,格式为:http://ip:2375/version
B.Docker镜像管理
拉取命令:docker pull xxx:
查看镜像:docker images
运行镜像:docker run -p 8080:80 nginx:1.19 -d
查看容器:docker ps
接下来使用dockefile来进行启动容器,新建文件:
FROM centos:8
MAINTAINER [email protected]
#安装相关工具
#RUN apt-get update && apt-get install vim -y
RUN yum update -y
RUN yum -y install vim && yum -y install net-tools && yum -y install wget
#安装arthas
RUN mkdir /home/arthas && wget https://alibaba.github.io/arthas/arthas-boot.jar
# 设置系统编码,不然web接口或日志中文会出现乱码
ENV LANG C.UTF-8
#工作目录
WORKDIR /root
#在/usr/local下创建jdk目录,用来存放jdk文件
RUN mkdir /usr/local/jdk
#在/usr/local/下创建tomcat目录,用来存放tomcat
RUN mkdir /usr/local/tomcat
#在/usr/local下创建maven目录,用来存放maven文件
RUN mkdir /usr/local/maven
ADD jdk-8u251-linux-x64.tar.gz /usr/local/jdk
ADD apache-tomcat-9.0.36.tar.gz /usr/local/tomcat
ADD apache-maven-3.6.3-bin.tar.gz /usr/local/maven
#设置环境变量
ENV JAVA_HOME /usr/local/jdk/jdk1.8.0_251
ENV JRE_HOME $JAVA_HOME/jre
ENV CATALINA_HOME /usr/local/tomcat/apache-tomcat-9.0.36
ENV MAVEN_HOME /usr/local/maven/apache-maven-3.6.3
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$MAVEN_HOME/bin
#创建项目目录
RUN mkdir /home/www && mkdir /home/www/file
#maven的settings.xml
COPY settings.xml /usr/local/maven/apache-maven-3.6.3/conf/
#tomcat的server.xml
COPY server.xml /usr/local/tomcat/apache-tomcat-9.0.36/conf/
#拷贝项目到Tomcat的运行目录下
#COPY /dockerproject/BJ-SBF-TZGL-0.0.1-SNAPSHOT.war /usr/local/tomcat/apache-tomcat-9.0.36/webapps
#开启内部服务端口
EXPOSE 8080
#启动tomcat服务器
#CMD ["./usr/local/tomcat/apache-tomcat-9.0.36/bin/catalina.sh","run"]
#执行start.sh并打印日志
ENTRYPOINT /usr/local/tomcat/apache-tomcat-9.0.36/bin/startup.sh && tail -f /usr/local/tomcat/apache-tomcat-9.0.36/logs/catalina.out
(在Dockerfile所在的目录执行,webtomcat9 代表执行完的容器名称,这个 . 就代表当前目录)
执行:
docker build -t webtomcat9 .
启动容器:准备一个shell启动脚本(为了方便,不准备也可以)
webstart.sh
echo "启动WEB环境容器-开始"
docker run -d -p 8080:8080 --name webtomcat -v /home/docker/server/dockerproject:/usr/local/tomcat/apache-tomcat-9.0.36/webapps -v /home/docker/server/dockerprojectfile:/home/www/file --restart=always webtomcat9
docker logs webtomcat
echo "启动WEB环境容器-成功"
执行启动脚本:
sh webstart.sh
查看容器是都正常启动
docker ps
docker logs webtomcat
至此,项目启动成功
C.Docker容器管理
启动容器:使用docker run命令启动一个容器,同时指定镜像名称。
docker run hello-world
上述命令将下载并运行hello-world镜像。如果本地不存在该镜像,Docker将自动从Docker Hub下载。
列出运行中的容器:使用docker ps命令列出当前正在运行的容器。
docker ps
如果需要显示所有容器(包括停止的),可以使用-a选项。
docker ps -a
停止容器:使用docker stop命令停止运行中的容器。
docker stop <container_id>
启动已停止的容器:使用docker start命令启动一个已停止的容器。
docker start <container_id>
重启容器:使用docker restart命令重启容器。
docker restart <container_id>
查看容器详细信息:使用docker inspect命令查看容器的详细信息。
docker inspect <container_id>
查看容器日志:使用docker logs命令查看容器的日志信息。
docker logs <container_id>
上述命令将显示容器的标准输出日志。如果需要实时查看日志,可以使用-f选项:docker logs -f <container_id>
进入运行中的容器:使用docker exec命令进入正在运行的容器。
docker exec -it <container_id> /bin/bash
上述命令中,-it选项允许交互式访问,/bin/bash是要执行的命令,你也可以替换成其他Shell。
复制文件到容器:使用docker cp命令将本地文件复制到容器中。
docker cp /local/path/file.txt <container_id>:/container/path/file.tx
t
从容器复制文件到本地
反之,可以使用docker cp命令将容器中的文件复制到本地。
docker cp <container_id>:/container/path/file.txt /local/path/file.txt
tD.Docker网络管理
Docker本身有4种网络工作模式,和一些自定义网络模式,在安装 Docker 时,默认会自动创建 bridge 、 none 、 host
-
Bridge:此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
-
None:该模式关闭了容器的网络功能。
-
host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
-
Container模式:使用 --net=container:NAME_or_ID 指定。
E.Docker存储卷管理
不做赘述,参考:
https://www.cnblogs.com/along21/p/10237219.htm
F.Docker安全风险来源
Docker容器的安全风险主要来源于以下几个方面:
-
容器隔离问题:
-
内核共享:Docker容器共享主机操作系统的内核,这意味着一个容器内的漏洞或攻击可能导致其他容器或宿主机受到影响。例如,如果存在内核级别的安全漏洞,攻击者可能利用这些漏洞逃逸出容器,访问到宿主机或其他容器的数据。
-
权限管理与配置错误:
-
默认权限设置不当可能会导致容器获得不必要的访问权限,包括对敏感文件和网络资源的访问。
-
由于容器间没有完全物理隔离,恶意容器可能会通过资源共享等方式进行干扰或攻击其他容器。
-
镜像漏洞:
-
Docker镜像是层层构建的,若基础镜像或应用层包含已知安全漏洞,将直接影响基于此镜像的所有容器。因此需要定期扫描和更新镜像以修复漏洞。
-
不安全的API和服务暴露:
-
如果容器中运行的服务未正确配置安全措施(如防火墙规则、最小化端口暴露等),则可能导致未经授权的外部访问。
-
数据持久性与保密性:
-
数据在容器间的持久存储和传输时,如果没有正确的加密和隔离手段,可能存在数据泄露的风险。
-
供应链攻击:
-
下载并使用非官方或不受信任来源的Docker镜像,可能导致恶意代码注入,影响容器安全性。
-
版本漏洞:
-
Docker引擎本身以及相关的工具和依赖组件可能存在安全漏洞,需要及时更新以确保安全。
为了缓解上述安全风险,应采取一系列防范措施,包括但不限于:
-
使用最小权限原则配置容器
-
定期更新容器及所有依赖项
-
只从可信源下载镜像
-
对容器进行细粒度的网络隔离和限制
-
使用安全工具审查镜像
-
应用安全最佳实践,如不可变基础设施策略、强制执行安全策略等。
Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。使用前面介绍的Dockerfile我们很容易定义一个单独的应用容器。然而在日常开发工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器;再比如在分布式应用一般包含若干个服务,每个服务一般都会部署多个实例。如果每个服务都要手动启停,那么效率之低、维护量之大可想而知。这时候就需要一个工具能够管理一组相关联的的应用容器,这就是Docker Compose。
通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose有2个重要的概念:
-
项目(Project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
-
服务(Service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
-
从Python 3.7的镜像开始构建一个容器镜像。
-
复制src(即compose_test/src)目录到容器中的/opt/src目录。
-
将容器的工作目录设置为/opt/src(通过docker exec -it your_docker_container_id bash 进入容器后的默认目录)。
-
安装Python依赖关系。
-
将容器的默认命令设置为python app.py。
-
使用当前docker-compose.yml文件所在目录的上级目录(compose_test/Dockerfile)中的Dockerfile构建映像。
-
将容器上的暴露端口5000映射到主机上的端口5000。 我们使用Flask Web服务器的默认端口5000。
-
redis服务使用从Docker Hub提取的官方redis镜像3.0.7版本。
-
核心层:Kubernetes 最核心的功能,对外提供 API 构建高层的应用,对内提供插件式应用执行环境
-
应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS 解析等)
-
管理层:系统度量(如基础设施、容器和网络的度量),自动化(如自动扩展、动态 Provision 等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy 等)
-
接口层:kubectl 命令行工具、客户端 SDK 以及集群联邦
-
生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴
-
Kubernetes 外部:日志、监控、配置管理、CI、CD、Workflow、FaaS、OTS 应用、ChatOps 等
-
Kubernetes 内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等
-
配置错误:
-
不正确的权限分配:例如,通过不当的RBAC规则,可能会给不应拥有高级别权限的用户或服务账户过多的访问权限。
-
网络策略配置不足:没有合适的网络策略可能导致未授权的网络访问或者攻击者能够轻易在Pod间进行横向移动。
-
不安全的默认设置:Kubernetes的部分配置可能在默认情况下不够安全,需要集群管理员手动更改以提高安全性。
-
API Server漏洞:
-
API服务器是Kubernetes的核心组件,任何对API server的攻击都有可能影响整个集群。例如,未经身份验证或授权的访问、拒绝服务攻击等。
-
Secret管理不善:
-
如果 Secrets (如密码、密钥等敏感信息)暴露、误配置或存储不当,可能会被恶意使用者获取并用于非法目的。
-
镜像安全问题:
-
使用含有恶意软件或漏洞的容器镜像,可能导致攻击者在运行时入侵集群中的Pod。
-
容器逃逸漏洞:
-
容器内核漏洞或其他安全弱点可以被利用来实现逃逸到宿主机或者其他容器,从而破坏集群安全。
-
节点安全性:
-
节点级别的安全措施不足,例如操作系统补丁更新不及时、未禁用不必要的服务端口等。
-
不受管控的API访问:
-
Kubernetes API 的开放性意味着如果不受控制地暴露在外网环境中,有可能遭受恶意访问和操作。
-
第三方插件及工具风险:
-
使用了带有已知安全漏洞的第三方插件或者工具,比如Helm 2在其生命周期中的一些阶段由于缺乏内置的RBAC支持而存在安全风险。
-
日志与审计缺失:
-
缺乏有效的日志记录和审计机制,使得安全事件发生后难以追溯和定位问题。
-
内部通信加密不足:
-
集群内部的服务间通信如果没有充分加密,可能导致数据泄露。
试用ing
通过docker-compose构建一个在docker中运行的基于python flask框架的web应用。
注意:确保你已经安装了Docker Engine和Docker Compose。 您不需要安装Python或Redis,因为这两个都是由Docker镜像提供的。
Step 1: 定义python应用
1 .创建工程目录
mkdir compose_test
cd compose_test
mkdir src # 源码文件夹
mkdir docker # docker配置文件夹
目录结构如下:
└── compose_test
├── docker
│ └── docker-compose.yml
├── Dockerfile
└── src
├── app.py
└── requirements.txt
2 .在compose_test/src/目录下创建python flask应用
compose_test/src/app.py文件。
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.n'.format(count)
3 .创建python 需求文件
compose_test/src/requirements.txt
flask
redis
Step 2: 创建容器的Dockerfile文件
一个容器一个Dockerfile文件,在compose_test/目录中创建Dockerfile文件:
FROM python:3.7
COPY src/ /opt/src
WORKDIR /opt/src
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Dockerfile文件告诉docker了如下信息:
Step 3: 定义docker-compose脚本
在compose_test/docker/目录下创建docker-compose.yml文件,并在里面定义服务,内容如下:
version: '3'
services:
web:
build: ../
ports:
"5000:5000"
redis:
image: redis:3.0.7
这个compose文件定义了两个服务,即定义了web和redis两个容器。
web容器:
redis容器:
Step 4: 使用Compose构建并运行您的应用程序
在compose_test/docker/目录下执行docker-compose.yml文件:
docker-compose up
# 若是要后台运行: $ docker-compose up -d
# 若不使用默认的docker-compose.yml 文件名:
docker-compose -f server.yml up -d
然后在浏览器中输入http://0.0.0.0:5000/查看运行的应用程序即可。
A.k8s介绍
Kubernetes,从官方网站上可以看到,它是一个工业级的容器编排平台。Kubernetes 这个单词是希腊语,它的中文翻译是“舵手”或者“飞行员”。在一些常见的资料中也会看到“ks”这个词,也就是“K8s”,它是通过将 8 个字母“ubernete ”替换为“8”而导致的一个缩写。
Kubernetes 为什么要用“舵手”来命名呢?大家可以看一下这张图:
这是一艘载着一堆集装箱的轮船,轮船在大海上运着集装箱奔波,把集装箱送到它们该去的地方。我们之前其实介绍过一个概念叫做 container,container 这个英文单词也有另外的一个意思就是“集装箱”。Kubernetes 也就借着这个寓意,希望成为运送集装箱的一个轮船,来帮助我们管理这些集装箱,也就是管理这些容器。
这个就是为什么会选用 Kubernetes 这个词来代表这个项目的原因。更具体一点地来说:Kubernetes 是一个自动化的容器编排平台,它负责应用的部署、应用的弹性以及应用的管理,这些都是基于容器的。
B.k8s架构
Kubernetes 设计理念和功能其实就是一个类似 Linux 的分层架构,如下图所示
Kubernetes使用Pod来管理容器,每个Pod可以包含一个或多个紧密关联的容器,Pod是一组紧密关联的容器集合,它们共享PID、IPC、Network 和UTS Namespace,是Kubernetes调度的基本单位,Pod内的多个容器共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。Pod 是 Kubernetes 集群中所有业务类型的基础,可以看作运行在 Kubernetes 集群中的小机器人,不同类型的业务就需要不同类型的小机器人去执行。
C.核心概念
Node是Pod真正运行的主机,可以是物理机,也可以是虚拟机,为了管理Pod每个Node节点上至少要运行Container Runtime(比如docker或者rkt)、 Kubelet和Kube-proxy服务
D.k8s安装
跟随下文内容一步步执行即可:
// 以双节点为例
192.168.1.2
192.168.1.3
准备
若未明确说明,均为所有主机都操作
设置主机名以及hosts文件
设置主机名
# 分别设置为master、node1
hostnamectl set-hostname master
hostnamectl set-hostname node1
修改hosts(两主机运行)
192.168.1.2 master
192.168.1.3 node1
关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
关闭SELINUX
# 临时关闭
setenforce 0
# 永久关闭
vi /etc/selinux/config
#SELINUX修改为disabled
SELINUX=disabled
关闭swap
swapoff -a
sed -i '/swap/s/^(.*)$/#1/g' /etc/fstab
配置系统参数
# 制作配置文件
$ cat > /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
EOF
# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf
安装依赖
yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp
安装docker
yum remove docker docker-common docker-selinux docker-engine
yum install -y yum-utils device-mapper-persistent-data lvm2
wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
yum install docker-ce
# 安装指定版本的docker,比如17.03.2-ce
yum list docker-ce --showduplicates |sort -r
image
安装指定版本
yum install --setopt=obsoletes=0 docker-ce-selinux-17.03.2.ce-1.el7.centos docker-ce-17.03.2.ce-1.el7.centos -y
启停docker
systemctl start docker
systemctl enable docker
更改docker的cgroup-driver
# 查看
docker info | grep -i cgroup
# 默认是cgroup
# 更改为systemd
vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 重新启动docker
systemctl restart docker
安装kubeadm、kubelet、kubectl
以安装v1.11.2版本为例
配置源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
查找版本号并安装
yum makecache fast
yum list kubeadm --showduplicates | sort -r
# 其他类似
yum install kubeadm-1.11.2-0 kubelet-1.11.2-0 kubectl-1.11.2-0 -y
# 最新版可以直接使用
yum install kubeadm kubelet kubectl -y
开机自动启动kubelet
systemctl enable kubelet
systemctl start kubelet # 此时kubelet状态不是Starting,可以不用纠结
准备必要的镜像
查看必须要安装的镜像
$ kubeadm config images list --kubernetes-version v1.11.2
k8s.gcr.io/kube-apiserver-amd64:v1.11.2
k8s.gcr.io/kube-controller-manager-amd64:v1.11.2
k8s.gcr.io/kube-scheduler-amd64:v1.11.2
k8s.gcr.io/kube-proxy-amd64:v1.11.2
k8s.gcr.io/pause:3.1
k8s.gcr.io/etcd-amd64:3.2.18
k8s.gcr.io/coredns:1.1.3
各个节点安装镜像脚本
#!/bin/bash
images=(
kube-apiserver-amd64:v1.11.2
kube-controller-manager-amd64:v1.11.2
kube-scheduler-amd64:v1.11.2
kube-proxy-amd64:v1.11.2
pause:3.1
etcd-amd64:3.2.18
coredns:1.1.3
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/${imageName}
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/${imageName} k8s.gcr.io/${imageName}
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/${imageName}
done
初始化集群(只master节点执行)
初始化
kubeadm init --kubernetes-version=v1.11.2 --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.1.2 --token-ttl 0
--token-ttl:设置为0表示生成的token不过期
记住最下面的一行命令行,类似:
kubeadm join 192.168.1.2:6443 --token hu2clf.898he8fnu64w3fur --discovery-token-ca-cert-hash sha256:2a196bbd77e4152a700d294a666e9d97336d0f7097f55e19a651c19e03d340a4
允许使用kubectl访问集群
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
节点加入集群(在node节点上执行)
kubeadm join 192.168.1.2:6443 --token hu2clf.898he8fnu64w3fur --discovery-token-ca-cert-hash sha256:2a196bbd77e4152a700d294a666e9d97336d0f7097f55e19a651c19e03d340a4
重新创建集群
kubeadm reset
kubeadm init xxx.xxxxx
安装网络插件flannel
mkdir -p ~/k8s/
cd ~/k8s
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# vi kube-flannel.yml,将里面的Network网段修改为跟上面kubeadm init后面紧跟的--pod-network-cidr一样的网段,不然会报错
kubectl apply -f kube-flannel.yml
查看状态
kubectl get pod --all-namespaces
kubectl get nodes
设置master node参与工作负载(只在master节点执行)
允许master节点部署pod,使用命令如下:
kubectl taint nodes --all node-role.kubernetes.io/master-
输出如下
node "k8s" untainted
# 输出error: taint “node-role.kubernetes.io/master:” not found错误忽略。
禁止master部署pod
kubectl taint nodes k8s node-role.kubernetes.io/master=true:NoSchedule
集群中移除Node
在master节点上执行
kubectl drain node1 --delete-local-data --force --ignore-daemonsets
kubectl delete node node1
在node1上执行
kubeadm reset
ifconfig cni0 down
ip link delete cni0
ifconfig flannel.1 down
ip link delete flannel.1
rm -rf /var/lib/cni/
其他
重新创建join的token
kubeadm token create --print-join-command
更为详细的编排指导,在此不再赘述,可参考:
https://developer.aliyun.com/article/1354891?spm=a2c6h.12873639.article-detail.45.37335d9d7Lk5OP
https://developer.aliyun.com/article/1354900?spm=a2c6h.12873639.article-detail.39.37335d9d7Lk5OP
E.K8S的安全风险来源
Kubernetes(简称K8s)的安全风险来源多种多样,涉及集群的各个层次和组件,以下是一些主要的风险来源:
综上所述,保障Kubernetes安全需要系统化地评估和处理这些风险源,实施严格的访问控制、持续监控以及遵循最佳实践来进行安全管理。
以上就是对容器、docker和k8s的基础讲解,研究容器安全是个循序渐进的过程,即使我们在日后深入容器漏洞研究,也会不断加深对基础架构和原理的学习。请期待我们之后的分享,感谢~
我们在知识大陆的帮会也在参加官方年终活动,敬请参加:
原文始发于微信公众号(东方隐侠安全团队):第二节:容器基础知识
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论