分类 容器与云 下的文章

随着容器和容器技术的兴起,现在所有主流的 Linux 发行版都提供了容器基础镜像。本文介绍了 Fedora 项目如何构建其基本镜像,同时还展示了如何使用它来创建分层图像。

基础和分层镜像

在看如何构建 Fedora 容器 基础镜像 base image 之前,让我们定义基础镜像和 分层镜像 layered image 。定义基础镜像的简单方法是没有父镜像层的镜像。但这具体意味着什么呢?这意味着基础镜像通常只包含操作系统的根文件系统基础镜像(rootfs)。基础镜像通常提供安装软件以创建分层镜像所需的工具。

分层镜像在基础镜像上添加了一组层,以便安装、配置和运行应用。分层镜像在 Dockerfile 中使用 FROM 指令引用基础镜像:

FROM fedora:latest

如何构建基础镜像

Fedora 有一整套用于构建容器镜像的工具。其中包括 podman,它不需要以 root 身份运行。

构建 rootfs

基础镜像主要由一个 tarball) 构成。这个 tarball 包含一个 rootfs。有不同的方法来构建此 rootfs。Fedora 项目使用 kickstart) 安装方式以及 imagefactory 来创建这些 tarball。

在创建 Fedora 基础镜像期间使用的 kickstart 文件可以在 Fedora 的构建系统 Koji 中找到。Fedora-Container-Base 包重新组合了所有基础镜像的构建版本。如果选择了一个构建版本,那么可以访问所有相关文件,包括 kickstart 文件。查看 示例,文件末尾的 %packages 部分定义了要安装的所有软件包。这就是让软件放在基础镜像中的方法。

使用 rootfs 构建基础镜像

rootfs 完成后,构建基础镜像就很容易了。它只需要一个包含以下指令的 Dockerfile:

FROM scratch
ADD layer.tar /
CMD ["/bin/bash"]

这里的重要部分是 FROM scratch 指令,它会创建一个空镜像。然后,接下来的指令将 rootfs 添加到镜像,并设置在运行镜像时要执行的默认命令。

让我们使用 Koji 内置的 Fedora rootfs 构建一个基础镜像:

$ curl -o fedora-rootfs.tar.xz https://kojipkgs.fedoraproject.org/packages/Fedora-Container-Base/Rawhide/20190902.n.0/images/Fedora-Container-Base-Rawhide-20190902.n.0.x86_64.tar.xz
$ tar -xJvf fedora-rootfs.tar.xz 51c14619f9dfd8bf109ab021b3113ac598aec88870219ff457ba07bc29f5e6a2/layer.tar 
$ mv 51c14619f9dfd8bf109ab021b3113ac598aec88870219ff457ba07bc29f5e6a2/layer.tar layer.tar
$ printf "FROM scratch\nADD layer.tar /\nCMD [\"/bin/bash\"]" > Dockerfile
$ podman build -t my-fedora .
$ podman run -it --rm my-fedora cat /etc/os-release

需要从下载的存档中提取包含 rootfs 的 layer.tar 文件。这在 Fedora 生成的镜像已经可以被容器运行时使用才需要。

因此,使用 Fedora 生成的镜像,获得基础镜像会更容易。让我们看看它是如何工作的:

$ curl -O https://kojipkgs.fedoraproject.org/packages/Fedora-Container-Base/Rawhide/20190902.n.0/images/Fedora-Container-Base-Rawhide-20190902.n.0.x86_64.tar.xz
$ podman load --input Fedora-Container-Base-Rawhide-20190902.n.0.x86_64.tar.xz
$ podman run -it --rm localhost/fedora-container-base-rawhide-20190902.n.0.x86_64:latest cat /etc/os-release

构建分层镜像

要构建使用 Fedora 基础镜像的分层镜像,只需在 FROM 行指令中指定 fedora

FROM fedora:latest

latest 标记引用了最新的 Fedora 版本(编写本文时是 Fedora 30)。但是可以使用镜像的标签来使用其他版本。例如,FROM fedora:31 将使用 Fedora 31 基础镜像。

Fedora 支持将软件作为容器来构建并发布。这意味着你可以维护 Dockerfile 来使其他人可以使用你的软件。关于在 Fedora 中成为容器镜像维护者的更多信息,请查看 Fedora 容器指南


via: https://fedoramagazine.org/how-to-build-fedora-container-images/

作者:Clément Verna 选题:lujun9972 译者:geekpi 校对:wxy

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

了解如何使用 Podman 在单独的用户空间运行容器。

Podmanlibpod 库的一部分,使用户能够管理 pod、容器和容器镜像。在我的上一篇文章中,我写过将 Podman 作为一种更安全的运行容器的方式。在这里,我将解释如何使用 Podman 在单独的用户命名空间中运行容器。

作为分离容器的一个很棒的功能,我一直在思考 用户命名空间 user namespace ,它主要是由 Red Hat 的 Eric Biederman 开发的。用户命名空间允许你指定用于运行容器的用户标识符(UID)和组标识符(GID)映射。这意味着你可以在容器内以 UID 0 运行,在容器外以 UID 100000 运行。如果容器进程逃逸出了容器,内核会将它们视为以 UID 100000 运行。不仅如此,任何未映射到用户命名空间的 UID 所拥有的文件对象都将被视为 nobody 所拥有(UID 是 65534, 由 kernel.overflowuid 指定),并且不允许容器进程访问,除非该对象可由“其他人”访问(即世界可读/可写)。

如果你拥有一个权限为 660 的属主为“真实” root 的文件,而当用户命名空间中的容器进程尝试读取它时,会阻止它们访问它,并且会将该文件视为 nobody 所拥有。

示例

以下是它是如何工作的。首先,我在 root 拥有的系统中创建一个文件。

$ sudo bash -c "echo Test > /tmp/test"
$ sudo chmod 600 /tmp/test
$ sudo ls -l /tmp/test
-rw-------. 1 root root 5 Dec 17 16:40 /tmp/test

接下来,我将该文件卷挂载到一个使用用户命名空间映射 0:100000:5000 运行的容器中。

$ sudo podman run -ti -v /tmp/test:/tmp/test:Z --uidmap 0:100000:5000 fedora sh
# id
uid=0(root) gid=0(root) groups=0(root)
# ls -l /tmp/test
-rw-rw----. 1 nobody nobody 8 Nov 30 12:40 /tmp/test
# cat /tmp/test
cat: /tmp/test: Permission denied

上面的 --uidmap 设置告诉 Podman 在容器内映射一系列的 5000 个 UID,从容器外的 UID 100000 开始的范围(100000-104999)映射到容器内 UID 0 开始的范围(0-4999)。在容器内部,如果我的进程以 UID 1 运行,则它在主机上为 100001。

由于实际的 UID=0 未映射到容器中,因此 root 拥有的任何文件都将被视为 nobody 所拥有。即使容器内的进程具有 CAP_DAC_OVERRIDE 能力,也无法覆盖此种保护。DAC_OVERRIDE 能力使得 root 的进程能够读/写系统上的任何文件,即使进程不是 root 用户拥有的,也不是全局可读或可写的。

用户命名空间的功能与宿主机上的功能不同。它们是命名空间的功能。这意味着我的容器的 root 只在容器内具有功能 —— 实际上只有该范围内的 UID 映射到内用户命名空间。如果容器进程逃逸出了容器,则它将没有任何非映射到用户命名空间的 UID 之外的功能,这包括 UID=0。即使进程可能以某种方式进入另一个容器,如果容器使用不同范围的 UID,它们也不具备这些功能。

请注意,SELinux 和其他技术还限制了容器进程破开容器时会发生的情况。

使用 podman top 来显示用户名字空间

我们在 podman top 中添加了一些功能,允许你检查容器内运行的进程的用户名,并标识它们在宿主机上的真实 UID。

让我们首先使用我们的 UID 映射运行一个 sleep 容器。

$ sudo podman run --uidmap 0:100000:5000 -d fedora sleep 1000

现在运行 podman top

$ sudo podman top --latest user huser
USER   HUSER
root   100000

$ ps -ef | grep sleep
100000   21821 21809  0 08:04 ?         00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000

注意 podman top 报告用户进程在容器内以 root 身份运行,但在宿主机(HUSER)上以 UID 100000 运行。此外,ps 命令确认 sleep 过程以 UID 100000 运行。

现在让我们运行第二个容器,但这次我们将选择一个单独的 UID 映射,从 200000 开始。

$ sudo podman run --uidmap 0:200000:5000 -d fedora sleep 1000
$ sudo podman top --latest user huser
USER   HUSER
root   200000

$ ps -ef | grep sleep
100000   21821 21809  0 08:04 ?         00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
200000   23644 23632  1 08:08 ?         00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000

请注意,podman top 报告第二个容器在容器内以 root 身份运行,但在宿主机上是 UID=200000。

另请参阅 ps 命令,它显示两个 sleep 进程都在运行:一个为 100000,另一个为 200000。

这意味着在单独的用户命名空间内运行容器可以在进程之间进行传统的 UID 分离,而这从一开始就是 Linux/Unix 的标准安全工具。

用户名字空间的问题

几年来,我一直主张用户命名空间应该作为每个人应该有的安全工具,但几乎没有人使用过。原因是没有任何文件系统支持,也没有一个 移动文件系统 shifting file system

在容器中,你希望在许多容器之间共享基本镜像。上面的每个示例中使用了 Fedora 基本镜像。Fedora 镜像中的大多数文件都由真实的 UID=0 拥有。如果我在此镜像上使用用户名称空间 0:100000:5000 运行容器,默认情况下它会将所有这些文件视为 nobody 所拥有,因此我们需要移动所有这些 UID 以匹配用户名称空间。多年来,我想要一个挂载选项来告诉内核重新映射这些文件 UID 以匹配用户命名空间。上游内核存储开发人员还在继续研究,在此功能上已经取得一些进展,但这是一个难题。

由于由 Nalin Dahyabhai 领导的团队开发的自动 chown 内置于容器/存储中,Podman 可以在同一镜像上使用不同的用户名称空间。当 Podman 使用容器/存储,并且 Podman 在新的用户命名空间中首次使用一个容器镜像时,容器/存储会 “chown”(如,更改所有权)镜像中的所有文件到用户命名空间中映射的 UID 并创建一个新镜像。可以把它想象成一个 fedora:0:100000:5000 镜像。

当 Podman 在具有相同 UID 映射的镜像上运行另一个容器时,它使用“预先 chown”的镜像。当我在0:200000:5000 上运行第二个容器时,容器/存储会创建第二个镜像,我们称之为 fedora:0:200000:5000

请注意,如果你正在执行 podman buildpodman commit 并将新创建的镜像推送到容器注册库,Podman 将使用容器/存储来反转该移动,并将推送所有文件属主变回真实 UID=0 的镜像。

这可能会导致在新的 UID 映射中创建容器时出现真正的减速,因为 chown 可能会很慢,具体取决于镜像中的文件数。此外,在普通的 OverlayFS 上,镜像中的每个文件都会被复制。普通的 Fedora 镜像最多可能需要 30 秒才能完成 chown 并启动容器。

幸运的是,Red Hat 内核存储团队(主要是 Vivek Goyal 和 Miklos Szeredi)在内核 4.19 中为 OverlayFS 添加了一项新功能。该功能称为“仅复制元数据”。如果使用 metacopy=on 选项来挂载层叠文件系统,则在更改文件属性时,它不会复制较低层的内容;内核会创建新的 inode,其中包含引用指向较低级别数据的属性。如果内容发生变化,它仍会复制内容。如果你想试用它,可以在 Red Hat Enterprise Linux 8 Beta 中使用此功能。

这意味着容器 chown 可能在两秒钟内发生,并且你不会倍增每个容器的存储空间。

这使得像 Podman 这样的工具在不同的用户命名空间中运行容器是可行的,大大提高了系统的安全性。

前瞻

我想向 Podman 添加一个新选项,比如 --userns=auto,它会为你运行的每个容器自动选择一个唯一的用户命名空间。这类似于 SELinux 与单独的多类别安全(MCS)标签一起使用的方式。如果设置环境变量 PODMAN_USERNS=auto,则甚至不需要设置该选项。

Podman 最终允许用户在不同的用户名称空间中运行容器。像 BuildahCRI-O 这样的工具也可以利用用户命名空间。但是,对于 CRI-O,Kubernetes 需要了解哪个用户命名空间将运行容器引擎,上游正在开发这个功能。

在我的下一篇文章中,我将解释如何在用户命名空间中将 Podman 作为非 root 用户运行。


via: https://opensource.com/article/18/12/podman-and-user-namespaces

作者:Daniel J Walsh 选题:lujun9972 译者:wxy 校对:wxy

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

Podman 使用传统的 fork/exec 模型(相对于客户端/服务器模型)来运行容器。

在进入本文的主要主题 Podman 和容器之前,我需要了解一点 Linux 审计功能的技术。

什么是审计?

Linux 内核有一个有趣的安全功能,叫做审计。它允许管理员在系统上监视安全事件,并将它们记录到audit.log 中,该文件可以本地存储或远程存储在另一台机器上,以防止黑客试图掩盖他的踪迹。

/etc/shadow 文件是一个经常要监控的安全文件,因为向其添加记录可能允许攻击者获得对系统的访问权限。管理员想知道是否有任何进程修改了该文件,你可以通过执行以下命令来执行此操作:

# auditctl -w /etc/shadow

现在让我们看看当我修改了 /etc/shadow 文件会发生什么:

# touch /etc/shadow 
# ausearch -f /etc/shadow -i -ts recent

type=PROCTITLE msg=audit(10/10/2018 09:46:03.042:4108) : proctitle=touch /etc/shadow type=SYSCALL msg=audit(10/10/2018 09:46:03.042:4108) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffff9c a1=0x7ffdb17f6704 a2=O_WRONLY|O_CREAT|O_NOCTTY| O_NONBLOCK a3=0x1b6 items=2 ppid=2712 pid=3727 auid=dwalsh uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts1 ses=3 comm=touch exe=/usr/bin/touch subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)`

审计记录中有很多信息,但我重点注意到它记录了 root 修改了 /etc/shadow 文件,并且该进程的审计 UID(auid)的所有者是 dwalsh

内核修改了这个文件了么?

跟踪登录 UID

登录 UID(loginuid),存储在 /proc/self/loginuid 中,它是系统上每个进程的 proc 结构的一部分。该字段只能设置一次;设置后,内核将不允许任何进程重置它。

当我登录系统时,登录程序会为我的登录过程设置 loginuid 字段。

我(dwalsh)的 UID 是 3267。

$ cat /proc/self/loginuid
3267

现在,即使我变成了 root,我的登录 UID 仍将保持不变。

$ sudo cat /proc/self/loginuid
3267

请注意,从初始登录过程 fork 并 exec 的每个进程都会自动继承 loginuid。这就是内核知道登录的人是 dwalsh 的方式。

容器

现在让我们来看看容器。

sudo podman run fedora cat /proc/self/loginuid
3267

甚至容器进程也保留了我的 loginuid。 现在让我们用 Docker 试试。

sudo docker run fedora cat /proc/self/loginuid 
4294967295

为什么不一样?

Podman 对于容器使用传统的 fork/exec 模型,因此容器进程是 Podman 进程的后代。Docker 使用客户端/服务器模型。我执行的 docker 命令是 Docker 客户端工具,它通过客户端/服务器操作与 Docker 守护进程通信。然后 Docker 守护程序创建容器并处理 stdin/stdout 与 Docker 客户端工具的通信。

进程的默认 loginuid(在设置 loginuid 之前)是 4294967295(LCTT 译注:2 32 - 1)。由于容器是 Docker 守护程序的后代,而 Docker 守护程序是 init 系统的子代,所以,我们看到 systemd、Docker 守护程序和容器进程全部具有相同的 loginuid4294967295,审计系统视其为未设置审计 UID。

cat /proc/1/loginuid 
4294967295

怎么会被滥用?

让我们来看看如果 Docker 启动的容器进程修改 /etc/shadow 文件会发生什么。

$ sudo docker run --privileged -v /:/host fedora touch /host/etc/shadow 
$ sudo ausearch -f /etc/shadow -i type=PROCTITLE msg=audit(10/10/2018 10:27:20.055:4569) : proctitle=/usr/bin/coreutils --coreutils-prog-shebang=touch /usr/bin/touch /host/etc/shadow type=SYSCALL msg=audit(10/10/2018 10:27:20.055:4569) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffff9c a1=0x7ffdb6973f50 a2=O_WRONLY|O_CREAT|O_NOCTTY| O_NONBLOCK a3=0x1b6 items=2 ppid=11863 pid=11882 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=touch exe=/usr/bin/coreutils subj=system_u:system_r:spc_t:s0 key=(null)

在 Docker 情形中,auid 是未设置的(4294967295);这意味着安全人员可能知道有进程修改了 /etc/shadow 文件但身份丢失了。

如果该攻击者随后删除了 Docker 容器,那么在系统上谁修改 /etc/shadow 文件将没有任何跟踪信息。

现在让我们看看相同的场景在 Podman 下的情况。

$ sudo podman run --privileged -v /:/host fedora touch /host/etc/shadow 
$ sudo ausearch -f /etc/shadow -i type=PROCTITLE msg=audit(10/10/2018 10:23:41.659:4530) : proctitle=/usr/bin/coreutils --coreutils-prog-shebang=touch /usr/bin/touch /host/etc/shadow type=SYSCALL msg=audit(10/10/2018 10:23:41.659:4530) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffff9c a1=0x7fffdffd0f34 a2=O_WRONLY|O_CREAT|O_NOCTTY| O_NONBLOCK a3=0x1b6 items=2 ppid=11671 pid=11683 auid=dwalsh uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=3 comm=touch exe=/usr/bin/coreutils subj=unconfined_u:system_r:spc_t:s0 key=(null)

由于它使用传统的 fork/exec 方式,因此 Podman 正确记录了所有内容。

这只是观察 /etc/shadow 文件的一个简单示例,但审计系统对于观察系统上的进程非常有用。使用 fork/exec 容器运行时(而不是客户端/服务器容器运行时)来启动容器允许你通过审计日志记录保持更好的安全性。

最后的想法

在启动容器时,与客户端/服务器模型相比,fork/exec 模型还有许多其他不错的功能。例如,systemd 功能包括:

  • SD_NOTIFY:如果将 Podman 命令放入 systemd 单元文件中,容器进程可以通过 Podman 返回通知,表明服务已准备好接收任务。这是在客户端/服务器模式下无法完成的事情。
  • 套接字激活:你可以将连接的套接字从 systemd 传递到 Podman,并传递到容器进程以便使用它们。这在客户端/服务器模型中是不可能的。

在我看来,其最好的功能是作为非 root 用户运行 Podman 和容器。这意味着你永远不会在宿主机上授予用户 root 权限,而在客户端/服务器模型中(如 Docker 使用的),你必须打开以 root 身份运行的特权守护程序的套接字来启动容器。在那里,你将受到守护程序中实现的安全机制与宿主机操作系统中实现的安全机制的支配 —— 这是一个危险的主张。


via: https://opensource.com/article/18/10/podman-more-secure-way-run-containers

作者:Daniel J Walsh 选题:lujun9972 译者:wxy 校对:wxy

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

学习如何驾驭 Kubernetes 比如何建造它更重要,这些工具可以帮助你更快上路。

 title=

在本系列的第三篇文章中,Kubernetes 基础:首先学习如何使用,我强调你应该学会使用 Kubernetes,而不是建造它。我还解释说,在 Kubernetes 中,你必须学习最小的一组原语来建模应用程序。我想强调这一点:你需要学习的这组原语是最简单的原语集,你可以通过它们学习如何实现生产级的应用程序部署(即高可用性 [HA]、多容器、多应用程序)。换句话说,学习 Kubernetes 内置的原语集比学习集群软件、集群文件系统、负载平衡器、让人发疯的 Apache 和 Nginx 的配置、路由器、交换机、防火墙和存储后端更容易 —— 这些是你在传统的 IT 环境(虚拟机或裸机)中建模简单的 HA 应用程序所需要的东西。

在这第四篇文章中,我将分享一些有助于你学习快速驾驭 Kubernetes 的工具。

1、Katacoda

无疑,Katacoda 是试驾 Kubernetes 集群的最简单方法。只需单击一下,五秒钟后就可以将基于 Web 的终端直接连接到正在运行的 Kubernetes 集群中。这对于使用和学习来说非常棒。我甚至将它用于演示和测试新想法。Katacoda 提供了一个完整的临时环境,在你使用完毕后可以回收利用。

 title=

OpenShift Playground

 title=

Kubernetes Playground

Katacoda 提供了一个临时的环境和更深入的实验室环境。例如,我最近三四年主讲的 Linux Container Internals Lab 是在 Katacoda 中构建的。

Katacoda 在其主站点上维护了若干 Kubernetes 和云教程并与 Red Hat 合作以支持了一个 OpenShift 的专用学习门户。了解一下,它们是极好的学习资源。

当你第一次学习驾驶翻斗车时,最好先观察一下其他人的驾驶方式。

2、Podman generate kube

podman generate kube 命令是一个很棒的子命令,可以帮助用户自然地从运行简单容器的简单容器引擎转换到运行许多容器的集群用例(正如我在上篇文章中所描述的那样)。Podman 通过让你启动一个新的容器,然后导出这个可工作的 Kube YAML,并在 Kubernetes 中启动它来实现这一点。看看这个(你可以在 Katacoda lab 中运行它,它已经有了 Podman 和 OpenShift)。

首先,请注意运行容器的语法与 Docker 非常相似:

podman run -dtn two-pizza quay.io/fatherlinux/two-pizza

不过这个是其它容器引擎所没有的:

podman generate kube two-pizza

输出:

# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-1.3.1
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2019-06-07T08:08:12Z"
  labels:
    app: two-pizza
  name: two-pizza
spec:
  containers:
  - command:
    - /bin/sh
    - -c
    - bash -c 'while true; do /usr/bin/nc -l -p 3306 < /srv/hello.txt; done'
    env:
    - name: PATH
      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    - name: TERM
      value: xterm
    - name: HOSTNAME
    - name: container
      value: oci
    image: quay.io/fatherlinux/two-pizza:latest
    name: two-pizza
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities: {}
      privileged: false
      readOnlyRootFilesystem: false
    tty: true
    workingDir: /
status: {}
---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2019-06-07T08:08:12Z"
  labels:
    app: two-pizza
  name: two-pizza
spec:
  selector:
    app: two-pizza
  type: NodePort
status:
  loadBalancer: {}

你现在有了一些可以的工作 Kubernetes YAML,你可以用它作为练习的起点来学习、调整等等。-s 标志可以为你创造一项服务。Brent Baude 甚至致力于添加卷/持久卷断言等新功能。如果想进一步深入,请在 Brent 的博客文章《Podman 现在可以轻松过渡到 Kubernetes 和 CRI-O》中了解他的工作。

3、oc new-app

oc new-app 命令非常强大。它是特定于 OpenShift 的,所以它在默认的 Kubernetes 中不可用,但是当你开始学习 Kubernetes 时它非常有用。让我们从快速命令开始创建一个相当复杂的应用程序:

oc new-project -n example
oc new-app -f https://raw.githubusercontent.com/openshift/origin/master/examples/quickstarts/cakephp-mysql.json

使用 oc new-app,你可以从 OpenShift 开发人员那里偷取模板,并在开发原语来描述你自己的应用程序时拥有一个已知良好的起点。运行上述命令后,你的 Kubernetes 命名空间(在 OpenShift 中)将由若干新的已定义资源填充。

oc get all

输出:

NAME                                READY     STATUS      RESTARTS   AGE
pod/cakephp-mysql-example-1-build   0/1       Completed   0          4m
pod/cakephp-mysql-example-1-gz65l   1/1       Running     0          1m
pod/mysql-1-nkhqn                   1/1       Running     0          4m

NAME                                            DESIRED   CURRENT   READY     AGE
replicationcontroller/cakephp-mysql-example-1   1         1         1         1m
replicationcontroller/mysql-1                   1         1         1         4m

NAME                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/cakephp-mysql-example   ClusterIP   172.30.234.135   <none>        8080/TCP   4m
service/mysql                   ClusterIP   172.30.13.195    <none>        3306/TCP   4m

NAME                                                       REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfig.apps.openshift.io/cakephp-mysql-example   1          1         1         config,image(cakephp-mysql-example:latest)
deploymentconfig.apps.openshift.io/mysql                   1          1         1         config,image(mysql:5.7)

NAME                                                   TYPE      FROM      LATEST
buildconfig.build.openshift.io/cakephp-mysql-example   Source    Git       1

NAME                                               TYPE      FROM          STATUS     STARTED         DURATION
build.build.openshift.io/cakephp-mysql-example-1   Source    Git@47a951e   Complete   4 minutes ago   2m27s

NAME                                                   DOCKER REPO                                                      TAGS      UPDATED
imagestream.image.openshift.io/cakephp-mysql-example   docker-registry.default.svc:5000/example/cakephp-mysql-example   latest    About aminute ago

NAME                                             HOST/PORT                                                                         PATH   SERVICES                PORT      TERMINATION   WILDCARD
route.route.openshift.io/cakephp-mysql-example   cakephp-mysql-example-example.2886795271-80-rhsummit1.environments.katacoda.com   cakephp-mysql-example   <all>                   None

这样做的好处是你可以删除 Pod,观察复制控制器如何重新创建它们,缩放 Pod 等等。你可以使用模板并将其更改为其他应用程序(这是我第一次启动时所做的)。

4、Visual Studio Code

我把我最喜欢的放在最后。我的大部分工作都使用 vi,但我从来没有为 Kubernetes 找到一个好的语法高亮器和代码补完插件(如果有的话,请告诉我)。相反,我发现微软的 VS Code 有一套杀手级的插件,可以完成 Kubernetes 资源的创建并提供样板。

 title=

首先,安装上图中显示的 Kubernetes 和 YAML 插件。

 title=

然后,你可以从头开始创建新的 YAML 文件,并自动补完 Kubernetes 资源。上面的示例显示了一个服务。

 title=

当你使用自动补完并选择服务资源时,它会填充该对象的一些模板。当你第一次学习使用 Kubernetes 时,这非常棒。你可以构建 Pod、服务、复制控制器、部署等。当你从头开始构建这些文件甚至修改你使用 podman generate kube 创建的文件时,这是一个非常好的功能。

总结

这四个工具(如果算上两个插件,则为六个)将帮助你学习驾驭 Kubernetes,而不是构造或装备它。在本系列的最后一篇文章中,我将讨论为什么 Kubernetes 如此适合运行这么多不同的工作负载。


via: https://opensource.com/article/19/6/tools-drive-kubernetes

作者:Scott McCarty 选题:lujun9972 译者:wxy 校对:wxy

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

Mac 用户可使用 MicroK8s 运行 Kubernetes 环境,进而开发、测试应用。通过下面的步骤可轻松搭建此环境。

MicroK8s 是一个 Ubuntu 推出的一个本地的 Kubernetes 版本。它是一个轻量级的 snap 应用,可安装到 PC 上作为一个单节点集群使用。尽管 MicroK8s 仅针对 Linux 构建,但是也可以在 Mac 上启动 Ubuntu VM 来实现。

MicroK8s 可在 Ubuntu 和任意支持 snap 的 OS 上运行全部原生的 K8s 服务。这对于开发应用,创建简单的 K8s 集群和本地微服务开发非常有帮助,所有的开发工作最终都还是需要部署的。

MicroK8s 提供另一个级别的可靠性因为它提供了与当前 Kubernetes(以下简称 Kubernetes 为 K8s)版本一致的开发环境。 在最新的上游 K8s 发布后的一周内,在 Ubuntu 上即可使用。

在 Mac 上配置 Kubernetes

K8s 和 MicroK8s 都需要一个 Linux 内核来工作,因此二者都需要 Ubuntu 环境。Mac 用户可使用 Multipass,此工具被设计为方便用户在 Mac、Windows、Linux 上开启 Ubuntu VM(虚拟)环境。

下面的教程将介绍在 Mac 上配置 Multipass 和运行 K8s。

步骤1:使用 Multipass 为 Mac 安装一个 VM

最新的 Multipass 的程序包可在 GitHub 上找到,双击 .pkg 即可安装。用 MicroK8s 来启动一个 VM:

multipass launch --name microk8s-vm --mem 4G --disk 40G  
multipass exec microk8s-vm -- sudo snap install microk8s --classic       
multipass exec microk8s-vm -- sudo iptables -P FORWARD ACCEPT       

确保为主机保留足够的资源。上述命令表示我们创建了一个名字为 microk8s-vm 的 VM,分配了 4GB 内存和 40GB 硬盘。

使用以下命令来查看 VM 分配的 IP 地址:(记一下下面的 IP,我们将从此开始)

multipass list  
Name         State     IPv4            Release     
microk8s-vm  RUNNING   192.168.64.1   Ubuntu 18.04 LTS                                                              

步骤2:在 VM 上与 MicroK8s 互动

可使用以下 3 种方式:

命令行,用 Multipass 的 shell 提示符:

multipass shell microk8s-vm                                                                                     

multipass exec 来执行一个命令(输入后无提示):

multipass exec microk8s-vm -- /snap/bin/microk8s.status                             

调用运行在 VM 的 K8s API 服务器,这里使用 MicroK8s 的 kubeconfig 文件和一个本地的安装的 kubectl 来访问 VM 内的 K8s,运行以下命令:

multipass exec microk8s-vm -- /snap/bin/microk8s.config > kubeconfig     

下一步,在本地主机安装 kubectl,然后使用 kubeconfig:

kubectl --kubeconfig=kubeconfig get all --all-namespaces            
NAMESPACE  NAME  TYPE  CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE          
Default service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 3m12s

步骤 3:用 Mutlpass 服务访问 VM 并开启 MicroK8s 组件

配置基础的 MicroK8s 组件是开启 Grafana 仪表,下面我们将展示一步开启 Grafana,监视和分析一个 MicroK8s 实例。可执行以下命令:

multipass exec microk8s-vm -- /snap/bin/microk8s.enable dns dashboard  
Enabling DNS  
Applying manifest  
service/kube-dns created  
serviceaccount/kube-dns created  
configmap/kube-dns created  
deployment.extensions/kube-dns created  
Restarting kubelet  
DNS is enabled  
Enabling dashboard  
secret/kubernetes-dashboard-certs created  
serviceaccount/kubernetes-dashboard created  
deployment.apps/kubernetes-dashboard created  
service/kubernetes-dashboard created  
service/monitoring-grafana created  
service/monitoring-influxdb created  
service/heapster created  
deployment.extensions/monitoring-influxdb-grafana-v4 created  
serviceaccount/heapster created  
configmap/heapster-config created  
configmap/eventer-config created  
deployment.extesions/heapster-v1.5.2 created  
dashboard enabled

接下来,用下面命令检查部署进程:

multipass exec microk8s-vm -- /snap/bin/microk8s.kubectl get all --all-namespaces                                                                                                                        

返回信息如下:

一旦所有的必要服务已开启,接下来使用以下的链接访问仪表。命令如下:

multipass exec microk8s-vm -- /snap/bin/microk8s.kubectl cluster-info    
Kubernetes master is running at https://127.0.0.1:16443  
Heapster is running at https://127.0.0.1:16443/api/v1/namespaces/kube-system/services/heapster/proxy  
KubeDNS is running at https://127.0.0.1:16443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy  
Grafana is running at https://127.0.0.1:16443/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy  
InfluxDB is running at https://127.0.0.1:16443/api/v1/namespaces/kube-system/services/monitoring-influxdb:http/proxy  
  
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

如果我们在 VM 内,可以用此链接来访问 Grafana 仪表。不过,我们可以通过代理在主机上访问。

multipass exec microk8s-vm -- /snap/bin/microk8s.kubectl proxy --address='0.0.0.0' --accept-hosts='.*'   
Starting to serve on [::][::]:8001

保持终端运行状态,记一下端口号(8001),我们在下一步需要用到。要访问 Grafana 仪表,我们需要修改 VM 内仪表的链接:

  • 使用 VM 的 IP 替换 127.0.0.1(multipass info microk8s-vm
  • 将端口(16443)替换为代理端口 8001。
  • 在浏览器内输入这个链接地址:https://127.0.0.1:8001/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy,你将看到 Grafana 仪表,如下图:

总结

使用 MicroK8s 在本地开发和测试应用,将使得团队在部署上更快,这对于开发者和 DevOp 团队来说是非常有价值和意义的。

Getting Started With Docker

在我们的上一个教程中,我们已经了解如何在 Ubuntu 上安装 Docker,和如何在 CentOS 上安装 Docker。今天,我们将会了解 Docker 的一些基础用法。该教程包含了如何创建一个新的 Docker 容器,如何运行该容器,如何从现有的 Docker 容器中创建自己的 Docker 镜像等 Docker 的一些基础知识、操作。所有步骤均在 Ubuntu 18.04 LTS server 版本下测试通过。

入门指南

在开始指南之前,不要混淆 Docker 镜像和 Docker 容器这两个概念。在之前的教程中,我就解释过,Docker 镜像是决定 Docker 容器行为的一个文件,Docker 容器则是 Docker 镜像的运行态或停止态。(LCTT 译注:在 macOS 下使用 Docker 终端时,不需要加 sudo

1、搜索 Docker 镜像

我们可以从 Docker 仓库中获取镜像,例如 Docker hub,或者自己创建镜像。这里解释一下,Docker hub 是一个云服务器,用来提供给 Docker 的用户们创建、测试,和保存他们的镜像。

Docker hub 拥有成千上万个 Docker 镜像文件。你可以通过 docker search命令在这里搜索任何你想要的镜像。

例如,搜索一个基于 Ubuntu 的镜像文件,只需要运行:

$ sudo docker search ubuntu

示例输出:

搜索基于 CentOS 的镜像,运行:

$ sudo docker search centos

搜索 AWS 的镜像,运行:

$ sudo docker search aws

搜索 WordPress 的镜像:

$ sudo docker search wordpress

Docker hub 拥有几乎所有种类的镜像,包含操作系统、程序和其他任意的类型,这些你都能在 Docker hub 上找到已经构建完的镜像。如果你在搜索时,无法找到你想要的镜像文件,你也可以自己构建一个,将其发布出去,或者仅供你自己使用。

2、下载 Docker 镜像

下载 Ubuntu 的镜像,你需要在终端运行以下命令:

$ sudo docker pull ubuntu

这条命令将会从 Docker hub 下载最近一个版本的 Ubuntu 镜像文件。

示例输出:

Using default tag: latest
latest: Pulling from library/ubuntu
6abc03819f3e: Pull complete 
05731e63f211: Pull complete 
0bd67c50d6be: Pull complete 
Digest: sha256:f08638ec7ddc90065187e7eabdfac3c96e5ff0f6b2f1762cf31a4f49b53000a5
Status: Downloaded newer image for ubuntu:latest

下载 Docker 镜像

你也可以下载指定版本的 Ubuntu 镜像。运行以下命令:

$ docker pull ubuntu:18.04

Docker 允许在任意的宿主机操作系统下,下载任意的镜像文件,并运行。

例如,下载 CentOS 镜像:

$ sudo docker pull centos

所有下载的镜像文件,都被保存在 /var/lib/docker 文件夹下。(LCTT 译注:不同操作系统存放的文件夹并不是一致的,具体存放位置请在官方查询)

查看已经下载的镜像列表,可以使用以下命令:

$ sudo docker images

示例输出:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              7698f282e524        14 hours ago        69.9MB
centos              latest              9f38484d220f        2 months ago        202MB
hello-world         latest              fce289e99eb9        4 months ago        1.84kB

正如你看到的那样,我已经下载了三个镜像文件:ubuntucentoshello-world

现在,让我们继续,来看一下如何运行我们刚刚下载的镜像。

3、运行 Docker 镜像

运行一个容器有两种方法。我们可以使用标签或者是镜像 ID。标签指的是特定的镜像快照。镜像 ID 是指镜像的唯一标识。

正如上面结果中显示,latest 是所有镜像的一个标签。7698f282e524 是 Ubuntu Docker 镜像的镜像 ID,9f38484d220f是 CentOS 镜像的镜像 ID,fce289e99eb9 是 hello\_world 镜像的 镜像 ID。

下载完 Docker 镜像之后,你可以通过下面的命令来使用其标签来启动:

$ sudo docker run -t -i ubuntu:latest /bin/bash

在这条语句中:

  • -t:在该容器中启动一个新的终端
  • -i:通过容器中的标准输入流建立交互式连接
  • ubuntu:latest:带有标签 latest 的 Ubuntu 容器
  • /bin/bash:在新的容器中启动 BASH Shell

或者,你可以通过镜像 ID 来启动新的容器:

$ sudo docker run -t -i 7698f282e524 /bin/bash

在这条语句里:

  • 7698f282e524 — 镜像 ID

在启动容器之后,将会自动进入容器的 shell 中(注意看命令行的提示符)。

Docker 容器的 Shell

如果想要退回到宿主机的终端(在这个例子中,对我来说,就是退回到 18.04 LTS),并且不中断该容器的执行,你可以按下 CTRL+P,再按下 CTRL+Q。现在,你就安全的返回到了你的宿主机系统中。需要注意的是,Docker 容器仍然在后台运行,我们并没有中断它。

可以通过下面的命令来查看正在运行的容器:

$ sudo docker ps

示例输出:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
32fc32ad0d54        ubuntu:latest       "/bin/bash"         7 minutes ago       Up 7 minutes                            modest_jones

列出正在运行的容器

可以看到:

  • 32fc32ad0d54 – 容器 ID
  • ubuntu:latest – Docker 镜像

需要注意的是,容器 ID 和 Docker 的镜像 ID是不同的。

可以通过以下命令查看所有正在运行和停止运行的容器:

$ sudo docker ps -a

在宿主机中断容器的执行:

$ sudo docker stop <container-id>

例如:

$ sudo docker stop 32fc32ad0d54

如果想要进入正在运行的容器中,你只需要运行:

$ sudo docker attach 32fc32ad0d54

正如你看到的,32fc32ad0d54 是一个容器的 ID。当你在容器中想要退出时,只需要在容器内的终端中输入命令:

# exit

你可以使用这个命令查看后台正在运行的容器:

$ sudo docker ps

4、构建自己的 Docker 镜像

Docker 不仅仅可以下载运行在线的容器,你也可以创建你的自己的容器。

想要创建自己的 Docker 镜像,你需要先运行一个你已经下载完的容器:

$ sudo docker run -t -i ubuntu:latest /bin/bash

现在,你运行了一个容器,并且进入了该容器。然后,在该容器安装任意一个软件或做任何你想做的事情。

例如,我们在容器中安装一个 Apache web 服务器。

当你完成所有的操作,安装完所有的软件之后,你可以执行以下的命令来构建你自己的 Docker 镜像:

# apt update
# apt install apache2

同样的,在容器中安装和测试你想要安装的所有软件。

当你安装完毕之后,返回的宿主机的终端。记住,不要关闭容器。想要返回到宿主机而不中断容器。请按下CTRL+P,再按下 CTRL+Q

从你的宿主机的终端中,运行以下命令如寻找容器的 ID:

$ sudo docker ps

最后,从一个正在运行的容器中创建 Docker 镜像:

$ sudo docker commit 3d24b3de0bfc ostechnix/ubuntu_apache

示例输出:

sha256:ce5aa74a48f1e01ea312165887d30691a59caa0d99a2a4aa5116ae124f02f962

在这里:

  • 3d24b3de0bfc — 指 Ubuntu 容器的 ID。
  • ostechnix — 我们创建的容器的用户名称
  • ubuntu_apache — 我们创建的镜像

让我们检查一下我们新创建的 Docker 镜像:

$ sudo docker images

示例输出:

REPOSITORY                TAG                 IMAGE ID            CREATED              SIZE
ostechnix/ubuntu_apache   latest              ce5aa74a48f1        About a minute ago   191MB
ubuntu                    latest              7698f282e524        15 hours ago         69.9MB
centos                    latest              9f38484d220f        2 months ago         202MB
hello-world               latest              fce289e99eb9        4 months ago         1.84kB

列出所有的 Docker 镜像

正如你看到的,这个新的镜像就是我们刚刚在本地系统上从运行的容器上创建的。

现在,你可以从这个镜像创建一个新的容器。

$ sudo docker run -t -i ostechnix/ubuntu_apache /bin/bash

5、删除容器

如果你在 Docker 上的工作已经全部完成,你就可以删除那些你不需要的容器。

想要删除一个容器,首先,你需要停止该容器。

我们先来看一下正在运行的容器有哪些

$ sudo docker ps

示例输出:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d24b3de0bfc ubuntu:latest "/bin/bash" 28 minutes ago Up 28 minutes goofy_easley

使用容器 ID 来停止该容器:

$ sudo docker stop 3d24b3de0bfc

现在,就可以删除该容器了。

$ sudo docker rm 3d24b3de0bfc

你就可以按照这样的方法来删除那些你不需要的容器了。

当需要删除的容器数量很多时,一个一个删除也是很麻烦的,我们可以直接删除所有的已经停止的容器。只需要运行:

$ sudo docker container prune

按下 Y,来确认你的操作:

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
32fc32ad0d5445f2dfd0d46121251c7b5a2aea06bb22588fb2594ddbe46e6564
5ec614e0302061469ece212f0dba303c8fe99889389749e6220fe891997f38d0

Total reclaimed space: 5B

这个命令仅支持最新的 Docker。(LCTT 译注:仅支持 1.25 及以上版本的 Docker)

6、删除 Docker 镜像

当你删除了不要的 Docker 容器后,你也可以删除你不需要的 Docker 镜像。

列出已经下载的镜像:

$ sudo docker images

示例输出:

REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
ostechnix/ubuntu_apache   latest              ce5aa74a48f1        5 minutes ago       191MB
ubuntu                    latest              7698f282e524        15 hours ago        69.9MB
centos                    latest              9f38484d220f        2 months ago        202MB
hello-world               latest              fce289e99eb9        4 months ago        1.84kB

由上面的命令可以知道,在本地的系统中存在三个镜像。

使用镜像 ID 来删除镜像。

$ sudo docekr rmi ce5aa74a48f1

示例输出:

Untagged: ostechnix/ubuntu_apache:latest
Deleted: sha256:ce5aa74a48f1e01ea312165887d30691a59caa0d99a2a4aa5116ae124f02f962
Deleted: sha256:d21c926f11a64b811dc75391bbe0191b50b8fe142419f7616b3cee70229f14cd

解决问题

Docker 禁止我们删除一个还在被容器使用的镜像。

例如,当我试图删除 Docker 镜像 b72889fa879c 时,我只能获得一个错误提示:

Error response from daemon: conflict: unable to delete b72889fa879c (must be forced) - image is being used by stopped container dde4dd285377

这是因为这个 Docker 镜像正在被一个容器使用。

所以,我们来检查一个正在运行的容器:

$ sudo docker ps

示例输出:

注意,现在并没有正在运行的容器!!!

查看一下所有的容器(包含所有的正在运行和已经停止的容器):

$ sudo docker pa -a

示例输出:

可以看到,仍然有一些已经停止的容器在使用这些镜像。

让我们把这些容器删除:

$ sudo docker rm 12e892156219

我们仍然使用容器 ID 来删除这些容器。

当我们删除了所有使用该镜像的容器之后,我们就可以删除 Docker 的镜像了。

例如:

$ sudo docekr rmi b72889fa879c

我们再来检查一下本机存在的镜像:

$ sudo docker images

想要知道更多的细节,请参阅本指南末尾给出的官方资源的链接或者在评论区进行留言。

这就是全部的教程了,希望你可以了解 Docker 的一些基础用法。

更多的教程马上就会到来,敬请关注。


via: https://www.ostechnix.com/getting-started-with-docker/

作者:sk 选题:lujun9972 译者:zhang5788 校对:wxy

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