summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/pods/logs.go31
-rw-r--r--docs/tutorials/podman_tutorial_cn.md173
-rwxr-xr-xhack/xref-helpmsgs-manpages7
-rw-r--r--libpod/define/container_inspect.go10
-rw-r--r--libpod/networking_linux.go4
-rw-r--r--libpod/networking_linux_test.go217
6 files changed, 412 insertions, 30 deletions
diff --git a/cmd/podman/pods/logs.go b/cmd/podman/pods/logs.go
index fe5205669..a79c0430f 100644
--- a/cmd/podman/pods/logs.go
+++ b/cmd/podman/pods/logs.go
@@ -27,11 +27,11 @@ type logsOptionsWrapper struct {
var (
logsPodOptions logsOptionsWrapper
logsPodDescription = `Displays logs for pod with one or more containers.`
- logsPodCommand = &cobra.Command{
+ podLogsCommand = &cobra.Command{
Use: "logs [options] POD",
Short: "Fetch logs for pod with one or more containers",
Long: logsPodDescription,
- // We dont want users to invoke latest and pod togather
+ // We dont want users to invoke latest and pod together
Args: func(cmd *cobra.Command, args []string) error {
switch {
case registry.IsRemote() && logsPodOptions.Latest:
@@ -53,35 +53,16 @@ var (
podman pod logs --follow=true --since 10m podID
podman pod logs mywebserver`,
}
-
- containerLogsCommand = &cobra.Command{
- Use: logsPodCommand.Use,
- Short: logsPodCommand.Short,
- Long: logsPodCommand.Long,
- Args: logsPodCommand.Args,
- RunE: logsPodCommand.RunE,
- ValidArgsFunction: logsPodCommand.ValidArgsFunction,
- Example: `podman pod logs podId
- podman pod logs -c ctrname podName
- podman pod logs --tail 2 mywebserver
- podman pod logs --follow=true --since 10m podID`,
- }
)
func init() {
+ // pod logs
registry.Commands = append(registry.Commands, registry.CliCommand{
- Command: logsPodCommand,
- })
- logsFlags(logsPodCommand)
- validate.AddLatestFlag(logsPodCommand, &logsPodOptions.Latest)
-
- // container logs
- registry.Commands = append(registry.Commands, registry.CliCommand{
- Command: containerLogsCommand,
+ Command: podLogsCommand,
Parent: podCmd,
})
- logsFlags(containerLogsCommand)
- validate.AddLatestFlag(containerLogsCommand, &logsPodOptions.Latest)
+ logsFlags(podLogsCommand)
+ validate.AddLatestFlag(podLogsCommand, &logsPodOptions.Latest)
}
func logsFlags(cmd *cobra.Command) {
diff --git a/docs/tutorials/podman_tutorial_cn.md b/docs/tutorials/podman_tutorial_cn.md
new file mode 100644
index 000000000..5290c4076
--- /dev/null
+++ b/docs/tutorials/podman_tutorial_cn.md
@@ -0,0 +1,173 @@
+> - 译文出自:[掘金翻译计划](https://juejin.cn/translate)
+
+![PODMAN logo](../../logo/podman-logo-source.svg)
+
+Podman是由libpod库提供一个实用的程序,可以被用于创建和管理容器。
+
+下面的教程会教你如何启动 Podman 并使用 Podman 执行一些基本的命令。
+
+如果你正在使用 Mac 或者 Windows
+,你应该先查看[Mac 和 Windows 使用说明](https://github.com/containers/podman/blob/master/docs/tutorials/mac_win_client.md)来设置 Podman
+远程客户端。
+
+**注意**:示例中所有命令皆以非 root 的用户运行,必要的时候通过 `sudo` 命令来获取 root 权限。
+
+## 安装Podman
+
+安装或者编译 Podman ,请参照[安装说明](https://github.com/containers/podman/blob/master/install.md)。
+
+## 熟悉podman
+
+### 运行一个示例容器
+
+这个示例容器会运行一个简单的只有主页的 httpd 服务器。
+
+```console
+podman run -dt -p 8080:8080/tcp -e HTTPD_VAR_RUN=/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \
+ -e HTTPD_MAIN_CONF_PATH=/etc/httpd/conf \
+ -e HTTPD_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/httpd/ \
+ registry.fedoraproject.org/f29/httpd /usr/bin/run-httpd
+```
+
+因为命令中的 *-d* 参数表明容器以 "detached" 模式运行,所以 Podman 会在容器运行后打印容器的 ID。
+
+注意为了访问这个 HTTP 服务器,我们将使用端口转发。成功运行需要 slirp4netns 的 v0.3.0+ 版本。
+
+Podman 的 *ps* 命令用于列出正在创建和运行的容器。
+
+```console
+podman ps
+```
+
+**注意**:如果为 *ps* 命令添加 *-a* 参数,Podman 将展示所有的容器。
+
+### 查看正在运行的容器
+
+你可以 "inspect" (查看)一个正在运行的容器的元数据以及其他详细信息。我们甚至可以使用 inspect 的子命令查看分配给容器的 IP 地址。由于容器以非 root 模式运行,没有分配 IP 地址,inspect 的输出会是 "
+none" 。
+
+```console
+podman inspect -l | grep IPAddress\":
+ "SecondaryIPAddresses": null,
+ "IPAddress": "",
+```
+
+**注意**:*-l* 参数是**最近的容器**的指代,你也可以使用容器的ID 代替 *-l*
+
+### 测试httpd服务器
+
+由于我们没有容器的 IP 地址,我们可以使用 curl 测试主机和容器之间的网络通信。下面的命令应该显示我们的容器化 httpd 服务器 的主页。
+
+```console
+curl http://localhost:8080
+```
+
+### 查看容器的日志
+
+你也可以使用 podman 查看容器的日志
+
+```console
+podman logs --latest
+10.88.0.1 - - [07/Feb/2018:15:22:11 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.55.1" "-"
+10.88.0.1 - - [07/Feb/2018:15:22:30 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.55.1" "-"
+10.88.0.1 - - [07/Feb/2018:15:22:30 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.55.1" "-"
+10.88.0.1 - - [07/Feb/2018:15:22:31 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.55.1" "-"
+10.88.0.1 - - [07/Feb/2018:15:22:31 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.55.1" "-"
+```
+
+### 查看容器中的进程pid
+
+你可以使用 *top* 命令查看容器中 httpd 的 pid
+
+```console
+podman top <container_id>
+ UID PID PPID C STIME TTY TIME CMD
+ 0 31873 31863 0 09:21 ? 00:00:00 nginx: master process nginx -g daemon off;
+ 101 31889 31873 0 09:21 ? 00:00:00 nginx: worker process
+```
+
+### 设置容器的检查点
+
+设置检查点会在停止容器的同时把容器中所有进程的状态写入磁盘。
+
+有了它,容器后续可以被恢复,并在与检查点完全相同的时间点继续运行。 这个功能需要在系统上安装 CRIU 的 3.11+ 版本。
+
+这个功能不支持非 root 模式,因此,如果你想尝试使用它,你需要使用 sudo 方式重新创建容器。
+
+设置容器检查点请使用:
+
+```console
+sudo podman container checkpoint <container_id>
+```
+
+### 恢复容器
+
+恢复容器只能在以前设置过检查点的容器上使用。恢复的容器会在与设置检查点时完全相同的时间点继续运行。
+
+恢复容器请使用:
+
+```console
+sudo podman container restore <container_id>
+```
+
+恢复之后。容器会像设置检查点之前一样回复请求
+
+```console
+curl http://<IP_address>:8080
+```
+
+### 迁移容器
+
+为了将容器从一个主机上热迁移到另一个主机,容器可以在在源系统上创建检查点,传输到目的系统,然后再在目的系统上恢复。
+为了便于传输容器的检查点,可以将其存储在一个指定的输出文件中。
+
+在源系统上:
+
+```console
+sudo podman container checkpoint <container_id> -e /tmp/checkpoint.tar.gz
+scp /tmp/checkpoint.tar.gz <destination_system>:/tmp
+```
+
+在目标系统上:
+
+```console
+sudo podman container restore -i /tmp/checkpoint.tar.gz
+```
+
+恢复之后,容器会像设置检查点之前一样回复请求。这时,容器会在目标系统上继续运行。
+
+```console
+curl http://<IP_address>:8080
+```
+
+### 停止容器
+
+停止 httpd 容器
+
+```console
+podman stop --latest
+```
+
+你还可以使用 *ps* 命令检查一个或多个容器的状态,在这个例子中,我们使用 *-a* 参数列出所有的容器。
+
+```console
+podman ps -a
+```
+
+### 移除容器
+
+移除 httpd 容器
+
+```console
+podman rm --latest
+```
+
+你可以使用 *podman ps -a* 验证容器的删除。
+
+## 集成测试
+
+在环境中如何设置并运行集成测试请查看集成测试的[自述页面](../../test/README.md)
+
+## 更多信息
+
+有关podman 和它的子命令的更多信息请查看 podman 的[自述页面](../../README.md#commands)
diff --git a/hack/xref-helpmsgs-manpages b/hack/xref-helpmsgs-manpages
index 6a2d627bb..a447f4da1 100755
--- a/hack/xref-helpmsgs-manpages
+++ b/hack/xref-helpmsgs-manpages
@@ -242,6 +242,13 @@ sub podman_help {
if ($line =~ /^\s{1,4}(\S+)\s/) {
my $subcommand = $1;
print "> podman @_ $subcommand\n" if $debug;
+
+ # check that the same subcommand is not listed twice (#12356)
+ if (exists $help{$subcommand}) {
+ warn "$ME: 'podman @_ help' lists '$subcommand' twice\n";
+ ++$Errs;
+ }
+
$help{$subcommand} = podman_help(@_, $subcommand)
unless $subcommand eq 'help'; # 'help' not in man
}
diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go
index 9f939335c..8e07cff81 100644
--- a/libpod/define/container_inspect.go
+++ b/libpod/define/container_inspect.go
@@ -542,6 +542,12 @@ type InspectContainerHostConfig struct {
CgroupConf map[string]string `json:"CgroupConf"`
}
+// Address represents an IP address.
+type Address struct {
+ Addr string
+ PrefixLength int
+}
+
// InspectBasicNetworkConfig holds basic configuration information (e.g. IP
// addresses, MAC address, subnet masks, etc) that are common for all networks
// (both additional and main).
@@ -556,7 +562,7 @@ type InspectBasicNetworkConfig struct {
IPPrefixLen int `json:"IPPrefixLen"`
// SecondaryIPAddresses is a list of extra IP Addresses that the
// container has been assigned in this network.
- SecondaryIPAddresses []string `json:"SecondaryIPAddresses,omitempty"`
+ SecondaryIPAddresses []Address `json:"SecondaryIPAddresses,omitempty"`
// IPv6Gateway is the IPv6 gateway this network will use.
IPv6Gateway string `json:"IPv6Gateway"`
// GlobalIPv6Address is the global-scope IPv6 Address for this network.
@@ -565,7 +571,7 @@ type InspectBasicNetworkConfig struct {
GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"`
// SecondaryIPv6Addresses is a list of extra IPv6 Addresses that the
// container has been assigned in this network.
- SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty"`
+ SecondaryIPv6Addresses []Address `json:"SecondaryIPv6Addresses,omitempty"`
// MacAddress is the MAC address for the interface in this network.
MacAddress string `json:"MacAddress"`
// AdditionalMacAddresses is a set of additional MAC Addresses beyond
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 314a74427..7d1214183 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -1139,7 +1139,7 @@ func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNe
config.IPPrefixLen = size
config.Gateway = netAddress.Gateway.String()
} else {
- config.SecondaryIPAddresses = append(config.SecondaryIPAddresses, netAddress.IPNet.IP.String())
+ config.SecondaryIPAddresses = append(config.SecondaryIPAddresses, define.Address{Addr: netAddress.IPNet.IP.String(), PrefixLength: size})
}
} else {
//ipv6
@@ -1148,7 +1148,7 @@ func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNe
config.GlobalIPv6PrefixLen = size
config.IPv6Gateway = netAddress.Gateway.String()
} else {
- config.SecondaryIPv6Addresses = append(config.SecondaryIPv6Addresses, netAddress.IPNet.IP.String())
+ config.SecondaryIPv6Addresses = append(config.SecondaryIPv6Addresses, define.Address{Addr: netAddress.IPNet.IP.String(), PrefixLength: size})
}
}
}
diff --git a/libpod/networking_linux_test.go b/libpod/networking_linux_test.go
index 06bf05723..d925b69f7 100644
--- a/libpod/networking_linux_test.go
+++ b/libpod/networking_linux_test.go
@@ -2,10 +2,14 @@ package libpod
import (
"fmt"
+ "net"
+ "reflect"
"testing"
- "github.com/containers/podman/v3/libpod/network/types"
"github.com/stretchr/testify/assert"
+
+ "github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/libpod/network/types"
)
func Test_ocicniPortsToNetTypesPorts(t *testing.T) {
@@ -234,6 +238,217 @@ func Test_ocicniPortsToNetTypesPorts(t *testing.T) {
}
}
+func Test_resultToBasicNetworkConfig(t *testing.T) {
+ testCases := []struct {
+ description string
+ expectError bool
+ inputResult types.StatusBlock
+ expectedNetworkConfig define.InspectBasicNetworkConfig
+ }{
+ {
+ description: "single secondary IPv4 address is shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("172.26.0.1"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.2"),
+ Mask: net.CIDRMask(20, 32),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.3"),
+ Mask: net.CIDRMask(10, 32),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ IPAddress: "172.26.0.2",
+ IPPrefixLen: 20,
+ Gateway: "172.26.0.1",
+ SecondaryIPAddresses: []define.Address{
+ {
+ Addr: "172.26.0.3",
+ PrefixLength: 10,
+ },
+ },
+ },
+ },
+ {
+ description: "multiple secondary IPv4 addresses are shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("172.26.0.1"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.2"),
+ Mask: net.CIDRMask(20, 32),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.3"),
+ Mask: net.CIDRMask(10, 32),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.4"),
+ Mask: net.CIDRMask(24, 32),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ IPAddress: "172.26.0.2",
+ IPPrefixLen: 20,
+ Gateway: "172.26.0.1",
+ SecondaryIPAddresses: []define.Address{
+ {
+ Addr: "172.26.0.3",
+ PrefixLength: 10,
+ },
+ {
+ Addr: "172.26.0.4",
+ PrefixLength: 24,
+ },
+ },
+ },
+ },
+ {
+ description: "single secondary IPv6 address is shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("ff02::fb"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fc"),
+ Mask: net.CIDRMask(20, 128),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fd"),
+ Mask: net.CIDRMask(10, 128),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ GlobalIPv6Address: "ff02::fc",
+ GlobalIPv6PrefixLen: 20,
+ IPv6Gateway: "ff02::fb",
+ SecondaryIPv6Addresses: []define.Address{
+ {
+ Addr: "ff02::fd",
+ PrefixLength: 10,
+ },
+ },
+ },
+ },
+ {
+ description: "multiple secondary IPv6 addresses are shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("ff02::fb"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fc"),
+ Mask: net.CIDRMask(20, 128),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fd"),
+ Mask: net.CIDRMask(10, 128),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fe"),
+ Mask: net.CIDRMask(24, 128),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ GlobalIPv6Address: "ff02::fc",
+ GlobalIPv6PrefixLen: 20,
+ IPv6Gateway: "ff02::fb",
+ SecondaryIPv6Addresses: []define.Address{
+ {
+ Addr: "ff02::fd",
+ PrefixLength: 10,
+ },
+ {
+ Addr: "ff02::fe",
+ PrefixLength: 24,
+ },
+ },
+ },
+ },
+ }
+
+ for _, tcl := range testCases {
+ tc := tcl
+ t.Run(tc.description, func(t *testing.T) {
+ t.Parallel()
+ actualNetworkConfig, err := resultToBasicNetworkConfig(tc.inputResult)
+
+ if tc.expectError && err == nil {
+ t.Fatalf("Expected error didn't happen")
+ }
+
+ if !tc.expectError && err != nil {
+ t.Fatalf("Unexpected error happened: %v", err)
+ }
+
+ if !reflect.DeepEqual(tc.expectedNetworkConfig, actualNetworkConfig) {
+ t.Fatalf(
+ "Expected networkConfig %+v didn't match actual value %+v", tc.expectedNetworkConfig, actualNetworkConfig)
+ }
+ })
+ }
+}
+
func benchmarkOCICNIPortsToNetTypesPorts(b *testing.B, ports []types.OCICNIPortMapping) {
for n := 0; n < b.N; n++ {
ocicniPortsToNetTypesPorts(ports)