2020年4月

本文是 Python 之禅特别系列的第三篇,此篇着眼于其中第五与第六条原则:扁平与稀疏。

Python 之禅 之所以得名,正是由于它那简明扼要的规则被设计出的意图在于让读者进行深入地思考,而绝不单是为编程提供一份易于遵守的指南。

读后不去三思其意,断然难以体会 Python 之禅的妙处。倘若 Python 之禅仅仅罗列出一组清晰的法则,那法则之间的矛盾是一种缺憾,然而作为引导读者沉思最优方案沉思的工具,矛盾却是绝佳的。

扁平胜过嵌套 Flat is better than nested

迫于对缩进的强硬要求,Python 对“扁平化”的需求显然远超它者。其余编程语言为了缓解对缩进的需求,通常会在嵌套结构里加入一种“作弊”的手段。为了理解这一点,不妨一同来看看 JavaScript。

JavaScript 本质上是异步的,这意味着程序员用 JavaScript 写的代码会用到大量的回调函数。

a(function(resultsFromA) {
  b(resultsFromA, function(resultsfromB) {
    c(resultsFromC, function(resultsFromC) {
      console.log(resultsFromC)
   }
  }
}

忽略这段代码的具体内容,只去观察这段代码的形状与缩进带来一个最右边的点的方式。这种独特的“箭头”图形在我们扫看代码时格外扎眼,这种写法也因此被视作不可取,甚至得到了“回调地狱”的绰号。不过,在 JavaScript 中,这种反映嵌套关系的缩进可以通过“作弊”来回避。

a(function(resultsFromA) {
b(resultsFromA,
  function(resultsfromB) {
c(resultsFromC,
  function(resultsFromC) {
    console.log(resultsFromC)
}}}

Python 并没有提供这种作弊手段:每一级嵌套在代码中都如实的对应着一层缩进。因此,Python 深层的嵌套关系在视觉上也一定是深层嵌套的。这使得“回调地狱”的问题对于 Python 而言要比在 JavaScript 中严重得多:嵌套的回调函数必定带来缩进,而绝无使用花括号来“作弊”的可能。

这项挑战与 Python 之禅的指导原则相结合后,在我参与的库中催生出了一个优雅的解决方案。我们在 Twisted 框架里提出了 deferred 抽象,日后 JavaScript 中流行的 promise 抽象亦是受其启发而生。正是由于 Python 对整洁代码的坚守,方能推动 Python 开发者去发掘新的、强力的抽象。

future_value = future_result()
future_value.addCallback(a)
future_value.addCallback(b)
future_value.addCallback(c)

(现代 JavaScript 程序员也许会觉得这段代码十分眼熟:promise 着实受到了 Twisted 里 deferred 抽象的深远影响。)

稀疏胜过密集 Sparse is better than dense

最易降低代码密集程度的方法是引入嵌套。这种习惯也正是有关稀疏的原则要随着前一条提出的原因:在竭尽所能地减少嵌套之后,我们往往会遗留下密集的代码或数据结构。此处的密集,是指塞进过量信息的小段代码,它们会导致错误发生后的解析变得困难。

这种密集性唯有通过创造性的思考方可改善,此外别无捷径。Python 之禅并不为我们提供简单的解决方案,它只会指明改善代码的方向,而非提供“如何”去做的向导。

起身走走,泡个热水澡,抑或是闻闻花香。盘坐冥思,直至灵感袭来。当你终于得到启发,便是动身写代码之时。


via: https://opensource.com/article/19/12/zen-python-flat-sparse

作者:Moshe Zadka 选题:lujun9972 译者:caiichenr 校对:wxy

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

无论是 Nvidia 还是 Radeon 或者 Intel,它们的显卡都可能在 Linux 中有问题。当你要对图形问题进行故障排除时,首先要了解系统中装有哪种显卡。

Linux 有几个命令可以检查硬件信息。你可以使用它们来检查你有哪些显卡(也称为视频卡)。让我向你展示一些命令来获取 Linux 中的 GPU 信息。

在 Linux 命令行中检查显卡详细信息

使用 lspci 命令查找显卡

lspci 命令显示通过 PCI 外设组件互连 Peripheral Component Interconnect )总线连接的设备的信息。基本上,此命令提供有关系统从键盘和鼠标到声卡、网卡和显卡的所有外设的详细信息。

默认情况下,你会有大量的此类外设列表。这就是为什么你需要用 grep 命令过滤出显卡的原因:

lspci | grep VGA

这应该会显示一行有关你显卡的信息:

abhishek@itsfoss:~$ lspci | grep VGA
00:02.0 VGA compatible controller: Intel Corporation HD Graphics 620 (rev 02)

如你所见,我的系统中有 Intel HD 620 显卡。

在 Linux 中使用 lshw 命令获取显卡详细信息

lspci 命令足以查看你的显卡,但是并不能告诉你很多信息。你可以使用 lshw 命令获取有关它的更多信息。

此命令要求你有 root 用户权限。你需要以这种方式查找视频卡(显卡)信息:

sudo lshw -C video

正如你在下面的输出中看到的那样,此命令提供了有关显卡的更多信息,例如时钟频率、位宽、驱动等。

abhishek@itsfoss:~$ sudo lshw -C video
[sudo] password for abhishek:
  *-display
       description: VGA compatible controller
       product: HD Graphics 620
       vendor: Intel Corporation
       physical id: 2
       bus info: [email protected]:00:02.0
       version: 02
       width: 64 bits
       clock: 33MHz
       capabilities: pciexpress msi pm vga_controller bus_master cap_list rom
       configuration: driver=i915 latency=0
       resources: irq:139 memory:db000000-dbffffff memory:90000000-9fffffff ioport:f000(size=64) memory:c0000-dffff

附赠技巧:以图形方式检查显卡详细信息

并非必须使用命令行在 Linux 中查找显卡详细信息。大多数 Linux 发行版(或者应该说是桌面环境)在设置中提供了必要的详细信息。

例如,如果你使用的是 GNOME 桌面环境,那么可以进入“设置”的“关于”部分来检查详细信息。Ubuntu 20.04 中看上去像这样:

Graphics card information check graphically

我希望这个快速技巧对你有所帮助。你也可以使用相同的命令来查找网卡Linux 中的 CPU 信息

如果你有任何疑问或建议,请随时发表评论。


via: https://itsfoss.com/check-graphics-card-linux/

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

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

Ubuntu 20.04 LTS 版本还有不到一个月就发布了,Ubuntu 在这一个版本中对视觉效果作出了大变动,同时在性能方面也有所提高。

如果你还在使用 Ubuntu 18.04 LTS 版本,你会发现 Ubuntu 20.04 配合深色 Yaru 主题非常惊艳,看过 Ubuntu 20.04 的展示视频你就知道了。

感觉确实不错。如果你想在 4 月 23 日最终稳定版正式发布前率先使用 Ubuntu 20.04,也可以在官方网站上下载 beta 版本。尽管是测试版本,但它的稳定性并不差,同时你也可以在使用这个版本的过程中帮助 Ubuntu 团队进行测试。

你可以下载 每日构建 daily build 版并进行重新安装,如果你正在使用的是 Ubuntu 18.04 或 Ubuntu 19.10,也可以在现有系统的基础上直接升级到 Ubuntu 20.04 beta 版本。

从现有系统中升级是很方便的,因为你不会丢失系统设置和其他文件。与重新安装不同的是,你不需要从头开始重新安装所有的软件。当你切换到新版本时,你的主目录、应用程序(大部分)、文件都会保持原样。

如果你需要确认正在使用的 Ubuntu 版本,可以参考这篇文章

在本文中,我将会介绍如何升级到 Ubuntu 20.04 beta 版本。

如何将 Ubuntu 18.04/19.10 升级到 Ubuntu 20.04 beta

在你阅读后面的内容之前,我首先说明一些关于升级到 Ubuntu beta 版本的常见问题。

  • 版本升级的过程并不复杂,但在整个过程中需要有良好的网络连接,以便下载高达好几 GB 的数据。
  • 版本升级的过程中,第三方存储库(比如你自行添加的 PPA)会被禁用,有些 PPA 可能也和新版本不兼容,在版本升级完毕后,你可以手动启用这些 PPA。
  • 强烈建议将重要数据备份到外部的 USB 硬盘上。你只需要将各个目录下的重要文件直接复制到外部 USB 硬盘上保存即可。
  • 升级到新版本之后,就无法再回滚到之前的旧版本了,如果需要旧版本的系统,只能重新安装。
  • 如果你选择升级到 Ubuntu 20.04 beta 版本,那么在 Ubuntu 20.04 最终稳定版发布之后,你也不需要重新安装。只需要保持定期更新 Ubuntu 系统,届时你就可以直接用上最终稳定版了。
  • Ubuntu 16.04/17/18/19.04 都无法直接升级到 Ubuntu 20.04。

了解完上面的内容之后,下面开始从 Ubuntu 18.04/19.10 升级到 Ubuntu 20.04。

步骤 1:检查设置是否正确

进入“ 软件和升级 Software & Updates ”应用:

Software & Updates application in Ubuntu

在“ 升级 Updates ”选项卡中,设置“有任何新版本 Ubuntu 都提醒我”或“有 LTS 版本 Ubuntu 就提醒我”:

Ubuntu Upgrade Version Settings

设置完成后,系统会刷新软件库缓存。

步骤 2:安装系统更新

在上面的步骤完成之后,打开终端(在 Ubuntu 中可以使用 Ctrl+Alt+T 快捷键),然后使用以下命令更新 Ubuntu 系统

sudo apt update && sudo apt full-upgrade

apt full-upgradeapt dist-upgrade 的功能和 apt upgrade 大致相同,但对于系统版本的升级,apt full-upgrade 会在需要的情况下将当前已安装的软件移除掉。

更新安装完成后,系统可能会需要重新启动。在重新启动之后,就可以进入步骤 3 了。

步骤 3:使用更新管理器查找开发版本

在步骤 2 中已经安装了所有必要的更新,现在通过下面的命令打开更新管理器,其中 -d 参数表示需要查找开发版本:

update-manager -d

整个过程可能需要好几分钟,随后会提示有新版本的 Ubuntu 可用:

Availability of Ubuntu 20.04 in Ubuntu 19.10

在 Ubuntu 18.04 上的提示是这样的:

Availability of Ubuntu 20.04 in Ubuntu 18.04

然后点击对话框中的“ 升级 upgrade ”按钮。

步骤 4:开始升级到 Ubuntu 20.04 beta

接下来只要等待下载更新就可以了,遇到对话框直接点击 “OK” 即可。

点击“ 升级 upgrade ”按钮,然后按照提示进行操作。

在升级过程中,可能会有提示信息告知所有第三方源都已经禁用。有时候还会提示有哪些软件包需要升级或删除,以及是否需要保留一些已经过时了的软件包。一般情况下,我会选择直接删除。

整个升级过程通常会需要几个小时,但主要还是取决于实际的网速。升级完成后,系统会提示需要重新启动。

下面的视频展示了所有相关步骤。

由此可见,这个升级流程并不复杂。欢迎体验 Ubuntu 20.04 带来的新特性。

如果你有疑问或建议,欢迎在评论区留言。


via: https://itsfoss.com/upgrade-ubuntu-beta/

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

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

本文是 24 天 Linux 桌面特别系列的一部分。Fluxbox 对系统资源的占用非常轻量,但它拥有重要的 Linux 桌面功能,让你的用户体验轻松、高效、快捷。

桌面的概念可谓是仁者见仁智者见智。很多人把桌面看作一个家的基地,或者一个舒适的客厅,甚至是一个字面意义上的桌面,在其中放置着他们经常使用的记事本、最好的笔和铅笔,还有他们最喜欢的咖啡杯。KDE、 GNOME、Pantheon 等等在 Linux 上提供了这种舒适的生活方式。

但是对一些用户来说,桌面只是一个空荡荡的显示器空间,这是还没有任何可以自由浮动的应用程序窗口直接投射到他们的视网膜上的副作用。对于这些用户来说,桌面是一个空的空间,他们可以在上面运行应用程序 —— 无论是大型办公软件和图形套件,还是一个简单的终端窗口,或是来管理服务的托盘小程序。这种操作 POSIX 计算机的模式由来已久,该家族树的一支是 *box 窗口管理器:Blackbox、Fluxbox 和 Openbox。

Fluxbox 是一个 X11 系统的窗口管理器,它基于一个较老的名为 Blackbox 的项目。当我发现 Linux 时,Blackbox 的开发已进入衰退期,因此我就喜欢上了 Fluxbox ,此后我至少在一个以上的常用的系统上使用过它。它是用 C++ 编写的,并在 MIT 开源许可证下授权。

安装 Fluxbox

你很可能会在你的 Linux 发行版的软件库中找到 Fluxbox,但是你也可以在 Fluxbox.org 上找到它。如果你正在运行另外一个桌面,在同一个系统上安装 Fluxbox 是安全的,因为 Fluxbox 不会预设任何配置或附带的应用程序。

在安装 Fluxbox 后,注销你当前的桌面会话,以便你可以登录一个新的桌面会话。默认情况下,你的桌面会话管理器 (KDM、GDM、LightDM 或 XDM,取决于你的安装设置) 将继续让登录到之前的桌面,所以你在登录前必需要覆盖上一个桌面。

使用 GDM 覆盖一个桌面:

 title=

或者使用 KDM:

 title=

配置 Fluxbox 桌面

当你第一次登录到桌面时,屏幕基本是空的,因为 Fluxbox 提供的所有东西是面板(用于任务栏、系统托盘等等)和用于应用程序窗口的窗口装饰品。

 title=

如果你的发行版提供一个简单的 Fluxbox 桌面,你可以使用 feh 命令(你可能需要从你的发行版的软件库中安装它)来为你的桌面设置背景。这个命令有几个用于设置背景的选项,包括使用你选择的墙纸来填充屏幕的 --bg-fill 选项,来按比例缩放的 --bg-scale 等等选项。

$ feh --bg-fill ~/photo/oamaru/leaf-spiral.jpg

 title=

默认情况下,Fluxbox 自动生成一个菜单,在桌面上任意位置右键单击可用该菜单,这给予你访问应用程序的能力。根据你的发行版的不同,这个菜单可能非常小,也可能列出 /usr/share/applications 目录中的所有启动程序。

Fluxbox 配置是在文本文件中设置的,这些文本文件包含在 $HOME/.fluxbox 目录中。你可以:

  • keys 中设置键盘快捷键
  • startup 中启动的服务和应用程序
  • init 设置桌面首选项(例如工作区数量、面板位置等等)
  • menu 中设置菜单项

该文本配置文件非常易于推断,但是你也可以(并且是应该)阅读 Fluxbox 的文档

例如,这是我的典型菜单(或者说至少有它的基本结构):

# 为使用你自己的菜单,复制这些文本到 ~/.fluxbox/menu,然后编辑
# ~/.fluxbox/init ,并更改 session.menuFile 文件路径到 ~/.fluxbox/menu

[begin] (fluxkbox)
 [submenu] (apps) {}
  [submenu] (txt) {}
   [exec] (Emacs 23 (text\)) { x-terminal-emulator -T "Emacs (text)" -e /usr/bin/emacs -nw} <>
   [exec] (Emacs (X11\)) {/usr/bin/emacs} <>
   [exec] (LibreOffice) {/usr/bin/libreoffice}
  [end]
  [submenu] (code) {}
   [exec] (qtCreator) {/usr/bin/qtcreator}
   [exec] (eclipse) {/usr/bin/eclipse}
  [end]
  [submenu] (graphics) {}
   [exec] (ksnapshot) {/usr/bin/ksnapshot}
   [exec] (gimp) {/usr/bin/gimp}
   [exec] (blender) {/usr/bin/blender}
  [end]
  [submenu] (files) {}
   [exec] (dolphin) {/usr/bin/dolphin}
   [exec] (konqueror) { /usr/bin/kfmclient openURL $HOME }
  [end]
  [submenu] (network) {}
   [exec] (firefox) {/usr/bin/firefox}
   [exec] (konqueror) {/usr/bin/konqueror}
  [end]
 [end]
## 更改窗口管理器或工作环境
[submenu] (environments) {}
 [restart] (flux)  {/usr/bin/startfluxbox}
 [restart] (ratpoison)  {/usr/bin/ratpoison}
 [exec] (openIndiana) {/home/kenlon/qemu/startSolaris.sh}
[end]

[config] (config)
 [submenu] (styles) {}
  [stylesdir] (/usr/share/fluxbox/styles)
  [stylesdir] (~/.fluxbox/styles)
 [end]
[workspaces] (workspaces)
[reconfig] (reconfigure)
[restart] (restart)
[exit] (exeunt)
[end]

该菜单也提供一些首选项设置,例如,选择一个主题,从 Fluxbox 会话中重启或注销的能力。

我使用键盘快捷键来启动大多数的应用程序,这些快捷键写入到 keys 配置文件中。这里有一些示例(Mod4 按键是 Super 键,我使用其来指定全局快捷键):

# 打开应用程序
Mod4 t :Exec konsole
Mod4 k :Exec konqueror
Mod4 z :Exec fbrun
Mod4 e :Exec emacs
Mod4 f :Exec firefox
Mod4 x :Exec urxvt
Mod4 d :Exec dolphin
Mod4 q :Exec xscreensaver-command -activate
Mod4 3 :Exec ksnapshot

在这些快捷方式和一个打开的终端之间,在我工作日的大部分时间内很少使用鼠标,因此从一个控制器切换到另一个控制器不会浪费时间。并且因为 Fluxbox 很好地避开了控制器之间切换的方法,因此在其中操作没有一丝干扰。

为什么你应该使用 Fluxbox

Fluxbox 对系统资源的占用非常轻量,但是它拥有重要的功能,可以使你的用户体验轻松、快速、高效。它很容易定制,并且允许你定义你自己的工作流。你不必使用 Fluxbox 的面板,因为还有其它优秀的面板。你甚至可以鼠标中键点击并拖动两个独立的应用程序窗口到彼此之中,以便它们成为一个窗口,每个窗口都有自己的选项卡。

可能性是无穷的,所以今天就在你的 Linux 上尝试一下 Fluxbox 的简单稳定吧!


via: https://opensource.com/article/19/12/fluxbox-linux-desktop

作者:Seth Kenlon 选题:lujun9972 译者:robsean 校对:wxy

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

将流量引入 Kubernetes 树莓派集群的分步指南。

在本文中,我们将部署几个简单的网站,并学习如何使用 Traefik 将来自外部世界的流量引入到我们的集群中。之后,我们还将学习如何删除 Kubernetes 资源。让我们开始吧!

准备

要继续阅读本文,你只需要我们在上一篇文章中构建的 k3s 树莓派集群。由于你的集群将从网络上拉取镜像,因此该集群需要能够访问互联网。

出于解释目的,本文将显示一些配置文件和示例 HTML 文件。所有示例文件都可以在此处下载。

部署一个简单的网站

之前,我们使用 kubectl 进行了直接部署。但是,这不是典型的部署方法。一般情况都会使用 YAML 配置文件,这也是我们要在本文中使用的配置文件。我们将从顶部开始,并以自顶向下的方式创建该配置文件。

部署配置

首先是部署配置。配置如下所示,并在下面进行说明。我通常以 Kubernetes 文档中的示例为起点,然后根据需要对其进行修改。例如,下面的配置是复制了部署文档中的示例后修改的。

创建一个文件 mysite.yaml,其内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysite-nginx
  labels:
    app: mysite-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysite-nginx
  template:
    metadata:
      labels:
        app: mysite-nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

其中大部分是样板。重要的部分,我们会将该部署命名为 mysite-nginx,并为其加上同名的 app 标签。我们指定了一个 副本 replica ,这意味着将只创建一个 Pod。我们还指定了一个容器,我们将其命名为 nginx。我们将 镜像 image 指定为 nginx。这意味着在部署时,k3s 将从 DockerHub 下载 nginx 镜像并从中创建一个 Pod。最后,我们指定了 容器端口 containerPort 80,这只意味着在容器内部 Pod 会监听 80 端口。

我在上面强调了“在容器内部”,因为这是一个重要的区别。由于我们是按容器配置的,因此只能在容器内部访问它,并且进一步将其限制为内部网络。这对于允许多个容器在同一容器端口上监听所是必要的。换句话说,通过这种配置,其他一些 Pod 也可以在其容器端口 80 上侦听,并且不会与此容器冲突。为了提供对该 Pod 的正式访问权限,我们需要一个 服务 service 配置。

服务配置

在 Kubernetes 中, 服务 service 是一种抽象。它提供了一种访问 Pod 或 Pod 集合的方法。当连接到服务时,服务会路由到单个 Pod,或者如果定义了多个 Pod 副本,会通过负载均衡路由到多个 Pod。

可以在同一配置文件中指定该服务,这就是我们将在此处要做的。用 --- 分隔配置区域,将以下内容添加到 mysite.yaml 中:

---
apiVersion: v1
kind: Service
metadata:
  name: mysite-nginx-service
spec:
  selector:
    app: mysite-nginx
  ports:
    - protocol: TCP
      port: 80

在此配置中,我们将服务命名为 mysite-nginx-service。我们提供了一个 选择器 selector app: mysite-nginx。这是服务选择其路由到的应用程序容器的方式。请记住,我们为容器提供了 app 标签:mysite-nginx 。这就是服务用来查找我们的容器的方式。最后,我们指定服务协议为 TCP,在端口 80 上监听。

入口配置

入口 Ingress 配置指定了如何将流量从集群外部传递到集群内部的服务。请记住,k3s 预先配置了 Traefik 作为入口控制器。因此,我们将编写特定于 Traefik 的入口配置。将以下内容添加到 mysite.yaml 中(不要忘了用 --- 分隔):

---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: mysite-nginx-ingress
  annotations:
    kubernetes.io/ingress.class: "traefik"
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: mysite-nginx-service
          servicePort: 80

在此配置中,我们将入口记录命名为 mysite-nginx-ingress。我们告诉 Kubernetes,我们希望 traefik 成为我们的入口控制器,再加上 kubernetes.io/ingress.class 的注解。

规则 rules 部分中,我们基本上是说,当 http 流量进入时,并且 path 匹配 /(或其下的任何内容),将其路由到由 serviceName mysite-nginx-service 指定的 后端 backend 服务中,并将其路由到 servicePort 80。这会将传入的 HTTP 流量连接到我们之前定义的服务。

需要部署的东西

就配置而言,就是这样了。如果我们现在部署,我们将获得默认的 nginx 页面,但这不是我们想要的。让我们创建一些简单但可自定义的部署方式。创建具有以下内容的文件 index.html

<html>
<head><title>K3S!</title>
  <style>
    html {
      font-size: 62.5%;
    }
    body {
      font-family: sans-serif;
      background-color: midnightblue;
      color: white;
      display: flex;
      flex-direction: column;
      justify-content: center;
      height: 100vh;
    }
    div {
      text-align: center;
      font-size: 8rem;
      text-shadow: 3px 3px 4px dimgrey;
    }
  </style>
</head>
<body>
  <div>Hello from K3S!</div>
</body>
</html>

我们尚未介绍 Kubernetes 中的存储机制,因此在这里我们偷懒一下,仅将该文件存储在 Kubernetes 配置映射中。这不是我们推荐的部署网站的方式,但对于我们的目的来说是可行的。运行以下命令:

kubectl create configmap mysite-html --from-file index.html

该命令从本地文件 index.html 创建名为 mysite-html 配置映射 configmap 资源。这实际上是在 Kubernetes 资源中存储一个文件(或一组文件),我们可以在配置中调出该文件。它通常用于存储配置文件(因此而得名),我们在这里稍加滥用。在以后的文章中,我们将讨论 Kubernetes 中适当的存储解决方案。

创建配置映射后,让我们将其挂载在我们的 nginx 容器中。我们分两个步骤进行。首先,我们需要指定一个 volume 来调出配置映射。然后我们需要将该卷挂载到 nginx 容器中。通过在 mysite.yaml 中的 container 后面的 spec 标签下添加以下内容来完成第一步:

      volumes:
      - name: html-volume
        configMap:
          name: mysite-html

这告诉 Kubernetes 我们要定义一个名为 html-volume 的卷,并且该卷应包含名为 html-volume(我们在上一步中创建的)的配置映射的内容。

接下来,在 nginx 容器规范中的 端口 ports 下方,添加以下内容:

        volumeMounts:
        - name: html-volume
          mountPath: /usr/share/nginx/html

这告诉 Kubernetes,对于 nginx 容器,我们想在容器中的 /usr/share/nginx/html 路径上挂载名为 html-volume 的卷。 为什么要使用 /usr/share/nginx/html?那个位置就是 nginx 镜像提供 HTML 服务的地方。通过在该路径上挂载卷,我们用该卷内容替换了默认内容。

作为参考,配置文件的 deployment 部分现在应如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysite-nginx
  labels:
    app: mysite-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysite-nginx
  template:
    metadata:
      labels:
        app: mysite-nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html-volume
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html-volume
        configMap:
          name: mysite-html

部署它!

现在我们准备部署! 我们可以这样做:

kubectl apply -f mysite.yaml

你应该看到类似于以下内容:

deployment.apps/mysite-nginx created
service/mysite-nginx-service created
ingress.networking.k8s.io/mysite-nginx-ingress created

这意味着 Kubernetes 为我们指定的三个配置分别创建了资源。使用以下方法检查 Pod 的状态:

kubectl get pods

如果看到状态为 ContainerCreating,请给它一些时间并再次运行 kubectl get pods。通常,第一次会花一些时间,因为 k3s 必须下载 nginx 镜像来创建 Pod。一段时间后,你应该看到 Running 的状态。

尝试一下!

Pod 运行之后,就该尝试了。打开浏览器,然后在地址栏中输入 kmaster

恭喜你!你已经在 k3s 集群上部署了一个网站!

另一个

因此,现在我们有了一个运行单个网站的整个 k3s 集群。但是我们可以有更多的网站!如果我们要在同一集群中提供另一个网站怎么办?让我们看看如何做到这一点。

同样,我们需要部署一些东西。碰巧我的狗有一条她想让全世界都知道的信息,她想了好久了。因此,我专门为她制作了一些 HTML(可从示例 zip 文件中获得)。同样,我们将使用配置映射的技巧来托管这些 HTML。这次我们将把整个目录(html 目录)放到配置映射中,但是调用是相同的。

kubectl create configmap mydog-html --from-file html

现在,我们需要为此站点创建一个配置文件。它几乎与用于 mysite.yaml 的完全相同,因此首先将 mysite.yaml 复制为 mydog.yaml。现在将 mydog.yaml 修改为:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydog-nginx
  labels:
    app: mydog-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mydog-nginx
  template:
    metadata:
      labels:
        app: mydog-nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html-volume
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html-volume
        configMap:
          name: mydog-html
---
apiVersion: v1
kind: Service
metadata:
  name: mydog-nginx-service
spec:
  selector:
    app: mydog-nginx
  ports:
    - protocol: TCP
      port: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: mydog-nginx-ingress
  annotations:
    kubernetes.io/ingress.class: "traefik"
    traefik.frontend.rule.type: PathPrefixStrip
spec:
  rules:
  - http:
      paths:
      - path: /mydog
        backend:
          serviceName: mydog-nginx-service
          servicePort: 80

我们只需进行搜索并将 mysite 替换为 mydog即可完成大多数修改。其他两个修改在入口部分中。我们将 path 更改为 /mydog,并添加了一个注解 traefik.frontend.rule.type: PathPrefixStrip

/mydog 路径的规范指示 Traefik 将以 /mydog 路径开头的所有传入请求路由到 mydog-nginx-service。任何其他路径将继续路由到 mysite-nginx-service

新的注解 PathPrefixStrip 告诉 Traefik 在将请求发送到 mydog-nginx-service 之前先去除前缀 /mydog。我们这样做是因为 mydog-nginx 应用程序不需要前缀。这意味着我们可以简单地通过更改入口记录中的前缀来更改挂载的服务的位置。

现在我们可以像以前一样进行部署:

kubectl apply -f mydog.yaml

现在,我的狗的消息应该可以在 http://kmaster/mydog/ 上找到。

呼!消息发出去了!也许今晚我们都可以睡一觉。

因此,现在,我们有了一个 k3s 集群,该集群托管了两个网站,Traefik 根据路径名决定将请求传递给哪个服务!但是,不仅限于基于路径的路由,我们也可以使用基于主机名的路由,我们将在以后的文章中进行探讨。

另外,我们刚刚托管的网站是标准的未加密 HTML 网站,而如今的所有内容都使用 SSL/TLS 加密。在我们的下一篇文章中,我们将为 k3s 集群添加支持以托管 SSL/TLS HTTPS 站点!

清理

在开始之前,由于本文主要涉及的是示例站点,因此我想向你展示如何删除内容,以防万一你不希望将这些示例丢在集群中。

对于大多数配置,只需使用与部署时使用的相同配置文件运行 delete 命令即可撤消配置。因此,让我们同时清理 mysitemydog

kubectl delete -f mysite.yaml
kubectl delete -f mydog.yaml

由于我们是手动创建配置映射的,因此我们也需要手动删除它们。

kubectl delete configmap mysite-html
kubectl delete configmap mydog-html

现在,如果我们执行 kubectl get pods,我们应该看到我们的 nginx Pod 不存在了。

$ kubectl get pods
No resources found in default namespace.

一切都清理了。

请在下面的评论中告诉我你对这个项目有什么想法。


via: https://opensource.com/article/20/3/kubernetes-traefik

作者:Lee Carpenter 选题:lujun9972 译者:wxy 校对:wxy

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

我们来研究下 Linux 上的 ufw(简单防火墙),为你更改防火墙提供一些见解和命令。

ufw 简单防火墙 Uncomplicated FireWall )真正地简化了 iptables,它从出现的这几年,已经成为 Ubuntu 和 Debian 等系统上的默认防火墙。而且 ufw 出乎意料的简单,这对新管理员来说是一个福音,否则他们可能需要投入大量时间来学习防火墙管理。

ufw 也有 GUI 客户端(例如 gufw),但是 ufw 命令通常在命令行上执行的。本文介绍了一些使用 ufw 的命令,并研究了它的工作方式。

首先,快速查看 ufw 配置的方法是查看其配置文件 —— /etc/default/ufw。使用下面的命令可以查看其配置,使用 grep 来抑制了空行和注释(以 # 开头的行)的显示。

$ grep -v '^#\|^$' /etc/default/ufw
IPV6=yes
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"
DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_APPLICATION_POLICY="SKIP"
MANAGE_BUILTINS=no
IPT_SYSCTL=/etc/ufw/sysctl.conf
IPT_MODULES="nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns"

正如你所看到的,默认策略是丢弃输入但允许输出。允许你接受特定的连接的其它规则是需要单独配置的。

ufw 命令的基本语法如下所示,但是这个概要并不意味着你只需要输入 ufw 就行,而是一个告诉你需要哪些参数的快速提示。

ufw [--dry-run] [options] [rule syntax]

--dry-run 选项意味着 ufw 不会运行你指定的命令,但会显示给你如果执行后的结果。但是它会显示假如更改后的整个规则集,因此你要做有好多行输出的准备。

要检查 ufw 的状态,请运行以下命令。注意,即使是这个命令也需要使用 sudo 或 root 账户。

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       192.168.0.0/24
9090                       ALLOW       Anywhere
9090 (v6)                  ALLOW       Anywhere (v6)

否则,你会看到以下内容:

$ ufw status
ERROR: You need to be root to run this script

加上 verbose 选项会提供一些其它细节:

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22                         ALLOW IN    192.168.0.0/24
9090                       ALLOW IN    Anywhere
9090 (v6)                  ALLOW IN    Anywhere (v6)

你可以使用以下命令轻松地通过端口号允许和拒绝连接:

$ sudo ufw allow 80         <== 允许 http 访问
$ sudo ufw deny 25              <== 拒绝 smtp 访问

你可以查看 /etc/services 文件来找到端口号和服务名称之间的联系。

$ grep 80/ /etc/services
http            80/tcp          www             # WorldWideWeb HTTP
socks           1080/tcp                        # socks proxy server
socks           1080/udp
http-alt        8080/tcp        webcache        # WWW caching service
http-alt        8080/udp
amanda          10080/tcp                       # amanda backup services
amanda          10080/udp
canna           5680/tcp                        # cannaserver

或者,你可以命令中直接使用服务的名称。

$ sudo ufw allow http
Rule added
Rule added (v6)
$ sudo ufw allow https
Rule added
Rule added (v6)

进行更改后,你应该再次检查状态来查看是否生效:

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       192.168.0.0/24
9090                       ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere         <==
443/tcp                    ALLOW       Anywhere         <==
9090 (v6)                  ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)    <==
443/tcp (v6)               ALLOW       Anywhere (v6)    <==

ufw 遵循的规则存储在 /etc/ufw 目录中。注意,你需要 root 用户访问权限才能查看这些文件,每个文件都包含大量规则。

$ ls -ltr /etc/ufw
total 48
-rw-r--r-- 1 root root 1391 Aug 15  2017 sysctl.conf
-rw-r----- 1 root root 1004 Aug 17  2017 after.rules
-rw-r----- 1 root root  915 Aug 17  2017 after6.rules
-rw-r----- 1 root root 1130 Jan  5  2018 before.init
-rw-r----- 1 root root 1126 Jan  5  2018 after.init
-rw-r----- 1 root root 2537 Mar 25  2019 before.rules
-rw-r----- 1 root root 6700 Mar 25  2019 before6.rules
drwxr-xr-x 3 root root 4096 Nov 12 08:21 applications.d
-rw-r--r-- 1 root root  313 Mar 18 17:30 ufw.conf
-rw-r----- 1 root root 1711 Mar 19 10:42 user.rules
-rw-r----- 1 root root 1530 Mar 19 10:42 user6.rules

本文前面所作的更改,为 http 访问添加了端口 80 和为 https 访问添加了端口 443,在 user.rulesuser6.rules 文件中看起来像这样:

# grep " 80 " user*.rules
user6.rules:### tuple ### allow tcp 80 ::/0 any ::/0 in
user6.rules:-A ufw6-user-input -p tcp --dport 80 -j ACCEPT
user.rules:### tuple ### allow tcp 80 0.0.0.0/0 any 0.0.0.0/0 in
user.rules:-A ufw-user-input -p tcp --dport 80 -j ACCEPT
You have new mail in /var/mail/root
# grep 443 user*.rules
user6.rules:### tuple ### allow tcp 443 ::/0 any ::/0 in
user6.rules:-A ufw6-user-input -p tcp --dport 443 -j ACCEPT
user.rules:### tuple ### allow tcp 443 0.0.0.0/0 any 0.0.0.0/0 in
user.rules:-A ufw-user-input -p tcp --dport 443 -j ACCEPT

使用 ufw,你还可以使用以下命令轻松地阻止来自一个 IP 地址的连接:

$ sudo ufw deny from 208.176.0.50
Rule added

status 命令将显示更改:

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22                         ALLOW IN    192.168.0.0/24
9090                       ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
Anywhere                   DENY IN     208.176.0.50             <== new
9090 (v6)                  ALLOW IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

总而言之,ufw 不仅容易配置,而且且容易理解。


via: https://www.networkworld.com/article/3533551/linux-firewall-basics-with-ufw.html

作者:Sandra Henry-Stocker 选题:lujun9972 译者:MjSeven 校对:wxy

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