分类 容器与云 下的文章

LogTool 是一组 Python 脚本,可帮助你找出 Overcloud 节点中问题的根本原因。

OpenStack 在其 Overcloud 节点和 Undercloud 主机上存储和管理了一堆日志文件。因此,使用 OSP 日志文件来排查遇到的问题并不是一件容易的事,尤其在你甚至都不知道是什么原因导致问题时。

如果你正处于这种情况,那么 LogTool 可以使你的生活变得更加轻松!它会为你节省本需要人工排查问题所需的时间和精力。LogTool 基于模糊字符串匹配算法,可提供过去发生的所有唯一错误和警告信息。你可以根据日志中的时间戳导出特定时间段(例如 10 分钟前、一个小时前、一天前等)的这些信息。

LogTool 是一组 Python 脚本,其主要模块 PyTool.py 在 Undercloud 主机上执行。某些操作模式使用直接在 Overcloud 节点上执行的其他脚本,例如从 Overcloud 日志中导出错误和警告信息。

LogTool 支持 Python 2 和 Python 3,你可以根据需要更改工作目录:LogTool\_Python2 or LogTool\_Python3

操作方式

1、从 Overcloud 日志中导出错误和警告信息

此模式用于从过去发生的 Overcloud 节点中提取 错误警告 信息。作为用户,系统将提示你提供“开始时间”和“调试级别”,以用于提取错误或警告消息。例如,如果在过去 10 分钟内出了问题,你则可以只提取该时间段内的错误和警告消息。

此操作模式将为每个 Overcloud 节点生成一个包含结果文件的目录。结果文件是经过压缩的简单文本文件(*.gz),以减少从 Overcloud 节点下载所需的时间。将压缩文件转换为常规文本文件,可以使用 zcat 或类似工具。此外,Vi 的某些版本和 Emacs 的任何最新版本均支持读取压缩数据。结果文件分为几部分,并在底部包含目录。

LogTool 可以即时检测两种日志文件:标准和非标准。在标准文件中,每条日志行都有一个已知的和已定义的结构:时间戳、调试级别、信息等等。在非标准文件中,日志的结构未知。例如,它可能是第三方的日志。在目录中,你可以找到每个部分的“名称 –> 行号”例如:

  • 原始数据 - 从标准 OSP 日志中提取的错误/警告消息: 这部分包含所有提取的错误/警告消息,没有任何修改或更改。这些消息是 LogTool 用于模糊匹配分析的原始数据。
  • 统计信息 - 每个标准 OSP 日志的错误/警告信息数量: 在此部分,你将找到每个标准日志文件的错误和警告数量。这些信息可以帮助你了解用于排查问题根本原因的潜在组件。
  • 统计信息 - 每个标准 OSP 日志文件的唯一消息: 这部分提供指定时间戳内的唯一的错误和警告消息。有关每个唯一错误或警告的更多详细信息,请在“原始数据”部分中查找相同的消息。
  • 统计信息 - 每个非标准日志文件在任意时间的唯一消息: 此部分包含非标准日志文件中的唯一消息。遗憾的是,LogTool 无法像标准日志文件那样的处理方式处理这些日志文件。因此,在你提取“特定时间”的日志信息时会被忽略,你会看到过去创建的所有唯一的错误/警告消息。因此,首先,向下滚动到结果文件底部的目录并查看其部分-使用目录中的行索引跳到相关部分,其中第 3、4 和 5 行的信息最重要。

2、从 Overcloud 节点下载所有日志

所有 Overcloud 节点的日志将被压缩并下载到 Undercloud 主机上的本地目录。

3、所有 Overcloud 日志中搜索字符串

该模式“grep”(搜索)由用户在所有 Overcloud 日志上提供的字符串。例如,你可能希望查看特定请求的所有日志消息,例如,“Create VM”的失败的请求 ID。

4、检查 Overcloud 上当前的 CPU、RAM 和磁盘使用情况

该模式显示每个 Overcloud 节点上的当前 CPU、RAM 和磁盘信息。

5、执行用户脚本

该模式使用户可以在 Overcloud 节点上运行自己的脚本。例如,假设 Overcloud 部署失败,你就需要在每个控制器节点上执行相同的过程来修复该问题。你可以实现“替代方法”脚本,并使用此模式在控制器上运行它。

6、仅按给定的时间戳下载相关日志

此模式仅下载 Overcloud 上 “给定的时间戳”的“上次修改时间”的日志。例如,如果 10 分钟前出现错误,则与旧日志文件就没有关系,因此无需下载。此外,你不能(或不应)在某些错误报告工具中附加大文件,因此此模式可能有助于编写错误报告。

7、从 Undercloud 日志中导出错误和警告信息

这与上面的模式 1 相同。

8、在 Overcloud 上检查不正常的 docker

此模式用于在节点上搜索不正常的 Docker。

9、下载 OSP 日志并在本地运行 LogTool

此模式允许你从 Jenkins 或 Log Storage 下载 OSP 日志(例如,cougar11.scl.lab.tlv.redhat.com),并在本地分析。

10、在 Undercloud 上分析部署日志

此模式可以帮助你了解 Overcloud 或 Undercloud 部署过程中出了什么问题。例如,在overcloud_deploy.sh 脚本中,使用 --log 选项时会生成部署日志;此类日志的问题是“不友好”,你很难理解是什么出了问题,尤其是当详细程度设置为 vv 或更高时,使得日志中的数据难以读取。此模式提供有关所有失败任务的详细信息。

11、分析 Gerrit(Zuul)失败的日志

此模式用于分析 Gerrit(Zuul)日志文件。它会自动从远程 Gerrit 门下载所有文件(HTTP 下载)并在本地进行分析。

安装

GitHub 上有 LogTool,使用以下命令将其克隆到你的 Undercloud 主机:

git clone https://github.com/zahlabut/LogTool.git

该工具还使用了一些外部 Python 模块:

Paramiko

默认情况下,SSH 模块通常会安装在 Undercloud 上。使用以下命令来验证是否已安装:

ls -a /usr/lib/python2.7/site-packages | grep paramiko

如果需要安装模块,请在 Undercloud 上执行以下命令:

sudo easy_install pip
sudo pip install paramiko==2.1.1

BeautifulSoup

此 HTML 解析器模块仅在使用 HTTP 下载日志文件的模式下使用。它用于解析 Artifacts HTML 页面以获取其中的所有链接。安装 BeautifulSoup,请输入以下命令:

pip install beautifulsoup4

你还可以通过执行以下命令使用 requirements.txt 文件安装所有必需的模块:

pip install -r requirements.txt

配置

所有必需的参数都直接在 PyTool.py 脚本中设置。默认值为:

overcloud_logs_dir = '/var/log/containers'
overcloud_ssh_user = 'heat-admin'
overcloud_ssh_key = '/home/stack/.ssh/id_rsa'
undercloud_logs_dir ='/var/log/containers'
source_rc_file_path='/home/stack/'

用法

此工具是交互式的,因此要启动它,只需输入:

cd LogTool
python PyTool.py

排除 LogTool 故障

在运行时会创建两个日志文件:Error.logRuntime.log。请在你要打开的问题的描述中添加两者的内容。

局限性

LogTool 进行硬编码以处理最大 500 MB 的文件。

LogTool\_Python3 脚本

github.com/zahlabut/LogTool 获取。


via: https://opensource.com/article/20/1/logtool-root-cause-identification

作者:Arkady Shtempler 选题:lujun9972 译者:Morisun029 校对:wxy

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

命名空间是什么?你为什么需要它?

kubernetes 命名空间 namespace 是什么?正如 Shakespeare 以前写过的,我们所谓的命名空间,或者任何其他名字,就是虚拟集群。通过虚拟集群,意味着 kubernetes 可以在单个集群上提供多个 kubernetes 的集群,类似一个在其主机抽象出来的虚拟机。kubernetes 文档 中的解释:

kubernetes 在一个物理集群上提供了多个虚拟集群。这些虚拟集群被称为命名空间。

你为什么需要命名空间?一言以蔽之:隔离。

隔离有很多优点,如它提供了安全和干净的环境。如果你是基础设施的所属者,并且要为开发者提供环境,隔离就相当重要。你最不需要的就是,一个不熟悉你集群是如何搭建的人去修改系统配置 —— 这可能导致所有人都无法登录。

初始命名空间

一个集群的三个初始命名空间:defaultkube-systemkube-public。虽然技术上你可以用这三个命名空间作部署,但我还是推荐你把这三个命名空间留作系统配置用,而不是你的项目。

  • Default 用于某些没有指明命名空间的部署,这是一种快速创建混乱的做法,如果你在没有正确信息的情况下做了很多部署,将很难清理。我不会去动它,因为它只有这一个用途,而且在不止一种情况下误导过我。
  • Kube-system 是 Kubernetes 系统相关的所有对象组成的命名空间。任何对此命名空间的部署都可能是危险的操作,可能对系统本身造成不可挽回的破坏。没错,我试过;所以我不推荐。
  • Kube-public 所有人可读,但是这个命名空间是为系统保留的。

用命名空间来实现隔离

我用了多种方式通过命名空间来实现隔离。我经常用命名空间来把多个用户项目分割到不同的环境。这种方式可以有效防止跨项目的污染,因为命名空间提供了独立的环境。例如,用户可以安装不同版本的 Jenkins,如果它们的环境变量是在不同的命名空间,就不会冲突。

这种隔离对于清理也很有帮助。如果开发小组的多个项目突然被废弃,你可以用命令 kubectl delete ns <$NAMESPACENAME> 一键删除命名空间,清理命名空间内的所有东西。(请确认被删除的是正确的命名空间。我曾经在生产环境删除了错误的命名空间,这很不好。)

如果你是基础设施所有者,请谨慎操作,因为这可能会引发其他团队的的故障或引发其他问题。例如,如果你创建了一个特定的命名空间,里面有特殊的额外安全的 DNS 功能,但是其他人删除了它,那么命名空间内的所有 pod 和它们运行的应用都会被清空。所有的删除操作在真正实施之前都应该由同事(通过 GitOps)评审一下。

虽然官方文档不建议 10 人以下团队 使用多个命名空间,但出于架构需要,在我自己的集群上还是用了多个命名空间。集群越干净越好。

关于命名空间管理员应该知道的

首先,命名空间不能嵌套。部署只能在一个命名空间中进行。对于版本化项目,你不一定要用命名空间,你可以使用标签来区分有相同名字的版本化应用。命名空间使用配额来为不同的用户划分资源;例如,某个命名空间最多能有 x 个节点。最后,所有的命名空间对于该资源类型只能使用一个独一无二的名字。

命名空间命令操作

你需要安装 MinikubeHelmkubectl 命令行,才能使用下面的命名空间命令。我的文章《安全扫描你的 DevOps 流水线》中有它们的安装教程,你也可以去每个项目的官方主页去找安装教程。我使用的是最新的 Minikube。手动安装很快,第一次就能成功运行。

获取你的第一组命名空间:

jess@Athena:~$ kubectl get namespace
NAME            STATUS   AGE
default         Active   5m23s
kube-public     Active   5m24s
kube-system     Active   5m24s

创建一个命名空间:

jess@Athena:~$ kubectl create namespace athena
namespace/athena created

现在开发者可以部署到你创建的命名空间了;例如,这里是一个简短的 Helm chart:

jess@Athena:~$ helm install teset-deploy stable/redis --namespace athena
NAME: teset-deploy
LAST DEPLOYED: Sat Nov 23 13:47:43 2019
NAMESPACE: athena
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
` Please be patient while the chart is being deployed `
Redis can be accessed via port 6379 on the following DNS names from within your cluster:

teset-deploy-redis-master.athena.svc.cluster.local for read/write operations
teset-deploy-redis-slave.athena.svc.cluster.local for read-only operations

获取你的密码:

export REDIS_PASSWORD=$(kubectl get secret --namespace athena teset-deploy-redis -o jsonpath="{.data.redis-password}" | base64 --decode)

连接你的 redis 服务:

  1. 运行一个你可以作为客户端用的 Redis pod:
kubectl run --namespace athena teset-deploy-redis-client --rm --tty -i --restart='Never' \
       --env REDIS_PASSWORD=$REDIS_PASSWORD \
       --image docker.io/bitnami/redis:5.0.7-debian-9-r0 -- bash 
  1. 使用 Redis CLI 连接:
redis-cli -h teset-deploy-redis-master -a $REDIS_PASSWORD
redis-cli -h teset-deploy-redis-slave -a $REDIS_PASSWORD

从集群外连接你的数据库:

kubectl port-forward --namespace athena svc/teset-deploy-redis-master 6379:6379 &
redis-cli -h 127.0.0.1 -p 6379 -a $REDIS_PASSWORD

现在这一套部署已经完成了,你有一个在命名空间 test-deploy 中部署的 chart。

查看你的命名空间中有哪些 pod:

jess@Athena:~$ kubectl get pods --namespace athena
NAME                            READY   STATUS  RESTARTS   AGE
teset-deploy-redis-master-0   1/1       Running   0             2m38s
teset-deploy-redis-slave-0      1/1     Running   0             2m38s
teset-deploy-redis-slave-1      1/1     Running   0             90s

现在,你已经正式把你的应用隔离到了一个命名空间,创建了一个只在内部通信的虚拟集群。

一键删除所有东西:

jess@Athena:~$ kubectl delete namespace athena
namespace "athena" deleted

因为这会删除应用的所有内部配置,所以这个删除操作可能会持续一段时间,持续时间取决于你的部署到底有多大。

再次检查一下所有东西是否被删除了:

jess@Athena:~$ kubectl get pods --all-namespaces
NAMESPACE       NAME                            READY   STATUS  RESTARTS   AGE
kube-system   coredns-5644d7b6d9-4vxv6          1/1     Running   0             32m
kube-system   coredns-5644d7b6d9-t5wn7          1/1     Running   0             32m
kube-system   etcd-minikube                     1/1     Running   0             31m
kube-system   kube-addon-manager-minikube       1/1     Running   0             32m
kube-system   kube-apiserver-minikube           1/1     Running   0             31m
kube-system   kube-controller-manager-minikube  1/1     Running   0             31m
kube-system   kube-proxy-5tdmh                  1/1     Running   0             32m
kube-system   kube-scheduler-minikube           1/1     Running   0             31m
kube-system   storage-provisioner               1/1     Running   0             27m

这是一个所有 pod 及它们存在于的已知命名空间的列表。你可以看到,之前创建的应用和命名空间现在已经不在了。

命名空间实践

当前我是出于安全考虑才使用命名空间,如限制用户的权限。你可以限制所有的东西 —— 从哪些角色可以访问命名空间,到命名空间可使用的集群资源(CPU 等)的配额等级。例如,我通过资源配额和 基于角色的访问控制 role-based access control (RBAC)配置来确保只有允许的服务账号可以访问命名空间。

对于隔离方面的安全,我不希望我的私人 Jenkins 应用可以通过一个信任的本地网络被当做一个有公共 IP 地址的安全镜像来访问(我不得不假定,可能会被侵袭)。

如果你很难提前计算出到底要在你的云平台上部署多少节点(或者,就我而言,是在搞崩我的家庭服务器之前我能部署多少个),那么命名空间在预算方面也很有用。虽然这超出了本文的讨论范围,而且很复杂,但值得你去调研和使用来防止你的集群过分扩展。

总结

命名空间是一个很好的隔离项目和应用的方法。本文仅是一个关于命名空间的简短介绍,所以我建议你更深入地研究下命名空间,在你的实践中更多地去使用它们。


via: https://opensource.com/article/19/12/kubernetes-namespaces

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

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

Toolbox 使你可以在容器中分类和管理开发环境,而无需 root 权限或手动添加卷。它创建一个容器,你可以在其中安装自己的命令行工具,而无需在基础系统中安装它们。当你没有 root 权限或无法直接安装程序时,也可以使用它。本文会介绍 Toolbox 及其功能。

安装 Toolbox

Silverblue 默认包含 Toolbox。对于 Workstation 和 Server 版本,你可以使用 dnf install toolbox 从默认仓库中获取它。

创建 Toolbox

打开终端并运行 toolbox enter。程序将自动请求许可来下载最新的镜像,创建第一个容器并将你的 shell 放在该容器中。

$ toolbox enter
No toolbox containers found. Create now? [y/N] y
Image required to create toolbox container.
Download registry.fedoraproject.org/f30/fedora-toolbox:30 (500MB)? [y/N]: y

当前,Toolbox 和你的基本系统之间没有区别。你的文件系统和软件包未曾改变。下面是一个使用仓库的示例,它包含 ~/src/resume 文件夹下的简历的文档源文件。简历是使用 pandoc 工具构建的。

$ pwd
/home/rwaltr
$ cd src/resume/
$ head -n 5 Makefile
all: pdf html rtf text docx

pdf: init
 pandoc -s -o BUILDS/resume.pdf markdown/*

$ make pdf
bash: make: command not found
$ pandoc -v
bash: pandoc: command not found

这个 toolbox 没有构建简历所需的程序。你可以通过使用 dnf 安装工具来解决此问题。由于正在容器中运行,因此不会提示你输入 root 密码。

$ sudo dnf groupinstall "Authoring and Publishing" -y && sudo dnf install pandoc make -y
...
$ make all #Successful builds
mkdir -p BUILDS
pandoc -s -o BUILDS/resume.pdf markdown/*
pandoc -s -o BUILDS/resume.html markdown/*
pandoc -s -o BUILDS/resume.rtf markdown/*
pandoc -s -o BUILDS/resume.txt markdown/*
pandoc -s -o BUILDS/resume.docx markdown/*
$ ls BUILDS/
resume.docx  resume.html  resume.pdf  resume.rtf  resume.txt

运行 exit 可以退出 toolbox。

$ cd BUILDS/
$ pandoc --version || ls
pandoc 2.2.1
Compiled with pandoc-types 1.17.5.4, texmath 0.11.1.2, skylighting 0.7.5
...
for a particular purpose.
resume.docx  resume.html  resume.pdf  resume.rtf  resume.txt
$ exit
logout
$ pandoc --version || ls
bash: pandoc: command not found...
resume.docx  resume.html  resume.pdf  resume.rtf  resume.txt

你会在主目录中得到由 toolbox 创建的文件。而在 toolbox 中安装的程序无法在外部访问。

提示和技巧

本介绍仅涉及 toolbox 的表面。还有一些其他提示,但是你也可以查看官方文档

  • toolbox –help 会显示 Toolbox 的手册页。
  • 你可以一次有多个 toolbox。使用 toolbox create -c Toolboxnametoolbox enter -c Toolboxname
  • Toolbox 使用 Podman 来完成繁重的工作。使用 toolbox list 可以查找 Toolbox 创建的容器的 ID。Podman 可以使用这些 ID 来执行 rmstop 之类的操作。 (你也可以在此文章中阅读有关 Podman 的更多信息。)

via: https://fedoramagazine.org/a-quick-introduction-to-toolbox-on-fedora/

作者:Ryan Walter 选题:lujun9972 译者:geekpi 校对:wxy

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

Kubernetes 是一款生产级的开源系统,用于容器化应用程序的自动部署、扩展和管理。本文关于使用 Kubernetes 来管理容器。

“容器”已成为最新的流行语之一。但是,这个词到底意味着什么呢?说起“容器”,人们通常会把它和 Docker 联系起来,Docker 是一个被定义为软件的标准化单元容器。该容器将软件和运行软件所需的环境封装到一个易于交付的单元中。

容器是一个软件的标准单元,用它来打包代码及其所有依赖项,这样应用程序就可以从一个计算环境到另一个计算环境快速可靠地运行。容器通过创建类似于 ISO 镜像的方式来实现此目的。容器镜像是一个轻量级的、独立的、可执行的软件包,其中包含运行应用程序所需的所有信息,包括代码、运行时、系统工具、系统库和设置。

容器镜像在运行时变成容器,对于 Docker 容器,镜像在 Docker 引擎上运行时变成容器。容器将软件与环境隔离开来,确保不同环境下的实例,都可以正常运行。

什么是容器管理?

容器管理是组织、添加或替换大量软件容器的过程。容器管理使用软件来自动化创建、部署和扩展容器。这一过程就需要容器编排,容器编排是一个自动对基于容器的应用程序进行部署、管理、扩展、联网和提供可用性的工具。

Kubernetes

Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,它有助于配置和自动化。它最初由 Google 开发,拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、技术支持和工具得到广泛应用。

Google 在 2014 年开源了 Kubernetes 项目。Kubernetes 建立在 Google 十五年大规模运行生产工作负载的经验基础上,并结合了社区中最好的想法和实践以及声明式句法的使用。

下面列出了与Kubernetes生态系统相关的一些常用术语。

Pod:Pod 是 Kubernetes 应用程序的基本执行单元,是你创建或部署的 Kubernetes 对象模型中的最小和最简单的单元。Pod 代表在 Kubernetes 集群上运行的进程。

Pod 将运行中的容器、存储、网络 IP(唯一)和控制容器应如何运行的命令封装起来。它代表 Kubernetes 生态系统内的单个部署单元,代表一个应用程序的单个实例,该程序可能包含一个或多个紧密耦合并共享资源的容器。

Kubernetes 集群中的 Pod 有两种主要的使用方式。第一种是运行单个容器。即“一个容器一个 Pod”,这种方式是最常见的。第二种是运行多个需要一起工作的容器。

Pod 可能封装一个由紧密关联且需要共享资源的多个同位容器组成的应用程序。

副本集 ReplicaSet :副本集的目的是维护在任何给定时间运行的一组稳定的副本容器集。 副本集包含有关一个特定 Pod 应该运行多少个副本的信息。为了创建多个 Pod 以匹配副本集条件,Kubernetes 使用 Pod 模板。副本集与其 Pod 的链接是通过后者的 metas.ownerReferences 字段实现,该字段指定哪个资源拥有当前对象。

服务 Services :服务是一种抽象,用来公开一组 Pod 功能。使用 Kubernetes,你无需修改应用程序即可使用陌生服务发现机制。Kubernetes 给 Pod 提供了其自己的 IP 地址和一组 Pod 的单个 DNS 名称,并且可以在它们之间负载平衡。

服务解决的一个主要问题是 Web 应用程序前端和后端的集成。由于 Kubernetes 将幕后的 IP 地址提供给 Pod,因此当 Pod 被杀死并复活时,IP 地址会更改。这给给定的后端 IP 地址连接到相应的前端 IP 地址带来一个大问题。服务通过在 Pod 上提供抽象来解决此问题,类似于负载均衡器。

Volumes : Kubernetes 卷具有明确的生命周期,与围绕它的 Pod 相同。 因此,卷超过了 Pod 中运行的任何容器的寿命,并且在容器重新启动后保留了数据。当然,当 Pod 不存在时,该卷也将不再存在。也许比这更重要的是 Kubernetes 支持多种类型的卷,并且 Pod 可以同时使用任意数量的卷。

卷的核心只是一个目录,其中可能包含一些数据,Pod 中的容器可以访问该目录。该目录是如何产生的,它后端基于什么存储介质,其中的数据内容是什么,这些都由使用的特定卷类型来决定的。

为什么选择 Kubernetes?

容器是捆绑和运行应用程序的好方法。在生产环境中,你需要管理运行应用程序的容器,并确保没有停机时间。例如,如果一个容器发生故障,则需要启动另一个容器。如果由系统自动实现这一操作,岂不是更好? Kubernetes 就是来解决这个问题的!Kubernetes 提供了一个框架来弹性运行分布式系统。该框架负责扩展需求、故障转移、部署模式等。例如,Kubernetes 可以轻松管理系统的金丝雀部署。

Kubernetes 为用户提供了:

  1. 服务发现和负载平衡
  2. 存储编排
  3. 自动退出和回退
  4. 自动打包
  5. 自我修复
  6. 秘密配置管理

Kubernetes 可以做什么?

在本文中,我们将会看到一些从头构建 Web 应用程序时如何使用 Kubernetes 的代码示例。我们将在 Python 中使用 Flask 创建一个简单的后端服务器。

对于那些想从头开始构建 Web 应用程序的人,有一些前提条件,即:

  1. 对 Docker、Docker 容器和 Docker 镜像的基本了解。可以访问这里快速了解。
  2. 系统中应该安装 Docker。
  3. 系统中应该安装 Kubernetes,有关如何在本地计算机上安装的说明,请访问这里

现在,创建一个目录,如下代码片段所示:

mkdir flask-kubernetes/app && cd flask-kubernetes/app

接下来,在 flask-kubernetes/app 目录中,创建一个名为 main.py 的文件,如下面的代码片段所示:

touch main.py

在新创建的 main.py 文件中,粘贴下面代码:

from flask import Flask
app = Flask(__name__)
 
@app.route("/")
def hello():
    return "Hello from Kubernetes!"
 
if __name__ == "__main__":
    app.run(host='0.0.0.0')

使用下面命令在本地安装 Flask:

pip install Flask==0.10.1

Flask 安装后,执行下面的命令:

python app.py

应该在本地 5000 端口运行 Flask 服务器,这是 Flask 应用程序的默认端口,并且你可以在 http://localhost:5000 上看到输出 “Hello from Kubernetes!”。服务器在本地运行之后,我们创建一个供 Kubernetes 使用的 Docker 镜像。创建一个名为 Dockerfile 的文件,并将以下代码片段粘贴到其中:

FROM python:3.7
 
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN pip install -r requirements.txt
 
EXPOSE 5000
CMD ["python", "/app/main.py"]

Dockerfile 文件的说明如下:

  1. Docker 将从 DockerHub 获取 Python 3.7 镜像。
  2. 将在镜像中创建一个应用程序目录。
  3. 它将一个 /app 目录设置为工作目录。
  4. 将内容从主机中的应用程序目录复制到镜像应用程序目录。
  5. 发布端口 5000。
  6. 最后,它运行命令,启动 Flask 服务器。

接下来,我们将使用以下命令创建 Docker 镜像:

docker build -f Dockerfile -t flask-kubernetes:latest .

创建 Docker 镜像后,我们可以使用以下命令在本地运行该镜像进行测试:

docker run -p 5001:5000 flask-kubernetes

通过运行容器在本地完成测试之后,我们需要在 Kubernetes 中部署它。我们将首先使用 kubectl 命令验证 Kubernetes 是否正在运行。如果没有报错,则说明它正在工作。如果有报错,请参考该信息

接下来,我们创建一个部署文件。这是一个 Yaml 文件,其中包含有关 Kubernetes 的说明,该说明涉及如何以声明性的方式创建 Pod 和服务。因为我们有 Flask Web 应用程序,我们将创建一个 deployment.yaml 文件,并在其中包含 Pod 和服务声明。

创建一个名为 deployment.yaml 的文件并向其中添加以下内容,然后保存:

apiVersion: v1
kind: Service
metadata:
  name: flask-kubernetes -service
spec:
  selector:
    app: flask-kubernetes
  ports:
  - protocol: "TCP"
    port: 6000
    targetPort: 5000
  type: LoadBalancer

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-kubernetes
spec:
  replicas: 4
  template:
    metadata:
      labels:
        app: flask-kubernetes
    spec:
      containers:
      - name: flask-kubernetes
        image: flask-kubernetes:latest
        imagePullPolicy: Never
        ports:
          - containerPort: 5000

使用以下命令将 yaml 文件发送到 Kubernetes:

kubectl apply -f deployment.yaml

如果执行以下命令,你会看到 Pod 正在运行:

kubectl get pods

现在,导航至 http://localhost:6000,你应该会看到 “Hello from Kubernetes!”消息。成功了! 该应用程序现在正在 Kubernetes 中运行!

Kubernetes 做不了什么?

Kubernetes 不是一个传统的,包罗万象的 PaaS(平台即服务)系统。 由于 Kubernetes 运行在容器级别而非硬件级别,因此它提供了 PaaS 产品共有的一些普遍适用功能,如部署、扩展、负载平衡、日志记录和监控。Kubernetes 为开发人员平台提供了构建块,但在重要的地方保留了用户的选择和灵活性。

  • Kubernetes 不限制所支持的应用程序的类型。如果应用程序可以在容器中运行,那么它应该可以在 Kubernetes 上更好地运行。
  • 它不部署和构建源代码。
  • 它不决定日志记录、监视或警报解决方案。
  • 它不提供或不要求配置语言/系统。它提供了一个声明式的 API 供所有人使用。
  • 它不提供或不采用任何全面的机器配置、维护、管理或自我修复系统。

via: https://opensourceforu.com/2019/11/demystifying-kubernetes/

作者:Abhinav Nath Gupta 选题:lujun9972 译者:Morisun029 校对:wxy

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

今天早上,我为未来潜在容器杂志画了一幅 OverlayFS 的漫画,我对这个主题感到兴奋,想写一篇关于它的博客来提供更多详细信息。

容器镜像很大

容器镜像可能会很大(尽管有些很小,例如 alpine linux 才 2.5MB)。Ubuntu 16.04 约为 27 MB,Anaconda Python 发行版为 800MB 至 1.5GB

你以镜像启动的每个容器都是原始空白状态,仿佛它只是为使用容器而复制的一份镜像拷贝一样。但是对于大的容器镜像,像 800MB 的 Anaconda 镜像,复制一份拷贝既浪费磁盘空间也很慢。因此 Docker 不会复制,而是采用叠加

叠加如何工作

OverlayFS,也被称为 联合文件系统联合挂载,它可让你使用 2 个目录挂载文件系统:“下层”目录和“上层”目录。

基本上:

  • 文件系统的下层目录是只读的
  • 文件系统的上层目录可以读写

当进程“读取”文件时,OverlayFS 文件系统驱动将在上层目录中查找并从该目录中读取文件(如果存在)。否则,它将在下层目录中查找。

当进程“写入”文件时,OverlayFS 会将其写入上层目录。

让我们使用 mount 制造一个叠加层!

这有点抽象,所以让我们制作一个 OverlayFS 并尝试一下!这将只包含一些文件:我将创建上、下层目录,以及用来挂载合并的文件系统的 merged 目录:

$ mkdir upper lower merged work
$ echo "I'm from lower!" > lower/in_lower.txt
$ echo "I'm from upper!" > upper/in_upper.txt
$ # `in_both` is in both directories
$ echo "I'm from lower!" > lower/in_both.txt
$ echo "I'm from upper!" > upper/in_both.txt

合并上层目录和下层目录非常容易:我们可以通过 mount 来完成!

$ sudo mount -t overlay overlay
    -o lowerdir=/home/bork/test/lower,upperdir=/home/bork/test/upper,workdir=/home/bork/test/work
    /home/bork/test/merged

在执行此操作时,我不断收到一条非常烦人的错误消息,内容为:mount: /home/bork/test/merged: special device overlay does not exist.。这条消息是错误的,实际上只是意味着我指定的一个目录缺失(我写成了 ~/test/merged,但它没有被展开)。

让我们尝试从 OverlayFS 中读取其中一个文件!文件 in_both.txt 同时存在于 lower/upper/ 中,因此应从 upper/ 目录中读取该文件。

$ cat merged/in_both.txt
"I'm from upper!

可以成功!

目录的内容就是我们所期望的:

find lower/ upper/ merged/
lower/
lower/in_lower.txt
lower/in_both.txt
upper/
upper/in_upper.txt
upper/in_both.txt
merged/
merged/in_lower.txt
merged/in_both.txt
merged/in_upper.txt

创建新文件时会发生什么?

$ echo 'new file' > merged/new_file
$ ls -l */new_file
-rw-r--r-- 1 bork bork 9 Nov 18 14:24 merged/new_file
-rw-r--r-- 1 bork bork 9 Nov 18 14:24 upper/new_file

这是有作用的,新文件会在 upper 目录创建。

删除文件时会发生什么?

读写似乎很简单。但是删除会发生什么?开始试试!

$ rm merged/in_both.txt

发生了什么?让我们用 ls 看下:

ls -l upper/in_both.txt  lower/lower1.txt  merged/lower1.txt
ls: cannot access 'merged/in_both.txt': No such file or directory
-rw-r--r-- 1 bork bork    6 Nov 18 14:09 lower/in_both.txt
c--------- 1 root root 0, 0 Nov 18 14:19 upper/in_both.txt

所以:

  • in_both.txt 仍在 lower 目录中,并且保持不变
  • 它不在 merged 目录中。到目前为止,这就是我们所期望的。
  • 但是在 upper 中发生的事情有点奇怪:有一个名为 upper/in_both.txt 的文件,但是它是字符设备?我想这就是 overlayfs 驱动表示删除的文件的方式。

如果我们尝试复制这个奇怪的字符设备文件,会发生什么?

$ sudo cp upper/in_both.txt upper/in_lower.txt
cp: cannot open 'upper/in_both.txt' for reading: No such device or address

好吧,这似乎很合理,复制这个奇怪的删除信号文件并没有任何意义。

你可以挂载多个“下层”目录

Docker 镜像通常由 25 个“层”组成。OverlayFS 支持具有多个下层目录,因此你可以运行:

mount -t overlay overlay
      -o lowerdir:/dir1:/dir2:/dir3:...:/dir25,upperdir=...

因此,我假设这是有多个 Docker 层的容器的工作方式,它只是将每个层解压缩到一个单独的目录中,然后要求 OverlayFS 将它们全部合并在一起,并使用一个空的上层目录,容器将对其进行更改。

Docker 也可以使用 btrfs 快照

现在,我使用的是 ext4,而 Docker 使用 OverlayFS 快照来运行容器。但是我曾经用过 btrfs,接着 Docker 将改为使用 btrfs 的写时复制快照。(这是 Docker 何时使用哪种存储驱动的列表)

以这种方式使用 btrfs 快照会产生一些有趣的结果:去年某个时候,我在笔记本上运行了数百个临时的 Docker 容器,这导致我用尽了 btrfs 元数据空间(像这个人一样)。这真的很令人困惑,因为我以前从未听说过 btrfs 元数据,而且弄清楚如何清理文件系统以便再次运行 Docker 容器非常棘手。(这个 docker github 上的提案描述了 Docker 和 btrfs 的类似问题)

以简单的方式尝试容器功能很有趣!

我认为容器通常看起来像是在做“复杂的”事情,我认为将它们分解成这样很有趣。你可以运行一条 mount 咒语,而实际上并没有做任何与容器相关的其他事情,看看叠加层是如何工作的!


via: https://jvns.ca/blog/2019/11/18/how-containers-work–overlayfs/

作者:Julia Evans 选题:lujun9972 译者:geekpi 校对:wxy

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

了解如何使用 Ansible 在容器中执行命令。

容器和 Ansible 可以很好地融合在一起:从管理和编排到供应和构建。在本文中,我们将重点介绍构建部分。

如果你熟悉 Ansible,就会知道你可以编写一系列任务,ansible-playbook 命令将为你执行这些任务。你知道吗,如果你编写 Dockerfile 并运行 podman build,你还可以在容器环境中执行此类命令,并获得相同​​的结果。

这是一个例子:

- name: Serve our file using httpd
  hosts: all
  tasks:
  - name: Install httpd
    package:
      name: httpd
      state: installed
  - name: Copy our file to httpd’s webroot
    copy:
      src: our-file.txt
      dest: /var/www/html/

你可以在 Web 服务器本地或容器中执行这个剧本,并且只要你记得先创建 our-file.txt,它就可以工作。

但是这里缺少了一些东西。你需要启动(并配置)httpd 以便提供文件。这是容器构建和基础架构供应之间的区别:构建镜像时,你只需准备内容;而运行容器是另一项任务。另一方面,你可以将元数据附加到容器镜像,它会默认运行命令。

这有个工具可以帮助。试试看 ansible-bender 怎么样?

$ ansible-bender build the-playbook.yaml fedora:30 our-httpd

该脚本使用 ansible-bender 对 Fedora 30 容器镜像执行该剧本,并将生成的容器镜像命名为 our-httpd

但是,当你运行该容器时,它不会启动 httpd,因为它不知道如何操作。你可以通过向该剧本添加一些元数据来解决此问题:

- name: Serve our file using httpd
  hosts: all
  vars:
    ansible_bender:
      base_image: fedora:30
      target_image:
        name: our-httpd
        cmd: httpd -DFOREGROUND
  tasks:
  - name: Install httpd
    package:
      name: httpd
      state: installed
  - name: Listen on all network interfaces.
    lineinfile:    
      path: /etc/httpd/conf/httpd.conf  
      regexp: '^Listen '
      line: Listen 0.0.0.0:80  
  - name: Copy our file to httpd’s webroot
    copy:
      src: our-file.txt
      dest: /var/www/html

现在你可以构建镜像(从这里开始,请以 root 用户身份运行所有命令。目前,Buildah 和 Podman 不会为无 root 容器创建专用网络):

# ansible-bender build the-playbook.yaml
PLAY [Serve our file using httpd] ****************************************************
                                                                                                                                                                             
TASK [Gathering Facts] ***************************************************************    
ok: [our-httpd-20191004-131941266141-cont]

TASK [Install httpd] *****************************************************************
loaded from cache: 'f053578ed2d47581307e9ba3f64f4b4da945579a082c6f99bd797635e62befd0'
skipping: [our-httpd-20191004-131941266141-cont]

TASK [Listen on all network interfaces.] *********************************************
changed: [our-httpd-20191004-131941266141-cont]

TASK [Copy our file to httpd’s webroot] **********************************************
changed: [our-httpd-20191004-131941266141-cont]

PLAY RECAP ***************************************************************************
our-httpd-20191004-131941266141-cont : ok=3    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Getting image source signatures
Copying blob sha256:4650c04b851c62897e9c02c6041a0e3127f8253fafa3a09642552a8e77c044c8
Copying blob sha256:87b740bba596291af8e9d6d91e30a01d5eba9dd815b55895b8705a2acc3a825e
Copying blob sha256:82c21252bd87532e93e77498e3767ac2617aa9e578e32e4de09e87156b9189a0
Copying config sha256:44c6dc6dda1afe28892400c825de1c987c4641fd44fa5919a44cf0a94f58949f
Writing manifest to image destination
Storing signatures
44c6dc6dda1afe28892400c825de1c987c4641fd44fa5919a44cf0a94f58949f
Image 'our-httpd' was built successfully \o/

镜像构建完毕,可以运行容器了:

# podman run our-httpd
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.88.2.106. Set the 'ServerName' directive globally to suppress this message

是否提供文件了?首先,找出你容器的 IP:

# podman inspect -f '{{ .NetworkSettings.IPAddress }}' 7418570ba5a0
10.88.2.106

你现在可以检查了:

$ curl http://10.88.2.106/our-file.txt
Ansible is ❤

你文件内容是什么?

这只是使用 Ansible 构建容器镜像的介绍。如果你想了解有关 ansible-bender 可以做什么的更多信息,请查看它的 GitHub 页面。构建快乐!


via: https://opensource.com/article/19/10/building-container-images-ansible

作者:Tomas Tomecek 选题:lujun9972 译者:geekpi 校对:wxy

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