分类 容器与云 下的文章

搭建一个通过容器分发应用的可复用系统可能很复杂,但这儿有个好方法。

一个用于将源代码转换成可运行的应用的构建系统是由工具和流程共同组成。在转换过程中还涉及到代码的受众从软件开发者转变为最终用户,无论最终用户是运维的同事还是部署的同事。

在使用容器搭建了一些构建系统后,我觉得有一个不错的可复用的方法值得分享。虽然这些构建系统被用于编译机器学习算法和为嵌入式硬件生成可加载的软件镜像,但这个方法足够抽象,可用于任何基于容器的构建系统。

这个方法是以一种易于使用和维护的方式搭建或组织构建系统,但并不涉及处理特定编译器或工具容器化的技巧。它适用于软件开发人员构建软件,并将可维护镜像交给其他技术人员(无论是系统管理员、运维工程师或者其他一些头衔)的常见情况。该构建系统被从终端用户中抽象出来,这样他们就可以专注于软件。

为什么要容器化构建系统?

搭建基于容器的可复用构建系统可以为软件团队带来诸多好处:

  • 专注:我希望专注于应用的开发。当我调用一个工具进行“构建”时,我希望这个工具集能生成一个随时可用的二进制文件。我不想浪费时间在构建系统的查错上。实际上,我宁愿不了解,或者说不关心构建系统。
  • 一致的构建行为:无论在哪种使用情况下,我都想确保整个团队使用相同版本的工具集并在构建时得到相同的结果。否则,我就得不断地处理“我这咋就是好的”的麻烦。在团队项目中,使用相同版本的工具集并对给定的输入源文件集产生一致的输出是非常重要。
  • 易于部署和升级:即使向每个人都提供一套详细说明来安装一个项目的工具集,也可能会有人翻车。问题也可能是由于每个人对自己的 Linux 环境的个性化修改导致的。在团队中使用不同的 Linux 发行版(或者其他操作系统),情况可能还会变得更复杂。当需要将工具集升级到下一版本时,问题很快就会变得更糟糕。使用容器和本指南将使得新版本升级非常简单。

对我在项目中使用的构建系统进行容器化的这些经验显然很有价值,因为它可以缓解上述问题。我倾向于使用 Docker 作为容器工具,虽然在相对特殊的环境中安装和网络配置仍可能出现问题,尤其是当你在一个使用复杂代理的企业环境中工作时。但至少现在我需要解决的构建系统问题已经很少了。

漫步容器化的构建系统

我创建了一个教程存储库,随后你可以克隆并检查它,或者按照本文内容进行操作。我将逐个介绍存储库中的文件。这个构建系统非常简单(它运行 gcc),从而可以让你专注于这个构建系统结构上。

构建系统需求

我认为构建系统中有两个关键点:

  • 标准化构建调用:我希望能够指定一些形如 /path/to/workdir 的工作目录来构建代码。我希望以如下形式调用构建:
./build.sh /path/to/workdir

为了使得示例的结构足够简单(以便说明),我将假定输出也在 /path/to/workdir 路径下的某处生成。(否则,将增加容器中显示的卷的数量,虽然这并不困难,但解释起来比较麻烦。)

  • 通过 shell 自定义构建调用:有时,工具集会以出乎意料的方式被调用。除了标准的工具集调用 build.sh 之外,如果需要还可以为 build.sh 添加一些选项。但我一直希望能够有一个可以直接调用工具集命令的 shell。在这个简单的示例中,有时我想尝试不同的 gcc 优化选项并查看效果。为此,我希望调用:
./shell.sh /path/to/workdir

这将让我得到一个容器内部的 Bash shell,并且可以调用工具集和访问我的工作目录(workdir),从而我可以根据需要尝试使用这个工具集。

构建系统的架构

为了满足上述基本需求,这是我的构架系统架构:

 title=

在底部的 workdir 代表软件开发者用于构建的任意软件源码。通常,这个 workdir 是一个源代码的存储库。在构建之前,最终用户可以通过任何方式来操纵这个存储库。例如,如果他们使用 git 作为版本控制工具的话,可以使用 git checkout 切换到他们正在工作的功能分支上并添加或修改文件。这样可以使得构建系统独立于 workdir 之外。

顶部的三个模块共同代表了容器化的构建系统。最左边的黄色模块代表最终用户与构建系统交互的脚本(build.shshell.sh)。

在中间的红色模块是 Dockerfile 和相关的脚本 build_docker_image.sh。开发运营者(在这个例子中指我)通常将执行这个脚本并生成容器镜像(事实上我多次执行它直到一切正常为止,但这是另一回事)。然后我将镜像分发给最终用户,例如通过 容器信任注册库 container trusted registry 进行分发。最终用户将需要这个镜像。另外,他们将克隆构建系统的存储库(即一个与教程存储库等效的存储库)。

当最终用户调用 build.sh 或者 shell.sh 时,容器内将执行右边的 run_build.sh 脚本。接下来我将详细解释这些脚本。这里的关键是最终用户不需要为了使用而去了解任何关于红色或者蓝色模块或者容器工作原理的知识。

构建系统细节

把教程存储库的文件结构映射到这个系统结构上。我曾将这个原型结构用于相对复杂构建系统,因此它的简单并不会造成任何限制。下面我列出存储库中相关文件的树结构。文件夹 dockerize-tutorial 能用构建系统的其他任何名称代替。在这个文件夹下,我用 workdir 的路径作参数调用 build.shshell.sh

dockerize-tutorial/
├── build.sh
├── shell.sh
└── swbuilder
    ├── build_docker_image.sh
    ├── install_swbuilder.dockerfile
    └── scripts
        └── run_build.sh

请注意,我上面特意没列出 example_workdir,但你能在教程存储库中找到它。实际的源码通常存放在单独的存储库中,而不是构建工具库中的一部分;本教程为了不必处理两个存储库,所以我将它包含在这个存储库中。

如果你只对概念感兴趣,本教程并非必须的,因为我将解释所有文件。但是如果你继续本教程(并且已经安装 Docker),首先使用以下命令来构建容器镜像 swbuilder:v1

cd dockerize-tutorial/swbuilder/
./build_docker_image.sh
docker image ls  # resulting image will be swbuilder:v1

然后调用 build.sh

cd dockerize-tutorial
./build.sh ~/repos/dockerize-tutorial/example_workdir

下面是 build.sh 的代码。这个脚本从容器镜像 swbuilder:v1 实例化一个容器。而这个容器实例映射了两个卷:一个将文件夹 example_workdir 挂载到容器内部路径 /workdir 上,第二个则将容器外的文件夹 dockerize-tutorial/swbuilder/scripts 挂载到容器内部路径 /scripts 上。

docker container run                              \
    --volume $(pwd)/swbuilder/scripts:/scripts    \
    --volume $1:/workdir                          \
    --user $(id -u ${USER}):$(id -g ${USER})      \
    --rm -it --name build_swbuilder swbuilder:v1  \
    build

另外,build.sh 还会用你的用户名(以及组,本教程假设两者一致)去运行容器,以便在访问构建输出时不出现文件权限问题。

请注意,shell.shbuild.sh 大体上是一致的,除了两点不同:build.sh 会创建一个名为 build_swbuilder 的容器,而 shell.sh 则会创建一个名为 shell_swbuilder 的容器。这样一来,当其中一个脚本运行时另一个脚本被调用也不会产生冲突。

两个脚本之间的另一处关键不同则在于最后一个参数:build.sh 传入参数 buildshell.sh 则传入 shell。如果你看了用于构建容器镜像的 Dockerfile,就会发现最后一行包含了下面的 ENTRYPOINT 语句。这意味着上面的 docker container run 调用将使用 buildshell 作为唯一的输入参数来执行 run_build.sh 脚本。

# run bash script and process the input command
ENTRYPOINT [ "/bin/bash", "/scripts/run_build.sh"]

run\_build.sh 使用这个输入参数来选择启动 Bash shell 还是调用 gcc 来构建 helloworld.c 项目。一个真正的构建系统通常会使用 Makefile 而非直接运行 gcc

cd /workdir

if [ $1 = "shell" ]; then    
    echo "Starting Bash Shell"
    /bin/bash
elif [ $1 = "build" ]; then
    echo "Performing SW Build"
    gcc helloworld.c -o helloworld -Wall
fi

在使用时,如果你需要传入多个参数,当然也是可以的。我处理过的构建系统,构建通常是对给定的项目调用 make。如果一个构建系统有非常复杂的构建调用,则你可以让 run_build.sh 调用 workdir 下最终用户编写的特定脚本。

关于 scripts 文件夹的说明

你可能想知道为什么 scripts 文件夹位于目录树深处而不是位于存储库的顶层。两种方法都是可行的,但我不想鼓励最终用户到处乱翻并修改里面的脚本。将它放到更深的地方是一个让他们更难乱翻的方法。另外,我也可以添加一个 .dockerignore 文件去忽略 scripts 文件夹,因为它不是容器必需的部分。但因为它很小,所以我没有这样做。

简单而灵活

尽管这一方法很简单,但我在几个相当不同的构建系统中使用过,发现它相当灵活。相对稳定的部分(例如,一年仅修改数次的给定工具集)被固定在容器镜像内。较为灵活的部分则以脚本的形式放在镜像外。这使我能够通过修改脚本并将更改推送到构建系统存储库中,轻松修改调用工具集的方式。用户所需要做的是将更改拉到本地的构建系统存储库中,这通常是非常快的(与更新 Docker 镜像不同)。这种结构使其能够拥有尽可能多的卷和脚本,同时使最终用户摆脱复杂性。


via: https://opensource.com/article/20/4/how-containerize-build-system

作者:Ravi Chandran 选题:lujun9972 译者:LazyWolfLin 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

工作中用了容器?熟悉这些出自云原生计算基金会的项目吗?

随着用容器来开发应用的实践变得流行,云原生应用也在增长。云原生应用的定义为:

“云原生技术用于开发使用打包在容器中的服务所构建的应用程序,以微服务的形式部署,并通过敏捷的 DevOps 流程和持续交付工作流在弹性基础设施上进行管理。”

这个定义提到了构成云原生应用的不可或缺的四个元素:

  1. 容器
  2. 微服务
  3. DevOps
  4. 持续集成和持续交付 (CI/CD)

尽管这些技术各有各自独特的历史,但它们之间却相辅相成,在短时间内实现了云原生应用和工具的惊人的指数级增长。这个云原生计算基金会(CNCF)信息图呈现了当今云原生应用生态的规模和广度。

 title=

云原生计算基金会项目

我想说,瞧着吧!这仅仅是一个开始。正如 NodeJS 的出现引发了无数的 JavaScript 工具的爆炸式增长一样,容器技术的普及也推动了云原生应用的指数增长。

好消息是,有几个组织负责监管并将这些技术连接在一起。 其中之一是 开放容器倡议 Open Containers Initiative (OCI),它是一个轻量级的、开放的治理机构(或项目),“它是在 Linux 基金会的支持下形成的,其明确目的是创建开放的行业标准的容器格式和运行时。” 另一个是 CNCF,它是“一个致力于使云原生计算普及和可持续发展的开源软件基金会”。

通常除了围绕云原生应用建立社区之外,CNCF 还帮助项目围绕其云原生应用建立结构化管理。CNCF 创建了成熟等级的概念(沙箱级、孵化级或毕业级),分别与下图中的“创新者”、“早期采用者”和“早期大量应用”相对应。

 title=

CNCF 项目成熟等级

CNCF 为每个成熟等级制定了详细的标准(为方便读者而列在下面)。获得技术监督委员会(TOC)三分之二的同意才能转为孵化或毕业级。

沙箱级

要想成为沙箱级,一个项目必须至少有两个 TOC 赞助商。 有关详细过程,请参见《CNCF 沙箱指南 v1.0》。

孵化级

注:孵化级是我们期望对项目进行全面的尽职调查的起点。

要进入孵化级,项目除了满足沙箱级的要求之外还要满足:

  • 证明至少有三个独立的最终用户已成功将其用于生产,且 TOC 判断这些最终用户具有足够的质量和范围。
  • 提交者的数量要合理。提交者定义为具有提交权的人,即可以接受部分或全部项目贡献的人。
  • 显示出有大量持续提交和合并贡献。
  • 由于这些指标可能会根据项目的类型、范围和大小而有很大差异,所以 TOC 有权决定是否满足这些标准的活动水平。

毕业级

要从沙箱或孵化级毕业,或者要使一个新项目作为已毕业项目加入,项目除了必须满足孵化级的标准外还要满足:

  • 至少有两个来自组织的提交者。
  • 已获得并保持了“核心基础设施计划最佳实践徽章”。
  • 已完成独立的第三方安全审核,并发布了具有与以下示例类似的范围和质量的结果(包括已解决的关键漏洞):https://github.com/envoyproxy/envoy#security-audit,并在毕业之前需要解决所有关键的漏洞。
  • 采用《CNCF 行为准则》。
  • 明确规定项目治理和提交流程。最好将其列在 GOVERNANCE.md 文件中,并引用显示当前提交者和荣誉提交者的 OWNERS.md 文件。
  • 至少有一个主仓的项目采用者的公开列表(例如,ADOPTERS.md 或项目网站上的徽标)。
  • 获得 TOC 的绝大多数票,进入毕业阶段。如果项目能够表现出足够的成熟度,则可以尝试直接从沙箱级过渡到毕业级。项目可以无限期保持孵化状态,但是通常预计它们会在两年内毕业。

值得关注的 9 个项目

本文不可能涵盖所有的 CNCF 项目,我将介绍最有趣的 9 个毕业和孵化的开源项目。

名称授权类型简要描述
KubernetesApache 2.0容器编排平台
PrometheusApache 2.0系统和服务监控工具
EnvoyApache 2.0边缘和服务代理
rktApache 2.0Pod 原生的容器引擎
JaegerApache 2.0分布式跟踪系统
LinkerdApache 2.0透明服务网格
HelmApache 2.0Kubernetes 包管理器
EtcdApache 2.0分布式键值存储
CRI-OApache 2.0专门用于 Kubernetes 的轻量级运行时环境

我也创建了视频材料来介绍这些项目。

毕业项目

毕业的项目被认为是成熟的,已被许多组织采用的,并且严格遵守了 CNCF 的准则。以下是三个最受欢迎的开源 CNCF 毕业项目。(请注意,其中一些描述来源于项目的网站并被做了改编。)

Kubernetes(希腊语“舵手”)

Kubernetes! 说起云原生应用,怎么能不提 Kubernetes 呢? Google 发明的 Kubernetes 无疑是最著名的基于容器的应用程序的容器编排平台,而且它还是一个开源工具。

什么是容器编排平台?通常,一个容器引擎本身可以管理几个容器。但是,当你谈论数千个容器和数百个服务时,管理这些容器变得非常复杂。这就是容器编排引擎的用武之地。容器编排引擎通过自动化容器的部署、管理、网络和可用性来帮助管理大量的容器。

Docker Swarm 和 Mesosphere Marathon 也是容器编排引擎,但是可以肯定地说,Kubernetes 已经赢得了这场比赛(至少现在是这样)。Kubernetes 还催生了像 OKD 这样的容器即服务(CaaS)平台,它是 Kubernetes 的 Origin 社区发行版,并成了 Red Hat OpenShift 的一部分。

想开始学习,请访问 Kubernetes GitHub 仓库,并从 Kubernetes 文档页面访问其文档和学习资源。

Prometheus(普罗米修斯)

Prometheus 是 2012 年在 SoundCloud 上构建的一个开源的系统监控和告警工具。之后,许多公司和组织都采用了 Prometheus,并且该项目拥有非常活跃的开发者和用户群体。现在,它已经成为一个独立的开源项目,独立于公司之外进行维护。

 title=

Prometheus 的架构

理解 Prometheus 的最简单方法是可视化一个生产系统,该系统需要 24(小时)x 365(天)都可以正常运行。没有哪个系统是完美的,也有减少故障的技术(称为容错系统),但是,如果出现问题,最重要的是尽快发现问题。这就是像 Prometheus 这样的监控工具的用武之地。Prometheus 不仅仅是一个容器监控工具,但它在云原生应用公司中最受欢迎。此外,其他开源监视工具,包括 Grafana,都借助了 Prometheus。

开始使用 Prometheus 的最佳方法是下载其 GitHub 仓库。在本地运行 Prometheus 很容易,但是你需要安装一个容器引擎。你可以在 Prometheus 网站上查看详细的文档。

Envoy(使者)

Envoy(或 Envoy 代理)是专为云原生应用设计的开源的边缘代理和服务代理。由 Lyft 创建的 Envoy 是为单一服务和应用而设计的高性能的 C++ 开发的分布式代理,同时也是为由大量微服务组成的服务网格架构而设计的通信总线和通用数据平面。Envoy 建立在 Nginx、HAProxy、硬件负载均衡器和云负载均衡器等解决方案的基础上,Envoy 与每个应用相伴(并行)运行,并通过提供平台无关的方式提供通用特性来抽象网络。

当基础设施中的所有服务流量都经过 Envoy 网格时,很容易就可以通过一致的可观测性来可视化问题域,调整整体性能,并在单个位置添加基础功能。基本上,Envoy 代理是一个可帮助组织为生产环境构建容错系统的服务网格工具。

服务网格应用有很多替代方案,例如 Uber 的 Linkerd(下面会讨论)和 Istio。Istio 通过将其部署为 Sidecar 并利用了 Mixer 的配置模型,实现了对 Envoy 的扩展。Envoy 的显著特性有:

  • 包括所有的“ 入场筹码 table stakes (LCTT 译注:引申为基础必备特性)”特性(与 Istio 这样的控制平面组合时)
  • 带载运行时 99% 数据可达到低延时
  • 可以作为核心的 L3/L4 过滤器,提供了开箱即用的 L7 过滤器
  • 支持 gRPC 和 HTTP/2(上行/下行)
  • 由 API 驱动,并支持动态配置和热重载
  • 重点关注指标收集、跟踪和整体可监测性

要想了解 Envoy,证实其能力并实现其全部优势,需要丰富的生产级环境运行的经验。你可以在其详细文档或访问其 GitHub 仓库了解更多信息。

孵化项目

下面是六个最流行的开源的 CNCF 孵化项目。

rkt(火箭)

rkt, 读作“rocket”,是一个 Pod 原生的容器引擎。它有一个命令行接口用来在 Linux 上运行容器。从某种意义上讲,它和其他容器如 Podman、Docker 和 CRI-O 相似。

rkt 最初是由 CoreOS (后来被 Red Hat 收购)开发的,你可以在其网站上找到详细的文档,以及在 GitHub 上访问其源代码。

Jaeger(贼鸥)

Jaeger 是一个开源的端到端的分布式追踪系统,适用于云端应用。在某种程度上,它是像 Prometheus 这样的监控解决方案。但它有所不同,因为其使用场景有所扩展:

  • 分布式事务监控
  • 性能和延时优化
  • 根因分析
  • 服务依赖性分析
  • 分布式上下文传播

Jaeger 是一项 Uber 打造的开源技术。你可以在其网站上找到详细文档,以及在 GitHub 上找到其源码。

Linkerd

像创建 Envoy 代理的 Lyft 一样,Uber 开发了 Linkerd 开源解决方案用于生产级的服务维护。在某些方面,Linkerd 就像 Envoy 一样,因为两者都是服务网格工具,旨在提供平台级的可观测性、可靠性和安全性,而无需进行配置或代码更改。

但是,两者之间存在一些细微的差异。 尽管 Envoy 和 Linkerd 充当代理并可以通过所连接的服务进行上报,但是 Envoy 并不像 Linkerd 那样被设计为 Kubernetes Ingress 控制器。Linkerd 的显著特点包括:

  • 支持多种平台(Docker、Kubernetes、DC/OS、Amazon ECS 或任何独立的机器)
  • 内置服务发现抽象,可以将多个系统联合在一起
  • 支持 gRPC、HTTP/2 和 HTTP/1.x请 求和所有的 TCP 流量

你可以在 Linkerd 网站上阅读有关它的更多信息,并在 GitHub 上访问其源码。

Helm(舵轮)

Helm 基本上就是 Kubernetes 的包管理器。如果你使用过 Apache Maven、Maven Nexus 或类似的服务,你就会理解 Helm 的作用。Helm 可帮助你管理 Kubernetes 应用程序。它使用“Helm Chart”来定义、安装和升级最复杂的 Kubernetes 应用程序。Helm 并不是实现此功能的唯一方法;另一个流行的概念是 Kubernetes Operators,它被 Red Hat OpenShift 4 所使用。

你可以按照其文档中的快速开始指南GitHub 指南来试用 Helm。

Etcd

Etcd 是一个分布式的、可靠的键值存储,用于存储分布式系统中最关键的数据。其主要特性有:

  • 定义明确的、面向用户的 API(gRPC)
  • 自动 TLS,可选的客户端证书验证
  • 速度(可达每秒 10,000 次写入)
  • 可靠性(使用 Raft 实现分布式)

Etcd 是 Kubernetes 和许多其他技术的默认的内置数据存储方案。也就是说,它很少独立运行或作为单独的服务运行;相反,它以集成到 Kubernetes、OKD/OpenShift 或其他服务中的形式来运作。还有一个 etcd Operator 可以用来管理其生命周期并解锁其 API 管理功能:

你可以在 etcd 文档中了解更多信息,并在 GitHub上访问其源码。

CRI-O

CRI-O 是 Kubernetes 运行时接口的 OCI 兼容实现。CRI-O 用于各种功能,包括:

  • 使用 runc(或遵从 OCI 运行时规范的任何实现)和 OCI 运行时工具运行
  • 使用容器/镜像进行镜像管理
  • 使用容器/存储来存储和管理镜像层
  • 通过容器网络接口(CNI)来提供网络支持

CRI-O 提供了大量的文档,包括指南、教程、文章,甚至播客,你还可以访问其 GitHub 页面

我错过了其他有趣且开源的云原生项目吗?请在评论中提醒我。


via: https://opensource.com/article/19/8/cloud-native-projects

作者:Bryant Son 选题:lujun9972 译者:messon007 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Amazon 已经推出了自己的基于 Linux 的开源操作系统 Bottlerocket(“瓶装火箭”)。但在你兴奋地想要尝试安装和运行它之前,我必须告诉你,它不是常规的如 Ubuntu、Fedora 或 Debian 这样的 Linux 发行版。那它是什么?

Bottlerocket:来自 Amazon 的 Linux 发行版,用于运行容器

如果你不了解 Linux 容器,建议你阅读 Red Hat 的这篇文章

自从首次提出云计算一词以来,IT 行业发生了许多变化。得益于 Amazon AWS、Google、Linode、Digital Ocean 等云服务器提供商,部署 Linux 服务器(通常在虚拟机中运行)只需几秒钟。最重要的是,你可以借助 Docker 和 Kubernetes 之类的工具在这些服务器上以容器形式部署应用和服务。

问题是,当你唯一目的是在 Linux 系统上运行容器时,并不总是需要完整的 Linux 发行版。这就是为什么容器专用 Linux 仅提供必要软件包的原因。这将大大减少操作系统的大小,从而进一步减少部署时间。

Bottlerocket Linux 由 Amazon Web Services(AWS)专门构建,用于在虚拟机或裸机上运行容器。它支持 docker 镜像和其他遵循 OCI 镜像格式的镜像。

Bottlerocket Linux 的特性

这是来自 Amazon 的新 Linux 发行版提供的特性:

没有逐包更新

传统的 Linux 发行版更新过程由更新单个软件包组成。Bottlerocket 改用基于镜像的更新。

由于采用了这种方法,可以避免冲突和破坏,并可以进行快速而完整的回滚(如有必要)。

只读文件系统

Bottlerocket 还使用了只读主文件系统。在启动时通过 dm-verity 检查其完整性。在其他安全措施上,也不建议使用 SSH 访问,并且只能通过管理容器(附加机制)使用。

AWS 已经统治了云世界。

自动更新

你可以使用 Amazon EKS 之类的编排服务来自动执行 Bottlerocket 更新。

Amazon 还声称,与通用 Linux 发行版相比,仅包含运行容器的基本软件可以减少攻击面。

你怎么看?

Amazon 并不是第一个创建“容器专用 Linux” 的公司。我认为 CoreOS 是最早的此类发行版之一。CoreOS 被 Red Hat 收购,Red Hat 又被 IBM 收购。Red Hat 公司最近停用了 CoreOS,并用 Fedora CoreOS 代替了它。

云服务器是一个巨大的行业,它将继续发展壮大。像 Amazon 这样的巨头将竭尽所能与它竞争对手保持一致或领先。我认为,Bottlerocket 是对 IBM Fedora CoreOS(目前)的应答。

尽管 Bottlerocket 仓库可在 GitHub 上找到,但我还没发现就绪的镜像(LCTT 译注:源代码已经提供)。在撰写本文时,它仅可在 AWS 上预览

你对此有何看法?Amazon 会从 Bottlerocket 获得什么?如果你以前使用过 CoreOS 之类的软件,你会切换到 Bottlerocket 么?


via: https://itsfoss.com/bottlerocket-linux/

作者:Abhishek Prakash 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

去杂货店“采购”这些命令,你需要用这些 Kubernetes 工具来入门。

最近,我丈夫告诉我他即将要去参加一个工作面试,面试时他需要在计算机上运行一些基本命令。他对这场面试感到焦虑,但是对于他来说,学习和记住事情的最好方法是将不了解的事物比喻为非常熟悉的事物。因为我们的谈话是在我逛杂货店试图决定当晚要烹饪的食物之后进行的,所以这启发我用一次去杂货店的行程来介绍 kubectlhelm 命令。

Helm(“舵轮”)是在 Kubernetes(来自希腊语,意思是“舵手” 或 “领航员”)中管理应用程序的工具。你可以轻松地使用你的应用程序信息来部署“ 海图 chart ”,从而可以在你的 Kubernetes 环境中几分钟之内让它们就绪并预配置好。在学习新知识时,查看示例的“海图”以了解其用法总是很有帮助的,因此,如果有时间,请查看这些成型的“海图”。(LCTT 译注:Kubernetes 生态中大量使用了和航海有关的比喻,因此本文在翻译时也采用了这些比喻)

kubectl 是与 Kubernetes 环境交互的命令行界面,允许你配置和管理集群。它需要一些配置才能在环境中工作,因此请仔细阅读其文档以了解你需要做什么。

我会在示例中使用命名空间,你可以在我的文章《Kubernetes 命名空间入门》中了解它。

现在我们已经准备好了,让我们开始 kubectlhelm 基本命令的购物之旅!

用 Helm 列出清单

你去商店之前要做的第一件事是什么?好吧,如果你做事有条理,会创建一个“清单”。同样,这是我将解释的第一个基本的 Helm 命令。

在一个用 Helm 部署的应用程序中,list 命令提供有关应用程序当前版本的详细信息。在此示例中,我有一个已部署的应用程序:Jenkins CI/CD 应用程序。运行基本的 list 命令总是会显示默认的命名空间。由于我没有在默认的命名空间中部署任何内容,因此不会显示任何内容:

$helm list
NAME    NAMESPACE    REVISION    UPDATED    STATUS    CHART    APP VERSION

但是,如果运行带有额外标志的命令,则会显示我的应用程序和信息:

$helm list --all-namespaces
NAME     NAMESPACE  REVISION  UPDATED                   STATUS      CHART           APP  VERSION
jenkins  jenkins        1         2020-01-18 16:18:07 EST   deployed    jenkins-1.9.4   lts

最后,我可以指示 list 命令只检查我想从中获取信息的命名空间:

$helm list --namespace jenkins
NAME     NAMESPACE  REVISION  UPDATED                   STATUS    CHART          APP VERSION
jenkins    jenkins      1              2020-01-18 16:18:07 EST  deployed  jenkins-1.9.4  lts    

现在我有了一个清单,并且知道该清单上有什么,我可以使用 get 命令来“获取”我的物品!我会从 Kubernetes 集群开始,看看我能从中获取到什么?

用 Kubectl 获取物品

kubectl get 命令提供了有关 Kubernetes 中许多事物的信息,包括“ 吊舱 Pod ”、节点和命名空间。同样,如果没有指定命名空间标志,就会使用默认的命名空间。首先,我获取集群中的命名空间以查看正在运行的命名空间:

$kubectl get namespaces
NAME             STATUS   AGE
default          Active   53m
jenkins          Active   44m
kube-node-lease  Active   53m
kube-public      Active   53m
kube-system      Active   53m

现在我已经知道了在我的环境中运行的有哪些命名空间了,接下来获取节点并查看有多少个节点正在运行:

$kubectl get nodes
NAME       STATUS   ROLES       AGE   VERSION
minikube   Ready    master  55m   v1.16.2

我有一个节点正在运行,这主要是因为我的 Minikube 运行在一台小型服务器上。要得到在我的这一个节点上运行的“吊舱”可以这样:

$kubectl get pods
No resources found in default namespace.

啊哦,它是空的。我将通过以下方式获取 Jenkins 命名空间中的内容:

$kubectl get pods --namespace jenkins
NAME                      READY  STATUS   RESTARTS  AGE
jenkins-7fc688c874-mh7gv  1/1    Running  0         40m

好消息!这里发现了一个“吊舱”,它还没有重新启动过,已运行了 40 分钟了。好的,如今我知道“吊舱”已经装好,所以我想看看用 Helm 命令可以得到什么。

用 Helm 获取信息

helm get 命令稍微复杂一点,因为这个“获取”命令所需要的不仅仅是一个应用程序名称,而且你可以从应用程序中请求多个内容。我会从获取用于制作该应用程序的值开始,然后展示“获取全部”的操作结果的片段,该操作将提供与该应用程序相关的所有数据。

$helm get values jenkins -n jenkins
USER-SUPPLIED VALUES:
null

由于我只安装了最小限度的稳定版,因此配置没有更改。如果我运行“获取全部”命令,我将得到所有的“海图”:

$helm get all jenkins -n jenkins

 title=

这会产生大量数据,因此我始终建议保留一份 Helm “海图”的副本,以便你可以查看“海图”中的模板。我还创建自己的值来了解自己所拥有的。

现在,我把所有的商品都放在购物车中了,我会检查一下“描述”它们包含什么的标签。这些示例仅与 kubectl 命令有关,它们描述了我通过 Helm 部署的内容。

用 kubectl 查看描述

正如我使用“获取”命令(该命令可以描述 Kubernetes 中的几乎所有内容)所做的那样,我将示例限定到命名空间、“吊舱”和节点上。由于我知道它们每一个是什么,因此这很容易。

$kubectl describe ns jenkins
Name:           jenkins
Labels:         <none>
Annotations:  <none>
Status:         Active
No resource quota.
No resource limits.

我可以看到我的命名空间的名称,并且它是活动的,没有资源或限额限制。

describe pods 命令会产生大量信息,因此我这里提供的是一小段输出。如果你在不使用“吊舱”名称的情况下运行该命令,它将返回名称空间中所有“吊舱”的信息,这可能会很麻烦。因此,请确保在此命令中始终包含“吊舱”名称。例如:

$kubectl describe pods jenkins-7fc688c874-mh7gv --namespace jenkins

 title=

这会提供容器的状态、管理方式、标签以及“吊舱”中所使用的镜像(还有很多其它信息)。没有在这个简化过的输出中包括的数据有:在 Helm 配置值文件中应用的各种条件下的资源请求和限制、初始化容器和存储卷信息。如果你的应用程序由于资源不足而崩溃,或者是一个需要运行前置脚本进行配置的初始配置容器,或者生成不应该存储于纯文本 YAML 文件中的隐藏密码,则此数据很有用。

最后,我将使用 describe node 命令,当然,它是用来描述节点的。由于本示例只有一个名为 Minikube 的示例,因此我将使用这个名字。如果你的环境中有多个节点,则必须包含你想查找的的节点名称。

与“吊舱”一样,这个节点的命令会产生大量数据,因此我将仅包括输出片段。

$kubectl describe node minikube

 title=

注意,describe node 是更重要的基本命令之一。如此图所示,该命令返回统计信息,该信息指示节点何时资源用尽,并且该数据非常适合在需要扩展时(如果你的环境中没有自动扩展)向你发出警报。此输出片段中未包含的其它内容包括:对所有资源和限制的请求所占的百分比,以及资源的使用期限和分配(例如,对于我的应用程序而言)。

买单

使用这些命令,我完成了“购物”并得到了我想要的一切。希望这些基本命令也能在你使用 Kubernetes 的日常工作中提供帮助。

我鼓励你经常使用命令行并学习“帮助”部分中的速记标志,你可以通过运行以下命令来查看这些标志:

$helm --help

$kubectl -h

花生酱和果冻

有些东西像花生酱和果冻一样混在一起。Helm 和 kubectl 就有点像那样交错在一起。

我经常在自己的环境中使用这些工具。因为它们在很多地方都有很多相似之处,所以在使用其中一个之后,我通常需要跟进另一个。例如,我可以进行 Helm 部署,并使用 kubectl 观察它是否失败。一起试试它们,看看它们能为你做什么。


via: https://opensource.com/article/20/2/kubectl-helm-commands

作者:Jessica Cherry 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。

 title=

当你使用 Kubernetes 运行容器时,你通常会发现它们堆积在一起。这是设计使然。它是容器的优点之一:每当需要新的容器时,它们启动成本都很低。你可以使用前端工具(如 OpenShift 或 OKD)来管理 Pod 和容器。这些工具使可视化设置变得容易,并且它具有一组丰富的用于快速交互的命令。

如果管理容器的平台不符合你的要求,你也可以仅使用 Kubernetes 工具链获取这些信息,但这需要大量命令才能全面了解复杂环境。出于这个原因,我编写了 KRAWL,这是一个简单的脚本,可用于扫描 Kubernetes 集群命名空间下的 Pod 和容器,并在发现任何事件时,显示事件的输出。它也可用作为 Kubernetes 插件使用。这是获取大量有用信息的快速简便方法。

先决条件

  • 必须安装 kubectl
  • 集群的 kubeconfig 配置必须在它的默认位置($HOME/.kube/config)或已被导出到环境变量(KUBECONFIG=/path/to/kubeconfig)。

使用

$ ./krawl

 title=

脚本

#!/bin/bash
# AUTHOR: Abhishek Tamrakar
# EMAIL: [email protected]
# LICENSE: Copyright (C) 2018 Abhishek Tamrakar
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
##
#define the variables
KUBE_LOC=~/.kube/config
#define variables
KUBECTL=$(which kubectl)
GET=$(which egrep)
AWK=$(which awk)
red=$(tput setaf 1)
normal=$(tput sgr0)
# define functions

# wrapper for printing info messages
info()
{
  printf '\n\e[34m%s\e[m: %s\n' "INFO" "$@"
}

# cleanup when all done
cleanup()
{
  rm -f results.csv
}

# just check if the command we are about to call is available
checkcmd()
{
  #check if command exists
  local cmd=$1
  if [ -z "${!cmd}" ]
  then
    printf '\n\e[31m%s\e[m: %s\n' "ERROR"  "check if $1 is installed !!!"
    exit 1
  fi
}

get_namespaces()
{
  #get namespaces
  namespaces=( \
          $($KUBECTL get namespaces --ignore-not-found=true | \
          $AWK '/Active/ {print $1}' \
          ORS=" ") \
          )
#exit if namespaces are not found
if [ ${#namespaces[@]} -eq 0 ]
then
  printf '\n\e[31m%s\e[m: %s\n' "ERROR"  "No namespaces found!!"
  exit 1
fi
}

#get events for pods in errored state
get_pod_events()
{
  printf '\n'
  if [ ${#ERRORED[@]} -ne 0 ]
  then
      info "${#ERRORED[@]} errored pods found."
      for CULPRIT in ${ERRORED[@]}
      do
        info "POD: $CULPRIT"
        info
        $KUBECTL get events \
        --field-selector=involvedObject.name=$CULPRIT \
        -ocustom-columns=LASTSEEN:.lastTimestamp,REASON:.reason,MESSAGE:.message \
        --all-namespaces \
        --ignore-not-found=true
      done
  else
      info "0 pods with errored events found."
  fi
}

#define the logic
get_pod_errors()
{
  printf "%s %s %s\n" "NAMESPACE,POD_NAME,CONTAINER_NAME,ERRORS" > results.csv
  printf "%s %s %s\n" "---------,--------,--------------,------" >> results.csv
  for NAMESPACE in ${namespaces[@]}
  do
    while IFS=' ' read -r POD CONTAINERS
    do
      for CONTAINER in ${CONTAINERS//,/ }
      do
        COUNT=$($KUBECTL logs --since=1h --tail=20 $POD -c $CONTAINER -n $NAMESPACE 2>/dev/null| \
        $GET -c '^error|Error|ERROR|Warn|WARN')
        if [ $COUNT -gt 0 ]
        then
            STATE=("${STATE[@]}" "$NAMESPACE,$POD,$CONTAINER,$COUNT")
        else
        #catch pods in errored state
            ERRORED=($($KUBECTL get pods -n $NAMESPACE --no-headers=true | \
                awk '!/Running/ {print $1}' ORS=" ") \
                )
        fi
      done
    done< <($KUBECTL get pods -n $NAMESPACE --ignore-not-found=true -o=custom-columns=NAME:.metadata.name,CONTAINERS:.spec.containers[*].name --no-headers=true)
  done
  printf "%s\n" ${STATE[@]:-None} >> results.csv
  STATE=()
}
#define usage for seprate run
usage()
{
cat << EOF

  USAGE: "${0##*/} </path/to/kube-config>(optional)"

  This program is a free software under the terms of Apache 2.0 License.
  COPYRIGHT (C) 2018 Abhishek Tamrakar

EOF
exit 0
}

#check if basic commands are found
trap cleanup EXIT
checkcmd KUBECTL
#
#set the ground
if [ $# -lt 1 ]; then
  if [ ! -e ${KUBE_LOC} -a ! -s ${KUBE_LOC} ]
  then
    info "A readable kube config location is required!!"
    usage
  fi
elif [ $# -eq 1 ]
then
  export KUBECONFIG=$1
elif [ $# -gt 1 ]
then
  usage
fi
#play
get_namespaces
get_pod_errors

printf '\n%40s\n' 'KRAWL'
printf '%s\n' '---------------------------------------------------------------------------------'
printf '%s\n' '  Krawl is a command line utility to scan pods and prints name of errored pods   '
printf '%s\n\n' ' +and containers within. To use it as kubernetes plugin, please check their page '
printf '%s\n' '================================================================================='

cat results.csv | sed 's/,/,|/g'| column -s ',' -t
get_pod_events

此文最初发布在 KRAWL 的 GitHub 仓库下的 README 中,并被或许重用。


via: https://opensource.com/article/20/2/kubernetes-scanner

作者:Abhishek Tamrakar 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

一个使用 tmux 的 kubectl 插件可以使 Kubernetes 疑难问题变得更简单。

Kubernetes 是一个活跃的开源容器管理平台,它提供了可扩展性、高可用性、健壮性和富有弹性的应用程序管理。它的众多特性之一是支持通过其主要的二进制客户端 kubectl 运行定制脚本或可执行程序,kubectl 很强大的,允许用户在 Kubernetes 集群上用它直接做很多事情。

使用别名进行 Kubernetes 的故障排查

使用 Kubernetes 进行容器编排的人都知道由于设计上原因带来了其功能的复杂性。举例说,迫切需要以更快的速度并且几乎不需要手动干预的方式来简化 Kubernetes 中的故障排除(除过特殊情况)。

在故障排查功能方面,有很多场景需要考虑。在一种场景下,你知道你需要运行什么,但是这个命令的语法(即使作为一个单独的命令运行)过于复杂,或需要一、两次交互才能起作用。

例如,如果你需要经常进入一个系统命名空间中运行的容器,你可能发现自己在重复地键入:

kubectl --namespace=kube-system exec -i -t <your-pod-name>

为了简化故障排查,你可以用这些指令的命令行别名。比如,你可以增加下面命令到你的隐藏配置文件(.bashrc.zshrc):

alias ksysex='kubectl --namespace=kube-system exec -i -t'

这是来自于 Kubernetes 常见别名存储库的一个例子,它展示了一种简化 kubectl 中的功能的方法。像这种场景下的简单情形,使用别名很有用。

切换到 kubectl 插件

更复杂的故障排查场景是需要一个一个的执行很多命令,调查环境,最后得出结论。仅仅用别名方法是不能解决这种情况的;你需要知道你所部署的 Kubernetes 之间逻辑和相关性,你真正需要的是自动化,以在更短的时间内输出你想要的。

考虑到你的集群有 10 ~ 20 或 50 ~ 100 个命名空间来提供不同的微服务。一般在进行故障排查时,什么对你有帮助?

  • 你需要能够快速分辨出抛出错误的是哪个 命名空间的哪个 Pod 的东西。
  • 你需要一些可监视一个命名空间的所有 Pod 日志的东西。
  • 你可能也需要监视特定命名空间的出现错误的某个 Pod 的日志。

涵盖这些要点的解决方案对于定位生产环境的问题有很大的帮助,以及在开发和测试环节中也很有用。

你可以用 kubectl 插件创建比简单的别名更强大的功能。插件类似于其它用任何语言编写的独立脚本,但被设计为可以扩充 Kubernetes 管理员的主要命令。

创建一个插件,你必须用 kubectl-<your-plugin-name> 的正确的语法来拷贝这个脚本到 $PATH 中的导出目录之一,并需要为其赋予可执行权限(chmod +x)。

创建插件之后将其移动到路径中,你可以立即运行它。例如,我的路径下有一个 kubectl-krawlkubectl-kmux

$ kubectl plugin list
The following compatible plugins are available:

/usr/local/bin/kubectl-krawl
/usr/local/bin/kubectl-kmux

$ kubectl kmux

现在让我们见识下带有 tmux 的 Kubernetes 的有多强大。

驾驭强大的 tmux

Tmux 是一个非常强大的工具,许多管理员和运维团队都依赖它来解决与易操作性相关的问题:通过将窗口分成多个窗格以便在多台计算机上运行并行的调试来监视日志。它的主要的优点是可在命令行或自动化脚本中使用。

我创建一个 kubectl 插件,使用 tmux 使故障排查更加简单。我将通过注释来解析插件背后的逻辑(插件的完整代码留待给你实现):

# NAMESPACE 是要监控的名字空间
# POD 是 Pod 名称
# Containers 是容器名称

# 初始化一个计数器 n 以计算循环计数的数量,
# 之后 tmux 使用它来拆分窗格。
n=0;

# 在 Pod 和容器列表上开始循环
while IFS=' ' read -r POD CONTAINERS
do
    # tmux 为每个 Pod 创建一个新窗口
    tmux neww $COMMAND -n $POD 2>/dev/null
    # 对运行中的 Pod 中 的所有容器启动循环
    for CONTAINER in ${CONTAINERS//,/ }
    do
        if [ x$POD = x -o x$CONTAINER = x ]; then
            # 如果任何值为 null,则退出。
                     warn "Looks like there is a problem getting pods data."
            break
        fi
           
        # 设置要执行的命令
        COMMAND=”kubectl logs -f $POD -c $CONTAINER -n $NAMESPACE”
        # 检查 tmux 会话
        if tmux has-session -t <会话名> 2>/dev/null;
        then
            <设置会话退出>
        else
            <创建会话>
        fi
        # 在当前窗口为每个容器切分窗格
        tmux selectp -t $n \; \
        splitw $COMMAND \; \
        select-layout tiled \;
        # 终止容器循环
    done
    
    # 用 Pod 名称重命名窗口以识别
    tmux renamew $POD 2>/dev/null
    
    # 增加计数器
    ((n+=1))

# 终止 Pod 循环
done<<(<从 kubernetes  集群获取 Pod 和容器的列表>)

# 最后选择窗口并附加会话
tmux selectw -t <会话名>:1 \; \
attach-session -t <会话名>\;

运行插件脚本后,将产生类似于下图的输出。每个 Pod 有一个自己的窗口,每个容器(如果有多个)被分割到其窗口中 Pod 窗格中,并在日志到达时输出。Tmux 之美如下可见;通过正确的配置,你甚至会看到哪个窗口正处于激活运行状态(可看到标签是白色的)。

总结

别名是在 Kubernetes 环境下常见的也有用的简易故障排查方法。当环境变得复杂,用高级脚本生成的kubectl 插件是一个更强大的方法。至于用哪个编程语言来编写 kubectl 插件是没有限制。唯一的要求是该名字在路径中是可执行的,并且不能与已知的 kubectl 命令重复。

要阅读完整的插件源码,或试试我创建的插件,请查看我的 kube-plugins-github 存储库。欢迎提交提案和补丁。


via: https://opensource.com/article/20/2/kubernetes-tmux-kubectl

作者:Abhishek Tamrakar 选题:lujun9972 译者:guevaraya 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出