mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-25 23:11:02 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
c2bf67e3e1
@ -3,20 +3,16 @@
|
||||
|
||||
本周工作中,我花了整整一周的时间来尝试调试一个段错误。我以前从来没有这样做过,我花了很长时间才弄清楚其中涉及的一些基本事情(获得核心转储、找到导致段错误的行号)。于是便有了这篇博客来解释如何做那些事情!
|
||||
|
||||
|
||||
在看完这篇博客后,你应该知道如何从“哦,我的程序出现段错误,但我不知道正在发生什么”到“我知道它出现段错误时的堆栈、行号了! “。
|
||||
|
||||
### 什么是段错误?
|
||||
|
||||
一个“段错误”是指你的程序尝试访问不允许访问的内存地址的情况。这可能是由于:
|
||||
“<ruby>段错误<rt>segmentation fault</rt></ruby>”是指你的程序尝试访问不允许访问的内存地址的情况。这可能是由于:
|
||||
|
||||
* 试图解引用空指针(你不被允许访问内存地址 `0`);
|
||||
|
||||
* 试图解引用其他一些不在你内存(译者注:指不在合法的内存地址区间内)中的指针;
|
||||
|
||||
* 一个已被破坏并且指向错误的地方的 C++ 虚表指针,这导致程序尝试执行没有执行权限的内存地址;
|
||||
|
||||
* 其他一些我不明白的事情,比如我认为访问未对齐的内存地址也可能会导致段错误(译者注:在要求自然边界对齐的体系结构,如MIPS、ARM中更容易因非对齐访问产生段错误)。
|
||||
* 试图解引用其他一些不在你内存(LCTT 译注:指不在合法的内存地址区间内)中的指针;
|
||||
* 一个已被破坏并且指向错误的地方的 <ruby>C++ 虚表指针<rt>C++ vtable pointer</rt></ruby>,这导致程序尝试执行没有执行权限的内存中的指令;
|
||||
* 其他一些我不明白的事情,比如我认为访问未对齐的内存地址也可能会导致段错误(LCTT 译注:在要求自然边界对齐的体系结构,如 MIPS、ARM 中更容易因非对齐访问产生段错误)。
|
||||
|
||||
这个“C++ 虚表指针”是我的程序发生段错误的情况。我可能会在未来的博客中解释这个,因为我最初并不知道任何关于 C++ 的知识,并且这种虚表查找导致程序段错误的情况也是我所不了解的。
|
||||
|
||||
@ -24,34 +20,32 @@
|
||||
|
||||
### 步骤1:运行 valgrind
|
||||
|
||||
我发现找出为什么我的程序出现段错误的最简单的方式是使用valgrind:我运行
|
||||
我发现找出为什么我的程序出现段错误的最简单的方式是使用 `valgrind`:我运行
|
||||
|
||||
```
|
||||
valgrind -v your-program
|
||||
|
||||
```
|
||||
|
||||
这给了我一个故障时的堆栈调用序列。 简洁!
|
||||
|
||||
但我想也希望做一个更深入调查,并找出些valgrind没告诉我的信息! 所以我想获得一个核心转储并探索它。
|
||||
但我想也希望做一个更深入调查,并找出些 `valgrind` 没告诉我的信息! 所以我想获得一个核心转储并探索它。
|
||||
|
||||
### 如何获得一个核心转储
|
||||
|
||||
一个核心转储是您的程序内存的一个副本,并且当您试图调试您的有问题的程序哪里出错的时候它非常有用。
|
||||
<ruby>核心转储<rt>core dump</rt></ruby>是您的程序内存的一个副本,并且当您试图调试您的有问题的程序哪里出错的时候它非常有用。
|
||||
|
||||
当您的程序出现段错误,Linux 的内核有时会把一个核心转储写到磁盘。 当我最初试图获得一个核心转储时,我很长一段时间非常沮丧,因为 - Linux 没有生成核心转储!我的核心转储在哪里?
|
||||
|
||||
这就是我最后做了什么:
|
||||
这就是我最终做的事情:
|
||||
|
||||
1. 在启动我的程序之前运行 `ulimit -c unlimited`
|
||||
|
||||
2. 运行 `sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`
|
||||
|
||||
### ulimit:设置核心转储的最大尺寸
|
||||
|
||||
`ulimit -c` 设置核心转储的最大尺寸。 它往往设置为 0,这意味着内核根本不会写核心转储。 它以千字节为单位。 分别为每个进程设置 ulimit - 你可以通过运行 `cat /proc/PID/limit` 看到一个进程的各种资源限制。
|
||||
`ulimit -c` 设置核心转储的最大尺寸。 它往往设置为 0,这意味着内核根本不会写核心转储。 它以千字节为单位。 `ulimit` 是按每个进程分别设置的 —— 你可以通过运行 `cat /proc/PID/limit` 看到一个进程的各种资源限制。
|
||||
|
||||
例如这些是我的系统上一个任意Firefox进程的资源限制:
|
||||
例如这些是我的系统上一个随便一个 Firefox 进程的资源限制:
|
||||
|
||||
```
|
||||
$ cat /proc/6309/limits
|
||||
@ -72,10 +66,9 @@ Max msgqueue size 819200 819200 bytes
|
||||
Max nice priority 0 0
|
||||
Max realtime priority 0 0
|
||||
Max realtime timeout unlimited unlimited us
|
||||
|
||||
```
|
||||
|
||||
内核在决定写入多大的核心转储文件时使用 soft limit(在这种情况下,“最大的核心文件大小= 0”)。 您可以使用 shell 内置命令 `ulimit`(`ulimit -c unlimited`) 将 soft limit 增加到 hard limit。
|
||||
内核在决定写入多大的核心转储文件时使用<ruby>软限制<rt>soft limit</rt></ruby>(在这种情况下,`max core file size = 0`)。 您可以使用 shell 内置命令 `ulimit`(`ulimit -c unlimited`) 将软限制增加到<ruby>硬限制<rt>hard limit</rt></ruby>。
|
||||
|
||||
### kernel.core_pattern:核心转储保存在哪里
|
||||
|
||||
@ -83,57 +76,51 @@ Max realtime timeout unlimited unlimited us
|
||||
|
||||
内核参数是一种设定您的系统全局设置的方法。您可以通过运行 `sysctl -a` 得到一个包含每个内核参数的列表,或使用 `sysctl kernel.core_pattern` 来专门查看 `kernel.core_pattern` 设置。
|
||||
|
||||
所以 `sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t` 将核心转储保存到目录 `/tmp` 下并以 `core` 加上一系列能够标识(出故障的)进程的参数构成的后缀为文件名。
|
||||
所以 `sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t` 将核心转储保存到目录 `/tmp` 下,并以 `core` 加上一系列能够标识(出故障的)进程的参数构成的后缀为文件名。
|
||||
|
||||
如果你想知道这些形如 `%e`、`%p` 的参数都表示什么,请参考 [man core][1]。
|
||||
|
||||
有一点很重要,`kernel.core_pattern` 是一个全局设置 - 修改它的时候最好小心一点,因为有可能其它系统功能依赖于把它被设置为一个特定的方式(才能正常工作)。
|
||||
有一点很重要,`kernel.core_pattern` 是一个全局设置 —— 修改它的时候最好小心一点,因为有可能其它系统功能依赖于把它被设置为一个特定的方式(才能正常工作)。
|
||||
|
||||
### kernel.core_pattern 和 Ubuntu
|
||||
|
||||
默认情况下在ubuntu系统中,`kernel.core_pattern` 被设置为下面的值
|
||||
默认情况下在 ubuntu 系统中,`kernel.core_pattern` 被设置为下面的值:
|
||||
|
||||
```
|
||||
$ sysctl kernel.core_pattern
|
||||
kernel.core_pattern = |/usr/share/apport/apport %p %s %c %d %P
|
||||
|
||||
```
|
||||
|
||||
这引起了我的迷惑(这 apport 是干什么的,它对我的核心转储做了什么?)。以下关于这个我了解到的:
|
||||
|
||||
* Ubuntu 使用一种叫做 apport 的系统来报告 apt 包有关的崩溃信息。
|
||||
|
||||
* 设定 `kernel.core_pattern=|/usr/share/apport/apport %p %s %c %d %P` 意味着核心转储将被通过管道送给 `apport` 程序。
|
||||
|
||||
* apport 的日志保存在文件 /var/log/apport.log 中。
|
||||
|
||||
* apport 的日志保存在文件 `/var/log/apport.log` 中。
|
||||
* apport 默认会忽略来自不属于 Ubuntu 软件包一部分的二进制文件的崩溃信息
|
||||
|
||||
我最终只是覆盖了 apport,并把 `kernel.core_pattern` 重新设置为 `sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`,因为我在一台开发机上,我不在乎 apport 是否工作,我也不想尝试让 apport 把我的核心转储留在磁盘上。
|
||||
我最终只是跳过了 apport,并把 `kernel.core_pattern` 重新设置为 `sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`,因为我在一台开发机上,我不在乎 apport 是否工作,我也不想尝试让 apport 把我的核心转储留在磁盘上。
|
||||
|
||||
### 现在你有了核心转储,接下来干什么?
|
||||
|
||||
好的,现在我们了解了 ulimit 和 `kernel.core_pattern` ,并且实际上在磁盘的 `/tmp` 目录中有了一个核心转储文件。太好了!接下来干什么?我们仍然不知道该程序为什么会出现段错误!
|
||||
好的,现在我们了解了 `ulimit` 和 `kernel.core_pattern` ,并且实际上在磁盘的 `/tmp` 目录中有了一个核心转储文件。太好了!接下来干什么?我们仍然不知道该程序为什么会出现段错误!
|
||||
|
||||
下一步将使用 `gdb` 打开核心转储文件并获取堆栈调用序列。
|
||||
|
||||
### 从 gdb 中得到堆栈调用序列
|
||||
|
||||
你可以像这样用 `gdb` 打开一个核心转储文件
|
||||
你可以像这样用 `gdb` 打开一个核心转储文件:
|
||||
|
||||
```
|
||||
$ gdb -c my_core_file
|
||||
|
||||
```
|
||||
|
||||
接下来,我们想知道程序崩溃时的堆栈是什么样的。在 gdb 提示符下运行 `bt` 会给你一个调用序列。在我的例子里,gdb 没有为二进制文件加载符号信息,所以这些函数名就像“??????”。幸运的是,(我们通过)加载符号修复了它。
|
||||
接下来,我们想知道程序崩溃时的堆栈是什么样的。在 `gdb` 提示符下运行 `bt` 会给你一个<ruby>调用序列<rt>backtrace</rt></ruby>。在我的例子里,`gdb` 没有为二进制文件加载符号信息,所以这些函数名就像 “??????”。幸运的是,(我们通过)加载符号修复了它。
|
||||
|
||||
下面是如何加载调试符号。
|
||||
|
||||
```
|
||||
symbol-file /path/to/my/binary
|
||||
sharedlibrary
|
||||
|
||||
```
|
||||
|
||||
这从二进制文件及其引用的任何共享库中加载符号。一旦我这样做了,当我执行 `bt` 时,gdb 给了我一个带有行号的漂亮的堆栈跟踪!
|
||||
@ -142,46 +129,40 @@ sharedlibrary
|
||||
|
||||
### 查看每个线程的堆栈
|
||||
|
||||
通过以下方式在 gdb 中获取每个线程的调用栈!
|
||||
通过以下方式在 `gdb` 中获取每个线程的调用栈!
|
||||
|
||||
```
|
||||
thread apply all bt full
|
||||
|
||||
```
|
||||
|
||||
### gdb + 核心转储 = 惊喜
|
||||
|
||||
If you have a core dump & debugging symbols and gdb, you are in an amazing situation!! You can go up and down the call stack, print out variables, and poke around in memory to see what happened. It’s the best.
|
||||
|
||||
如果你有一个带调试符号的核心转储以及 gdb,那太棒了!您可以上下查看调用堆栈(译注:指跳进调用序列不同的函数中以便于查看局部变量),打印变量,并查看内存来得知发生了什么。这是最好的。
|
||||
如果你有一个带调试符号的核心转储以及 `gdb`,那太棒了!您可以上下查看调用堆栈(LCTT 译注:指跳进调用序列不同的函数中以便于查看局部变量),打印变量,并查看内存来得知发生了什么。这是最好的。
|
||||
|
||||
如果您仍然正在基于gdb向导来工作上,只打印出栈跟踪与bt也可以:)
|
||||
如果您仍然正在基于 gdb 向导来工作上,只打印出栈跟踪与bt也可以。 :)
|
||||
|
||||
### ASAN
|
||||
|
||||
另一种搞清楚您的段错误的方法是使用 AddressSanitizer 选项编译程序(“ASAN”,即 `$CC -fsanitize=address`)然后运行它。 本文中我不准备讨论那个,因为本文已经相当长了,并且在我的例子中打开 ASAN 后段错误消失了,可能是因为 ASAN 使用了一个不同的内存分配器(系统内存分配器,而不是 tcmalloc)。
|
||||
|
||||
在未来如果我能让ASAN工作,我可能会多写点有关它的东西。(译注:这里指使用ASAN也能复现段错误)
|
||||
在未来如果我能让 ASAN 工作,我可能会多写点有关它的东西。(LCTT 译注:这里指使用 ASAN 也能复现段错误)
|
||||
|
||||
### 从一个核心转储得到一个堆栈跟踪真的很亲切!
|
||||
|
||||
这个博客后听起来很多,但当我做这些的时候很困惑,但说真的,从一个段错误的程序中获得一个堆栈调用序列不需要那么多步骤:
|
||||
这个博客听起来很多,当我做这些的时候很困惑,但说真的,从一个段错误的程序中获得一个堆栈调用序列不需要那么多步骤:
|
||||
|
||||
1. 试试用valgrind
|
||||
1. 试试用 `valgrind`
|
||||
|
||||
如果那没用,或者你想要拿到一个核心转储来调查:
|
||||
|
||||
1. 确保二进制文件编译时带有调试符号信息;
|
||||
|
||||
2. 正确的设置 `ulimit` 和 `kernel.core_pattern`;
|
||||
|
||||
3. 运行程序;
|
||||
|
||||
4. 一旦你用 `gdb` 调试核心转储了,加载符号并运行 `bt`;
|
||||
|
||||
5. 尝试找出发生了什么!
|
||||
|
||||
我可以使用 gdb 弄清楚有个 C++ 的 vtable 条目指向一些被破坏的内存,这有点帮助,并且使我感觉好像理解 C++ 更好一点。也许有一天我们会更多地讨论如何使用 gdb 来查找问题!
|
||||
我可以使用 `gdb` 弄清楚有个 C++ 的虚表条目指向一些被破坏的内存,这有点帮助,并且使我感觉好像更懂了 C++ 一点。也许有一天我们会更多地讨论如何使用 `gdb` 来查找问题!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -189,7 +170,7 @@ via: https://jvns.ca/blog/2018/04/28/debugging-a-segfault-on-linux/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
译者:[stephenxs](https://github.com/stephenxs)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,14 +1,18 @@
|
||||
Buildah 入门
|
||||
======
|
||||
|
||||
> Buildah 提供一种灵活、可脚本编程的方式,来使用你熟悉的工具创建精简、高效的容器镜像。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/blocks_building.png?itok=eMOT-ire)
|
||||
|
||||
[Buildah][1] 是一个命令行工具,可以方便、快捷的构建与[<ruby>开放容器标准<rt>Open Container Initiative, OCI</rt></ruby>][2]兼容的容器镜像,意味着构建的镜像也与 Docker 和 Kubernetes 兼容。该工具可作为 Docker 守护进程 `docker build` 命令(即使用传统的 Dockerfile 构建镜像)的一种<ruby>简单<rt>drop-in</rt></ruby>替换,而且更加灵活,允许构建镜像时使用你擅长的工具。Buildah 可以轻松与脚本集成并生成<ruby>流水线<rt>pipelines</rt></ruby>,最好之处在于构建镜像不再需要运行容器守护进程(LCTT 译注:这里主要是指 Docker 守护进程)。
|
||||
[Buildah][1] 是一个命令行工具,可以方便、快捷的构建与<ruby>[开放容器标准][2]<rt>Open Container Initiative</rt></ruby>(OCI)兼容的容器镜像,这意味着其构建的镜像与 Docker 和 Kubernetes 兼容。该工具可作为 Docker 守护进程 `docker build` 命令(即使用传统的 Dockerfile 构建镜像)的一种<ruby>简单<rt>drop-in</rt></ruby>替换,而且更加灵活,允许构建镜像时使用你擅长的工具。Buildah 可以轻松与脚本集成并生成<ruby>流水线<rt>pipeline</rt></ruby>,最好之处在于构建镜像不再需要运行容器守护进程(LCTT 译注:这里主要是指 Docker 守护进程)。
|
||||
|
||||
### docker build 的简单替换
|
||||
|
||||
目前你可能使用 Dockerfile 和 `docker build` 命令构建镜像,那么你可以马上使用 Buildah 进行替代。Buildah 的 `build-using-dockerfile` 或 `bud` 子命令与 `docker build` 基本等价,因此可以轻松的与已有脚本结合或构建流水线。
|
||||
目前你可能使用 Dockerfile 和 `docker build` 命令构建镜像,那么你可以马上使用 Buildah 进行替代。Buildah 的 `build-using-dockerfile` (或 `bud`)子命令与 `docker build` 基本等价,因此可以轻松的与已有脚本结合或构建流水线。
|
||||
|
||||
类似我的上一篇关于 Buildah 的[文章][3],我也将以使用源码安装 “GNU Hello” 为例进行说明,对应的 Dockerfile 文件如下:
|
||||
|
||||
类似我的上一篇关于 Buildah 的[文章][3],我也将以使用源码安装 "GNU Hello" 为例进行说明,对应的 Dockerfile 文件如下:
|
||||
```
|
||||
FROM fedora:28
|
||||
LABEL maintainer Chris Collins <collins.christopher@gmail.com>
|
||||
@ -27,10 +31,10 @@ RUN make
|
||||
RUN make install
|
||||
RUN hello -v
|
||||
ENTRYPOINT "/usr/local/bin/hello"
|
||||
|
||||
```
|
||||
|
||||
使用 Buildah 从 Dockerfile 构建镜像也很简单,使用 `buildah bud -t hello .` 替换 `docker build -t hello .` 即可:
|
||||
|
||||
```
|
||||
[chris@krang] $ sudo buildah bud -t hello .
|
||||
STEP 1: FROM fedora:28
|
||||
@ -45,19 +49,19 @@ STEP 2: LABEL maintainer Chris Collins <collins.christopher@gmail.com>
|
||||
STEP 3: RUN dnf install -y tar gzip gcc make && dnf clean all
|
||||
|
||||
<考虑篇幅,略去后续输出>
|
||||
|
||||
```
|
||||
|
||||
镜像构建完毕后,可以使用 `buildah images` 命令查看这个新镜像:
|
||||
|
||||
```
|
||||
[chris@krang] $ sudo buildah images
|
||||
IMAGE ID IMAGE NAME CREATED AT SIZE
|
||||
30190780b56e docker.io/library/fedora:28 Mar 7, 2018 16:53 247 MB
|
||||
6d54bef73e63 docker.io/library/hello:latest May 3, 2018 15:24 391.8 MB
|
||||
|
||||
```
|
||||
|
||||
新镜像的标签为 `hello:latest`,我们可以将其推送至远程镜像仓库,可以使用 [CRI-O][4] 或其它 Kubernetes CRI 兼容的运行时运行该镜像,也可以推送到远程仓库。如果你要测试对 Docker build 命令的替代性,你可以将镜像拷贝至 docker 守护进程的本地镜像存储中,这样 Docker 也可以使用该镜像。使用 `buildah push` 可以很容易的完成推送操作:
|
||||
新镜像的标签为 `hello:latest`,我们可以将其推送至远程镜像仓库,可以使用 [CRI-O][4] 或其它 Kubernetes CRI 兼容的运行时来运行该镜像,也可以推送到远程仓库。如果你要测试对 Docker build 命令的替代性,你可以将镜像拷贝至 docker 守护进程的本地镜像存储中,这样 Docker 也可以使用该镜像。使用 `buildah push` 可以很容易的完成推送操作:
|
||||
|
||||
```
|
||||
[chris@krang] $ sudo buildah push hello:latest docker-daemon:hello:latest
|
||||
Getting image source signatures
|
||||
@ -76,12 +80,11 @@ docker.io/hello latest 6d54bef73e63 2 minutes ago 398 MB
|
||||
|
||||
[chris@krang] $ sudo docker run -t hello:latest
|
||||
Hello, world!
|
||||
|
||||
```
|
||||
|
||||
### 若干差异
|
||||
|
||||
与 Docker build 不同,Buildah 不会自动的将 Dockerfile 中的每条指令产生的变更提到到新的<ruby>分层<rt>layer</rt></ruby>中,只是简单的每次从头到尾执行构建。类似于<ruby>自动化<rt>automation</rt></ruby>和<ruby>流水线构建<rt>build pipelines</rt></ruby>,这种<ruby>无缓存构建<rt>non-cached</rt></ruby>方式的好处是可以提高构建速度,在指令较多时尤为明显。从<ruby>自动部署<rt>automated deployment</rt></ruby>或<ruby>持续交付<rt>continuous delivery</rt></ruby>的视角来看,使用这种方式可以快速的将新变更落实到生产环境中。
|
||||
与 Docker build 不同,Buildah 不会自动的将 Dockerfile 中的每条指令产生的变更提到新的<ruby>分层<rt>layer</rt></ruby>中,只是简单的每次从头到尾执行构建。类似于<ruby>自动化<rt>automation</rt></ruby>和<ruby>流水线构建<rt>build pipeline</rt></ruby>,这种<ruby>无缓存构建<rt>non-cached</rt></ruby>方式的好处是可以提高构建速度,在指令较多时尤为明显。从<ruby>自动部署<rt>automated deployment</rt></ruby>或<ruby>持续交付<rt>continuous delivery</rt></ruby>的视角来看,使用这种方式可以快速的将新变更落实到生产环境中。
|
||||
|
||||
但从实际角度出发,缓存机制的缺乏对镜像开发不利,毕竟缓存层可以避免一遍遍的执行构建,从而显著的节省时间。自动分层只在 `build-using-dockerfile` 命令中生效。但我们在下面会看到,Buildah 原生命令允许我们选择将变更提交到硬盘的时间,提高了开发的灵活性。
|
||||
|
||||
@ -89,7 +92,8 @@ Hello, world!
|
||||
|
||||
Buildah _真正_ 有趣之处在于它的原生命令,你可以在容器构建过程中使用这些命令进行交互。相比与使用 `build-using-dockerfile/bud` 命令执行每次构建,Buildah 提供命令让你可以与构建过程中的临时容器进行交互。(Docker 也使用临时或<ruby> _中间_ <rt>intermediate</rt></ruby>容器,但你无法在镜像构建过程中与其交互。)
|
||||
|
||||
还是使用 "GNU Hello" 为例,考虑使用如下 Buildah 命令构建的镜像:
|
||||
还是使用 “GNU Hello” 为例,考虑使用如下 Buildah 命令构建的镜像:
|
||||
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
|
||||
@ -123,18 +127,18 @@ buildah config --entrypoint /usr/local/bin/hello $container
|
||||
|
||||
# Finally saves the running container to an image
|
||||
buildah commit --format docker $container hello:latest
|
||||
|
||||
```
|
||||
|
||||
我们可以一眼看出这是一个 Bash 脚本而不是 Dockerfile。基于 Buildah 的原生命令,可以轻易的使用任何脚本语言或你擅长的自动化工具编写脚本。形式可以是 makefile、Python 脚本或其它你擅长的类型。
|
||||
|
||||
这个脚本做了哪些工作呢?首先,Buildah 命令 `container=$(buildah from fedora:28)` 基于 fedora:28 镜像创建了一个正在运行的容器,将容器名(buildah from 命令的返回值)保存到变量中,便于后续使用。后续所有命令都是有 $container 变量指明需要操作的容器。这些命令的功能大多可以从名称看出:`buildah copy` 将文件拷贝至容器,`buildah run` 会在容器中执行命令。可以很容易的将上述命令与 Dockerfile 中的指令对应起来。
|
||||
这个脚本做了哪些工作呢?首先,Buildah 命令 `container=$(buildah from fedora:28)` 基于 fedora:28 镜像创建了一个正在运行的容器,将容器名(`buildah from` 命令的返回值)保存到变量中,便于后续使用。后续所有命令都是有 `$container` 变量指明需要操作的容器。这些命令的功能大多可以从名称看出:`buildah copy` 将文件拷贝至容器,`buildah run` 会在容器中执行命令。可以很容易的将上述命令与 Dockerfile 中的指令对应起来。
|
||||
|
||||
最后一条命令 `buildah commit` 将容器提交到硬盘上的镜像中。当不使用 Dockerfile 而是使用 Buildah 命令构建镜像时,你可以使用 `commit` 命令决定何时保存变更。在上例中,所有的变更是一起提交的;但也可以增加中间提交,让你可以选择作为起点的<ruby>缓存点<rt>cache points</rt></ruby>。(例如,执行完 `dnf install` 命令后将变更缓存到硬盘是特别有意义的,一方面因为该操作耗时较长,另一方面每次执行的结果也确实相同。)
|
||||
最后一条命令 `buildah commit` 将容器提交到硬盘上的镜像中。当不使用 Dockerfile 而是使用 Buildah 命令构建镜像时,你可以使用 `commit` 命令决定何时保存变更。在上例中,所有的变更是一起提交的;但也可以增加中间提交,让你可以选择作为起点的<ruby>缓存点<rt>cache point</rt></ruby>。(例如,执行完 `dnf install` 命令后将变更缓存到硬盘是特别有意义的,一方面因为该操作耗时较长,另一方面每次执行的结果也确实相同。)
|
||||
|
||||
### 挂载点,安装目录以及 chroot
|
||||
|
||||
另一个可以大大增加构建镜像灵活性的 Buildah 命令是 `buildah mount`,可以将容器的根目录挂载到你主机的一个挂载点上。例如:
|
||||
|
||||
```
|
||||
[chris@krang] $ container=$(sudo buildah from fedora:28)
|
||||
[chris@krang] $ mountpoint=$(sudo buildah mount ${container})
|
||||
@ -145,9 +149,10 @@ Fedora release 28 (Twenty Eight)
|
||||
[chris@krang] $ ls ${mountpoint}
|
||||
bin dev home lib64 media opt root sbin sys usr
|
||||
boot etc lib lost+found mnt proc run srv tmp var
|
||||
|
||||
```
|
||||
这太棒了,你可以通过挂载点交互对容器镜像进行修改。这允许你使用主机上的工具进行构建和安装软件,不用将这些构建工具打包到容器镜像本身中。例如,在我们上面的 Bash 脚本中,我们需要安装 tar、Gzip、GCC 和 make,在容器内编译 "GNU Hello"。如果使用挂载点,我仍使用同样的工具进行构建,但下载的压缩包和 tar、Gzip 等 RPM 包都在主机而不是容器和生成的镜像内:
|
||||
|
||||
这太棒了,你可以通过与挂载点交互对容器镜像进行修改。这允许你使用主机上的工具进行构建和安装软件,不用将这些构建工具打包到容器镜像本身中。例如,在我们上面的 Bash 脚本中,我们需要安装 tar、Gzip、GCC 和 make,在容器内编译 “GNU Hello”。如果使用挂载点,我仍使用同样的工具进行构建,但下载的压缩包和 tar、Gzip 等 RPM 包都在主机而不是容器和生成的镜像内:
|
||||
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
|
||||
@ -174,7 +179,6 @@ chroot $mountpoint bash -c "/usr/local/bin/hello -v"
|
||||
buildah config --entrypoint "/usr/local/bin/hello" $container
|
||||
buildah commit --format docker $container hello
|
||||
buildah unmount $container
|
||||
|
||||
```
|
||||
|
||||
在上述脚本中,需要提到如下几点:
|
||||
@ -185,22 +189,22 @@ buildah unmount $container
|
||||
4. 这里的 `chroot` 命令用于将挂载点本身当作根路径并测试 "hello" 是否正常工作;类似于前面例子中用到的 `buildah run` 命令。
|
||||
|
||||
|
||||
这个脚本更加短小,使用大多数 Linux 爱好者都很熟悉的工具,最后生成的镜像也更小(没有压缩包,没有额外的软件包等)。你甚至可以使用主机系统上的包管理器为容器安装软件。例如,(出于某种原因)你希望安装 GNU Hello 的同时在容器中安装 [NGINX][5]:
|
||||
这个脚本更加短小,使用大多数 Linux 爱好者都很熟悉的工具,最后生成的镜像也更小(没有 tar 包,没有额外的软件包等)。你甚至可以使用主机系统上的包管理器为容器安装软件。例如,(出于某种原因)你希望安装 GNU Hello 的同时在容器中安装 [NGINX][5]:
|
||||
|
||||
```
|
||||
[chris@krang] $ mountpoint=$(sudo buildah mount ${container})
|
||||
[chris@krang] $ sudo dnf install nginx --installroot $mountpoint
|
||||
[chris@krang] $ sudo chroot $mountpoint nginx -v
|
||||
nginx version: nginx/1.12.1
|
||||
|
||||
```
|
||||
|
||||
在上面的例子中,DNF 使用 `--installroot` 参数将 NGINX 安装到容器中,可以通过 chroot 进行校验。
|
||||
|
||||
### 快来试试吧!
|
||||
|
||||
Buildah 是一种轻量级、灵活的容器镜像构建方法,不需要在主机上运行完整的 Docker 守护进程。除了提供基于 Dockerfiles 构建容器的开箱即用支持,Buildah 还可以很容易的与脚本或你喜欢的构建工具相结合,特别是可以使用主机上已有的工具构建容器镜像。Buildah 生成的容器体积更小,更便于网络传输,占用更小的存储空间,而且潜在的受攻击面更小。快来试试吧!
|
||||
Buildah 是一种轻量级、灵活的容器镜像构建方法,不需要在主机上运行完整的 Docker 守护进程。除了提供基于 Dockerfile 构建容器的开箱即用支持,Buildah 还可以很容易的与脚本或你喜欢的构建工具相结合,特别是可以使用主机上已有的工具构建容器镜像。Buildah 生成的容器体积更小,更便于网络传输,占用更小的存储空间,而且潜在的受攻击面更小。快来试试吧!
|
||||
|
||||
**[阅读相关的故事,[使用 Buildah 创建小体积容器][6]]**
|
||||
**[阅读相关的故事,[使用 Buildah 创建小体积的容器][6]]**
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -208,8 +212,8 @@ via: https://opensource.com/article/18/6/getting-started-buildah
|
||||
|
||||
作者:[Chris Collins][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[pinewall](https://github.com/pinewall)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -219,4 +223,4 @@ via: https://opensource.com/article/18/6/getting-started-buildah
|
||||
[3]:http://chris.collins.is/2017/08/17/buildah-a-new-way-to-build-container-images/
|
||||
[4]:http://cri-o.io/
|
||||
[5]:https://www.nginx.com/
|
||||
[6]:https://opensource.com/article/18/5/containers-buildah
|
||||
[6]:https://linux.cn/article-9719-1.html
|
@ -2,19 +2,17 @@ TrueOS 不再想要成为“桌面 BSD”了
|
||||
============================================================
|
||||
|
||||
|
||||
[TrueOS][9] 很快会有一些非常重大的变化。今天,我们将了解桌面 BSD 将会发生什么。
|
||||
[TrueOS][9] 很快会有一些非常重大的变化。今天,我们将了解桌面 BSD 领域将会发生什么。
|
||||
|
||||
### 通告
|
||||
|
||||
![TrueOS: Core Operating System BSD](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/06/true-os-bsd-desktop.jpeg)
|
||||
|
||||
[TrueOS][10] 背后的团队[宣布][11],他们将改变项目的重点。到目前为止,TrueOS 使用开箱即用的图形用户界面来轻松安装 BSD。然而,它现在将成为“一个先进的操作系统,保留你所知道和喜欢 ZFS([OpenZFS][12])和 [FreeBSD][13]的所有稳定性,并添加额外的功能来创造一个全新的、创新的操作系统。我们的目标是创建一个中心操作系统,该系统具有模块化、功能性,非常适合自己动手和高级用户。“
|
||||
[TrueOS][10] 背后的团队[宣布][11],他们将改变项目的重点。到目前为止,TrueOS 使用开箱即用的图形用户界面来轻松安装 BSD。然而,它现在将成为“一个先进的操作系统,保留你所知道和喜欢的 ZFS([OpenZFS][12])和 [FreeBSD][13]的所有稳定性,并添加额外的功能来创造一个全新的、创新的操作系统。我们的目标是创建一个核心操作系统,该系统具有模块化、实用性,非常适合自己动手和高级用户。“
|
||||
|
||||
从本质上讲,TrueOs 将成为 FreeBSD 的下游分支。他们将更新的软件集成到系统中,例如 [OpenRC][14] 和 [LibreSSL][15]。他们希望坚持 6 个月的发布周期。
|
||||
从本质上讲,TrueOs 将成为 FreeBSD 的下游分支。他们将集成更新一些的软件到系统中,例如 [OpenRC][14] 和 [LibreSSL][15]。他们希望能坚持 6 个月的发布周期。
|
||||
|
||||
目标是使 TrueOS 成为可以作为其他项目构建的基础。缺少图形部分以使其更加发行无关。
|
||||
|
||||
[建议阅读有关 MidnightBSD 创始人兼首席开发人员 Lucas Holt 的访谈][16]
|
||||
其目标是使 TrueOS 成为可以作为其他项目构建的基础。缺少图形部分以使其更加地与发行版无关。
|
||||
|
||||
### 桌面用户如何?
|
||||
|
||||
@ -22,15 +20,13 @@ TrueOS 不再想要成为“桌面 BSD”了
|
||||
|
||||
如果你目前拥有 TrueOS,则无需担心迁移。TrueOS 团队表示,“对于那些希望迁移到其他基于 FreeBSD 的发行版,如 Project Trident 或 [GhostBSD][19] 的人而言将会有迁移方式。”
|
||||
|
||||
[建议阅读有关 FreeDOS 创始人及开发领导 Lucas Holt 的访谈][16]
|
||||
|
||||
### 想法
|
||||
|
||||
当我第一次阅读公告时,坦率地说有点担心。改变名字可能是一个坏主意。客户将习惯使用一个名称,但如果产品名称发生变化,他们可能很容易失去对项目的跟踪。TrueOS 经历过名称更改。该项目于 2006 年启动时,它被命名为 PC-BSD,但在 2016 年,名称更改为 TrueOS。它让我想起了[ArchMerge 和 Arcolinux 传奇][21]。
|
||||
当我第一次阅读该公告时,坦率地说有点担心。改变名字可能是一个坏主意。客户将习惯使用一个名称,但如果产品名称发生变化,他们可能很容易失去对项目的跟踪。TrueOS 经历过名称更改。该项目于 2006 年启动时,它被命名为 PC-BSD,但在 2016 年,名称更改为 TrueOS。它让我想起了[ArchMerge 和 Arcolinux 传奇][21]。
|
||||
|
||||
话虽这么说,我认为这对 BSD 的桌面用户来说是一件好事。我听见 PC-BSD 和 TrueOS 的一个常见批评是它不是很精致。剥离项目的两个部分将有助于提高相关开发人员的关注度。TrueOS 团队将能够为缓慢进展的 FreeBSD 添加更新的功能,Project Trident 团队将能够改善用户的桌面体验。
|
||||
话虽这么说,我认为这对 BSD 的桌面用户来说是一件好事。我常听见对 PC-BSD 和 TrueOS 的一个批评是它不是很精致。剥离项目的两个部分将有助于提高相关开发人员的关注度。TrueOS 团队将能够为缓慢进展的 FreeBSD 添加更新的功能,Project Trident 团队将能够改善用户的桌面体验。
|
||||
|
||||
我希望两个团队都好。请记住,当有人在开源上工作时,即使是我们不会使用的工作时,我们也都会受益。
|
||||
我希望两个团队都好。请记住,当有人为开源而努力时,即使是我们不会使用的部分,我们也都会受益。
|
||||
|
||||
你对 TrueOS 和 Project Trident 的未来有何看法?请在下面的评论中告诉我们。
|
||||
|
||||
@ -47,7 +43,7 @@ via: https://itsfoss.com/trueos-plan-change/
|
||||
|
||||
作者:[John Paul Wohlscheid][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,3 +1,6 @@
|
||||
Translating by MjSeven
|
||||
|
||||
|
||||
3 practical Python tools: magic methods, iterators and generators, and method magic
|
||||
======
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
What is the Difference Between the macOS and Linux Kernels
|
||||
tranWhat is the Difference Between the macOS and Linux Kernels
|
||||
======
|
||||
Some people might think that there are similarities between the macOS and the Linux kernel because they can handle similar commands and similar software. Some people even think that Apple’s macOS is based on Linux. The truth is that both kernels have very different histories and features. Today, we will take a look at the difference between macOS and Linux kernels.
|
||||
|
||||
|
@ -1,31 +1,30 @@
|
||||
Translating by qhwdw
|
||||
Running a Python application on Kubernetes
|
||||
在 Kubernetes 上运行一个 Python 应用程序
|
||||
============================================================
|
||||
|
||||
### This step-by-step tutorial takes you through the process of deploying a simple Python application on Kubernetes.
|
||||
### 这个分步指导教程教你通过在 Kubernetes 上部署一个简单的 Python 应用程序来学习部署的流程。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/build_structure_tech_program_code_construction.png?itok=nVsiLuag)
|
||||
Image by : opensource.com
|
||||
图片来源:opensource.com
|
||||
|
||||
Kubernetes is an open source platform that offers deployment, maintenance, and scaling features. It simplifies management of containerized Python applications while providing portability, extensibility, and self-healing capabilities.
|
||||
Kubernetes 是一个具备部署、维护、和可伸缩特性的开源平台。它在提供可移植性、可扩展性、以及自我修复能力的同时,简化了容器化 Python 应用程序的管理。
|
||||
|
||||
Whether your Python applications are simple or more complex, Kubernetes lets you efficiently deploy and scale them, seamlessly rolling out new features while limiting resources to only those required.
|
||||
不论你的 Python 应用程序是简单还是复杂,Kubernetes 都可以帮你高效地部署和伸缩它们,在有限的资源范围内滚动升级新特性。
|
||||
|
||||
In this article, I will describe the process of deploying a simple Python application to Kubernetes, including:
|
||||
在本文中,我将描述在 Kubernetes 上部署一个简单的 Python 应用程序的过程,它包括:
|
||||
|
||||
* Creating Python container images
|
||||
* 创建 Python 容器镜像
|
||||
|
||||
* Publishing the container images to an image registry
|
||||
* 发布容器镜像到镜像注册中心
|
||||
|
||||
* Working with persistent volume
|
||||
* 使用持久卷
|
||||
|
||||
* Deploying the Python application to Kubernetes
|
||||
* 在 Kubernetes 上部署 Python 应用程序
|
||||
|
||||
### Requirements
|
||||
### 必需条件
|
||||
|
||||
You will need Docker, kubectl, and this [source code][10].
|
||||
你需要 Docker、kubectl、以及这个 [源代码][10]。
|
||||
|
||||
Docker is an open platform to build and ship distributed applications. To install Docker, follow the [official documentation][11]. To verify that Docker runs your system:
|
||||
Docker 是一个构建和承载已发布的应用程序的开源平台。可以参照 [官方文档][11] 去安装 Docker。运行如下的命令去验证你的系统上运行的 Docker:
|
||||
|
||||
```
|
||||
$ docker info
|
||||
@ -41,25 +40,25 @@ WARNING: No memory limit support
|
||||
WARNING: No swap limit support
|
||||
```
|
||||
|
||||
kubectl is a command-line interface for executing commands against a Kubernetes cluster. Run the shell script below to install kubectl:
|
||||
kubectl 是在 Kubernetes 集群上运行命令的一个命令行界面。运行下面的 shell 脚本去安装 kubectl:
|
||||
|
||||
```
|
||||
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
|
||||
```
|
||||
|
||||
Deploying to Kubernetes requires a containerized application. Let's review containerizing Python applications.
|
||||
部署到 Kubernetes 的应用要求必须是一个容器化的应用程序。我们来回顾一下 Python 应用程序的容器化过程。
|
||||
|
||||
### Containerization at a glance
|
||||
### 一句话了解容器化
|
||||
|
||||
Containerization involves enclosing an application in a container with its own operating system. This full machine virtualization option has the advantage of being able to run an application on any machine without concerns about dependencies.
|
||||
容器化是指将一个应用程序所需要的东西打包进一个自带操作系统的容器中。这种完整机器虚拟化的好处是,一个应用程序能够在任何机器上运行而无需考虑它的依赖项。
|
||||
|
||||
Roman Gaponov's [article][12] serves as a reference. Let's start by creating a container image for our Python code.
|
||||
我们以 Roman Gaponov 的 [文章][12] 为参考,来为我们的 Python 代码创建一个容器。
|
||||
|
||||
### Create a Python container image
|
||||
### 创建一个 Python 容器镜像
|
||||
|
||||
To create these images, we will use Docker, which enables us to deploy applications inside isolated Linux software containers. Docker is able to automatically build images using instructions from a Docker file.
|
||||
为创建这些镜像,我们将使用 Docker,它可以让我们在一个隔离的 Linux 软件容器中部署应用程序。Docker 可以使用来自一个 `Docker file` 中的指令来自动化构建镜像。
|
||||
|
||||
This is a Docker file for our Python application:
|
||||
这是我们的 Python 应用程序的 `Docker file`:
|
||||
|
||||
```
|
||||
FROM python:3.6
|
||||
@ -91,43 +90,43 @@ VOLUME ["/app-data"]
|
||||
CMD ["python", "app.py"]
|
||||
```
|
||||
|
||||
This Docker file contains instructions to run our sample Python code. It uses the Python 3.5 development environment.
|
||||
这个 `Docker file` 包含运行我们的示例 Python 代码的指令。它使用的开发环境是 Python 3.5。
|
||||
|
||||
### Build a Python Docker image
|
||||
### 构建一个 Python Docker 镜像
|
||||
|
||||
We can now build the Docker image from these instructions using this command:
|
||||
现在,我们可以使用下面的这个命令按照那些指令来构建 Docker 镜像:
|
||||
|
||||
```
|
||||
docker build -t k8s_python_sample_code .
|
||||
```
|
||||
|
||||
This command creates a Docker image for our Python application.
|
||||
这个命令为我们的 Python 应用程序创建了一个 Docker 镜像。
|
||||
|
||||
### Publish the container images
|
||||
### 发布容器镜像
|
||||
|
||||
We can publish our Python container image to different private/public cloud repositories, like Docker Hub, AWS ECR, Google Container Registry, etc. For this tutorial, we'll use Docker Hub.
|
||||
我们可以将我们的 Python 容器镜像发布到不同的私有/公共云仓库中,像 Docker Hub、AWS ECR、Google Container Registry 等等。本教程中我们将发布到 Docker Hub。
|
||||
|
||||
Before publishing the image, we need to tag it to a version:
|
||||
在发布镜像之前,我们需要给它标记一个版本号:
|
||||
|
||||
```
|
||||
docker tag k8s_python_sample_code:latest k8s_python_sample_code:0.1
|
||||
```
|
||||
|
||||
### Push the image to a cloud repository
|
||||
### 推送镜像到一个云仓库
|
||||
|
||||
Using a Docker registry other than Docker Hub to store images requires you to add that container registry to the local Docker daemon and Kubernetes Docker daemons. You can look up this information for the different cloud registries. We'll use Docker Hub in this example.
|
||||
如果使用一个 Docker 注册中心而不是 Docker Hub 去保存镜像,那么你需要在你本地的 Docker 守护程序和 Kubernetes Docker 守护程序上添加一个容器注册中心。对于不同的云注册中心,你可以在它上面找到相关信息。我们在示例中使用的是 Docker Hub。
|
||||
|
||||
Execute this Docker command to push the image:
|
||||
运行下面的 Docker 命令去推送镜像:
|
||||
|
||||
```
|
||||
docker push k8s_python_sample_code
|
||||
```
|
||||
|
||||
### Working with CephFS persistent storage
|
||||
### 使用 CephFS 持久卷
|
||||
|
||||
Kubernetes supports many persistent storage providers, including AWS EBS, CephFS, GlusterFS, Azure Disk, NFS, etc. I will cover Kubernetes persistence storage with CephFS.
|
||||
Kubernetes 支持许多的持久存储提供商,包括 AWS EBS、CephFS、GlusterFS、Azure Disk、NFS 等等。我在示例中使用 CephFS 做为 Kubernetes 的持久卷。
|
||||
|
||||
To use CephFS for persistent data to Kubernetes containers, we will create two files:
|
||||
为使用 CephFS 存储 Kubernetes 的容器数据,我们将创建两个文件:
|
||||
|
||||
persistent-volume.yml
|
||||
|
||||
@ -167,20 +166,20 @@ spec:
|
||||
storage: 10Gi
|
||||
```
|
||||
|
||||
We can now use kubectl to add the persistent volume and claim to the Kubernetes cluster:
|
||||
现在,我们将使用 kubectl 去添加持久卷并声明到 Kubernetes 集群中:
|
||||
|
||||
```
|
||||
$ kubectl create -f persistent-volume.yml
|
||||
$ kubectl create -f persistent-volume-claim.yml
|
||||
```
|
||||
|
||||
We are now ready to deploy to Kubernetes.
|
||||
现在,我们准备去部署 Kubernetes。
|
||||
|
||||
### Deploy the application to Kubernetes
|
||||
### 在 Kubernetes 上部署应用程序
|
||||
|
||||
To manage the last mile of deploying the application to Kubernetes, we will create two important files: a service file and a deployment file.
|
||||
为管理部署应用程序到 Kubernetes 上的最后一步,我们将创建两个重要文件:一个服务文件和一个部署文件。
|
||||
|
||||
Create a file and name it `k8s_python_sample_code.service.yml` with the following content:
|
||||
使用下列的内容创建服务文件,并将它命名为 `k8s_python_sample_code.service.yml`:
|
||||
|
||||
```
|
||||
apiVersion: v1
|
||||
@ -198,7 +197,7 @@ spec:
|
||||
k8s-app: k8s_python_sample_code
|
||||
```
|
||||
|
||||
Create a file and name it `k8s_python_sample_code.deployment.yml` with the following content:
|
||||
使用下列的内容创建部署文件并将它命名为 `k8s_python_sample_code.deployment.yml`:
|
||||
|
||||
```
|
||||
apiVersion: extensions/v1beta1
|
||||
@ -228,35 +227,35 @@ spec:
|
||||
claimName: appclaim1
|
||||
```
|
||||
|
||||
Finally, use kubectl to deploy the application to Kubernetes:
|
||||
最后,我们使用 kubectl 将应用程序部署到 Kubernetes:
|
||||
|
||||
```
|
||||
$ kubectl create -f k8s_python_sample_code.deployment.yml $ kubectl create -f k8s_python_sample_code.service.yml
|
||||
```
|
||||
|
||||
Your application was successfully deployed to Kubernetes.
|
||||
现在,你的应用程序已经成功部署到 Kubernetes。
|
||||
|
||||
You can verify whether your application is running by inspecting the running services:
|
||||
你可以通过检查运行的服务来验证你的应用程序是否在运行:
|
||||
|
||||
```
|
||||
kubectl get services
|
||||
```
|
||||
|
||||
May Kubernetes free you from future deployment hassles!
|
||||
或许 Kubernetes 可以解决未来你部署应用程序的各种麻烦!
|
||||
|
||||
_Want to learn more about Python? Nanjekye's book, [Python 2 and 3 Compatibility][7]offers clean ways to write code that will run on both Python 2 and 3, including detailed examples of how to convert existing Python 2-compatible code to code that will run reliably on both Python 2 and 3._
|
||||
_想学习更多关于 Python 的知识?Nanjekye 的书,[和平共处的 Python 2 和 3][7] 提供了完整的方法,让你写的代码在 Python 2 和 3 上完美运行,包括如何转换已有的 Python 2 代码为能够可靠运行在 Python 2 和 3 上的代码的详细示例。_
|
||||
|
||||
|
||||
### About the author
|
||||
### 关于作者
|
||||
|
||||
[![](https://opensource.com/sites/default/files/styles/profile_pictures/public/pictures/joannah-nanjekye.jpg?itok=F4RqEjoA)][13] Joannah Nanjekye - Straight Outta 256 , I choose Results over Reasons, Passionate Aviator, Show me the code.[More about me][8]
|
||||
[![](https://opensource.com/sites/default/files/styles/profile_pictures/public/pictures/joannah-nanjekye.jpg?itok=F4RqEjoA)][13] Joannah Nanjekye - Straight Outta 256 , 只要结果不问原因,充满激情的飞行员,喜欢用代码说话。[关于我的更多信息][8]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/1/running-python-application-kubernetes
|
||||
|
||||
作者:[Joannah Nanjekye ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
Loading…
Reference in New Issue
Block a user