summaryrefslogtreecommitdiffhomepage
path: root/g3doc
diff options
context:
space:
mode:
Diffstat (limited to 'g3doc')
-rw-r--r--g3doc/BUILD11
-rw-r--r--g3doc/README.md12
-rw-r--r--g3doc/style.md88
-rw-r--r--g3doc/user_guide/BUILD2
-rw-r--r--g3doc/user_guide/containerd/BUILD33
-rw-r--r--g3doc/user_guide/containerd/configuration.md70
-rw-r--r--g3doc/user_guide/containerd/containerd_11.md163
-rw-r--r--g3doc/user_guide/containerd/quick_start.md176
-rw-r--r--g3doc/user_guide/debugging.md10
-rw-r--r--g3doc/user_guide/quick_start/kubernetes.md12
-rw-r--r--g3doc/user_guide/quick_start/oci.md10
-rw-r--r--g3doc/user_guide/tutorials/BUILD22
-rw-r--r--g3doc/user_guide/tutorials/cni.md14
-rw-r--r--g3doc/user_guide/tutorials/docker.md2
14 files changed, 584 insertions, 41 deletions
diff --git a/g3doc/BUILD b/g3doc/BUILD
index dbbf96204..f91a77b6f 100644
--- a/g3doc/BUILD
+++ b/g3doc/BUILD
@@ -31,5 +31,14 @@ doc(
category = "Project",
permalink = "/community/",
subcategory = "Community",
- weight = "95",
+ weight = "10",
+)
+
+doc(
+ name = "style",
+ src = "style.md",
+ category = "Project",
+ permalink = "/community/style_guide/",
+ subcategory = "Community",
+ weight = "99",
)
diff --git a/g3doc/README.md b/g3doc/README.md
index 304a91493..22bfb15f7 100644
--- a/g3doc/README.md
+++ b/g3doc/README.md
@@ -117,9 +117,7 @@ for more information on filesystem bundles. `runsc` implements multiple commands
that perform various functions such as starting, stopping, listing, and querying
the status of containers.
-### Sentry
-
-<a name="sentry"></a> <!-- For deep linking. -->
+### Sentry {#sentry}
The Sentry is the largest component of gVisor. It can be thought of as a
application kernel. The Sentry implements all the kernel functionality needed by
@@ -136,9 +134,7 @@ calls it makes. For example, the Sentry is not able to open files directly; file
system operations that extend beyond the sandbox (not internal `/proc` files,
pipes, etc) are sent to the Gofer, described below.
-### Gofer
-
-<a name="gofer"></a> <!-- For deep linking. -->
+### Gofer {#gofer}
The Gofer is a standard host process which is started with each container and
communicates with the Sentry via the [9P protocol][9p] over a socket or shared
@@ -146,13 +142,13 @@ memory channel. The Sentry process is started in a restricted seccomp container
without access to file system resources. The Gofer mediates all access to the
these resources, providing an additional level of isolation.
-### Application
+### Application {#application}
The application is a normal Linux binary provided to gVisor in an OCI runtime
bundle. gVisor aims to provide an environment equivalent to Linux v4.4, so
applications should be able to run unmodified. However, gVisor does not
presently implement every system call, `/proc` file, or `/sys` file so some
-incompatibilities may occur. See [Commpatibility](./user_guide/compatibility.md)
+incompatibilities may occur. See [Compatibility](./user_guide/compatibility.md)
for more information.
[9p]: https://en.wikipedia.org/wiki/9P_(protocol)
diff --git a/g3doc/style.md b/g3doc/style.md
new file mode 100644
index 000000000..d10549fe9
--- /dev/null
+++ b/g3doc/style.md
@@ -0,0 +1,88 @@
+# Provisional style guide
+
+> These guidelines are new and may change. This note will be removed when
+> consensus is reached.
+
+Not all existing code will comply with this style guide, but new code should.
+Further, it is a goal to eventually update all existing code to be in
+compliance.
+
+## All code
+
+### Early exit
+
+All code, unless it substantially increases the line count or complexity, should
+use early exits from loops and functions where possible.
+
+## Go specific
+
+All Go code should comply with the [Go Code Review Comments][gostyle] and
+[Effective Go][effective_go] guides, as well as the additional guidelines
+described below.
+
+### Mutexes
+
+#### Naming
+
+Mutexes should be named mu or xxxMu. Mutexes as a general rule should not be
+exported. Instead, export methods which use the mutexes to avoid leaky
+abstractions.
+
+#### Location
+
+Mutexes should be sibling fields to the fields that they protect. Mutexes should
+not be declared as global variables, instead use a struct (anonymous ok, but
+naming conventions still apply).
+
+Mutexes should be ordered before the fields that they protect.
+
+#### Comments
+
+Mutexes should have a comment on their declaration explaining any ordering
+requirements (or pointing to where this information can be found), if
+applicable. There is no need for a comment explaining which fields are
+protected.
+
+Each field or variable protected by a mutex should state as such in a comment on
+the field or variable declaration.
+
+### Unused returns
+
+Unused returns should be explicitly ignored with underscores. If there is a
+function which is commonly used without using its return(s), a wrapper function
+should be declared which explicitly ignores the returns. That said, in many
+cases, it may make sense for the wrapper to check the returns.
+
+### Formatting verbs
+
+Built-in types should use their associated verbs (e.g. %d for integral types),
+but other types should use a %v variant, even if they implement fmt.Stringer.
+The built-in `error` type should use %w when formatted with `fmt.Errorf`, but
+only then.
+
+### Wrapping
+
+Comments should be wrapped at 80 columns with a 2 space tab size.
+
+Code does not need to be wrapped, but if wrapping would make it more readable,
+it should be wrapped with each subcomponent of the thing being wrapped on its
+own line. For example, if a struct is split between lines, each field should be
+on its own line.
+
+#### Example
+
+```go
+_ = exec.Cmd{
+ Path: "/foo/bar",
+ Args: []string{"-baz"},
+}
+```
+
+## C++ specific
+
+C++ code should conform to the [Google C++ Style Guide][cppstyle] and the
+guidelines described for tests.
+
+[cppstyle]: https://google.github.io/styleguide/cppguide.html
+[gostyle]: https://github.com/golang/go/wiki/CodeReviewComments
+[effective_go]: https://golang.org/doc/effective_go.html
diff --git a/g3doc/user_guide/BUILD b/g3doc/user_guide/BUILD
index 5568e1ba4..b69aee12c 100644
--- a/g3doc/user_guide/BUILD
+++ b/g3doc/user_guide/BUILD
@@ -33,7 +33,7 @@ doc(
name = "FAQ",
src = "FAQ.md",
category = "User Guide",
- permalink = "/docs/user_guide/FAQ/",
+ permalink = "/docs/user_guide/faq/",
weight = "90",
)
diff --git a/g3doc/user_guide/containerd/BUILD b/g3doc/user_guide/containerd/BUILD
new file mode 100644
index 000000000..979d46105
--- /dev/null
+++ b/g3doc/user_guide/containerd/BUILD
@@ -0,0 +1,33 @@
+load("//website:defs.bzl", "doc")
+
+package(
+ default_visibility = ["//website:__pkg__"],
+ licenses = ["notice"],
+)
+
+doc(
+ name = "quick_start",
+ src = "quick_start.md",
+ category = "User Guide",
+ permalink = "/docs/user_guide/containerd/quick_start/",
+ subcategory = "Containerd",
+ weight = "10",
+)
+
+doc(
+ name = "configuration",
+ src = "configuration.md",
+ category = "User Guide",
+ permalink = "/docs/user_guide/containerd/configuration/",
+ subcategory = "Containerd",
+ weight = "90",
+)
+
+doc(
+ name = "containerd_11",
+ src = "containerd_11.md",
+ category = "User Guide",
+ permalink = "/docs/user_guide/containerd/containerd_11/",
+ subcategory = "Containerd",
+ weight = "99",
+)
diff --git a/g3doc/user_guide/containerd/configuration.md b/g3doc/user_guide/containerd/configuration.md
new file mode 100644
index 000000000..5d485c24b
--- /dev/null
+++ b/g3doc/user_guide/containerd/configuration.md
@@ -0,0 +1,70 @@
+# Containerd Advanced Configuration
+
+This document describes how to configure runtime options for
+`containerd-shim-runsc-v1`. This follows the
+[Containerd Quick Start](./quick_start.md) and requires containerd 1.2 or later.
+
+### Update `/etc/containerd/config.toml` to point to a configuration file for `containerd-shim-runsc-v1`.
+
+`containerd-shim-runsc-v1` supports a few different configuration options based
+on the version of containerd that is used. For versions >= 1.3, it supports a
+configurable `ConfigPath` in the containerd runtime configuration.
+
+```shell
+cat <<EOF | sudo tee /etc/containerd/config.toml
+disabled_plugins = ["restart"]
+[plugins.linux]
+ shim_debug = true
+[plugins.cri.containerd.runtimes.runsc]
+ runtime_type = "io.containerd.runsc.v1"
+[plugins.cri.containerd.runtimes.runsc.options]
+ TypeUrl = "io.containerd.runsc.v1.options"
+ # containerd 1.3 only!
+ ConfigPath = "/etc/containerd/runsc.toml"
+EOF
+```
+
+When you are done restart containerd to pick up the new configuration files.
+
+```shell
+sudo systemctl restart containerd
+```
+
+### Configure `/etc/containerd/runsc.toml`
+
+> Note: For containerd 1.2, the config file should named `config.toml` and
+> located in the runtime root. By default, this is `/run/containerd/runsc`.
+
+The set of options that can be configured can be found in
+[options.go](https://github.com/google/gvisor/blob/master/pkg/shim/v2/options/options.go).
+
+#### Example: Enable the KVM platform
+
+gVisor enables the use of a number of platforms. This example shows how to
+configure `containerd-shim-runsc-v1` to use gvisor with the KVM platform.
+
+Find out more about platform in the
+[Platforms Guide](../../architecture_guide/platforms.md).
+
+```shell
+cat <<EOF | sudo tee /etc/containerd/runsc.toml
+[runsc_config]
+platform = "kvm"
+EOF
+```
+
+### Example: Enable gVisor debug logging
+
+gVisor debug logging can be enabled by setting the `debug` and `debug-log` flag.
+The shim will replace "%ID%" with the container ID, and "%COMMAND%" with the
+runsc command (run, boot, etc.) in the path of the `debug-log` flag.
+
+Find out more about debugging in the [debugging guide](../debugging.md).
+
+```shell
+cat <<EOF | sudo tee /etc/containerd/runsc.toml
+[runsc_config]
+ debug=true
+ debug-log=/var/log/%ID%/gvisor.%COMMAND%.log
+EOF
+```
diff --git a/g3doc/user_guide/containerd/containerd_11.md b/g3doc/user_guide/containerd/containerd_11.md
new file mode 100644
index 000000000..50befbdf4
--- /dev/null
+++ b/g3doc/user_guide/containerd/containerd_11.md
@@ -0,0 +1,163 @@
+# Older Versions (containerd 1.1)
+
+This document describes how to install and run the `gvisor-containerd-shim`
+using the untrusted workload CRI extension. This requires `containerd` 1.1 or
+later.
+
+*Note: The untrusted workload CRI extension is deprecated by containerd and
+`gvisor-containerd-shim` is maintained on a best-effort basis. If you are using
+containerd 1.2+, please see the
+[containerd 1.2+ documentation](./quick_start.md) and use
+`containerd-shim-runsc-v1`.*
+
+## Requirements
+
+- **runsc** and **gvisor-containerd-shim**: See the
+ [installation guide](/docs/user_guide/install/).
+- **containerd**: See the [containerd website](https://containerd.io/) for
+ information on how to install containerd.
+
+## Configure containerd
+
+Create the configuration for the gvisor shim in
+`/etc/containerd/gvisor-containerd-shim.toml`:
+
+```shell
+cat <<EOF | sudo tee /etc/containerd/gvisor-containerd-shim.toml
+# This is the path to the default runc containerd-shim.
+runc_shim = "/usr/local/bin/containerd-shim"
+EOF
+```
+
+Update `/etc/containerd/config.toml`. Be sure to update the path to
+`gvisor-containerd-shim` and `runsc` if necessary:
+
+```shell
+cat <<EOF | sudo tee /etc/containerd/config.toml
+disabled_plugins = ["restart"]
+[plugins.linux]
+ shim = "/usr/local/bin/gvisor-containerd-shim"
+ shim_debug = true
+[plugins.cri.containerd.untrusted_workload_runtime]
+ runtime_type = "io.containerd.runtime.v1.linux"
+ runtime_engine = "/usr/local/bin/runsc"
+ runtime_root = "/run/containerd/runsc"
+EOF
+```
+
+Restart `containerd`:
+
+```shell
+sudo systemctl restart containerd
+```
+
+## Usage
+
+You can run containers in gVisor via containerd's CRI.
+
+### Install crictl
+
+Download and install the `crictl` binary:
+
+```shell
+{
+wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.13.0/crictl-v1.13.0-linux-amd64.tar.gz
+tar xf crictl-v1.13.0-linux-amd64.tar.gz
+sudo mv crictl /usr/local/bin
+}
+```
+
+Write the `crictl` configuration file:
+
+```shell
+cat <<EOF | sudo tee /etc/crictl.yaml
+runtime-endpoint: unix:///run/containerd/containerd.sock
+EOF
+```
+
+### Create the nginx Sandbox in gVisor
+
+Pull the nginx image:
+
+```shell
+sudo crictl pull nginx
+```
+
+Create the sandbox creation request:
+
+```shell
+cat <<EOF | tee sandbox.json
+{
+ "metadata": {
+ "name": "nginx-sandbox",
+ "namespace": "default",
+ "attempt": 1,
+ "uid": "hdishd83djaidwnduwk28bcsb"
+ },
+ "annotations": {
+ "io.kubernetes.cri.untrusted-workload": "true"
+ },
+ "linux": {
+ },
+ "log_directory": "/tmp"
+}
+EOF
+```
+
+Create the pod in gVisor:
+
+```shell
+SANDBOX_ID=$(sudo crictl runp sandbox.json)
+```
+
+### Run the nginx Container in the Sandbox
+
+Create the nginx container creation request:
+
+```shell
+cat <<EOF | tee container.json
+{
+ "metadata": {
+ "name": "nginx"
+ },
+ "image":{
+ "image": "nginx"
+ },
+ "log_path":"nginx.0.log",
+ "linux": {
+ }
+}
+EOF
+```
+
+Create the nginx container:
+
+```shell
+CONTAINER_ID=$(sudo crictl create ${SANDBOX_ID} container.json sandbox.json)
+```
+
+Start the nginx container:
+
+```shell
+sudo crictl start ${CONTAINER_ID}
+```
+
+### Validate the container
+
+Inspect the created pod:
+
+```shell
+sudo crictl inspectp ${SANDBOX_ID}
+```
+
+Inspect the nginx container:
+
+```shell
+sudo crictl inspect ${CONTAINER_ID}
+```
+
+Verify that nginx is running in gVisor:
+
+```shell
+sudo crictl exec ${CONTAINER_ID} dmesg | grep -i gvisor
+```
diff --git a/g3doc/user_guide/containerd/quick_start.md b/g3doc/user_guide/containerd/quick_start.md
new file mode 100644
index 000000000..2f67eecb3
--- /dev/null
+++ b/g3doc/user_guide/containerd/quick_start.md
@@ -0,0 +1,176 @@
+# Containerd Quick Start
+
+This document describes how to install and configure `containerd-shim-runsc-v1`
+using the containerd runtime handler support on `containerd` 1.2 or later.
+
+## Requirements
+
+- **runsc** and **containerd-shim-runsc-v1**: See the
+ [installation guide](/docs/user_guide/install/).
+- **containerd**: See the [containerd website](https://containerd.io/) for
+ information on how to install containerd.
+
+## Configure containerd
+
+Update `/etc/containerd/config.toml`. Make sure `containerd-shim-runsc-v1` is in
+`${PATH}` or in the same directory as `containerd` binary.
+
+```shell
+cat <<EOF | sudo tee /etc/containerd/config.toml
+disabled_plugins = ["restart"]
+[plugins.linux]
+ shim_debug = true
+[plugins.cri.containerd.runtimes.runsc]
+ runtime_type = "io.containerd.runsc.v1"
+EOF
+```
+
+Restart `containerd`:
+
+```shell
+sudo systemctl restart containerd
+```
+
+## Usage
+
+You can run containers in gVisor via containerd's CRI.
+
+### Install crictl
+
+Download and install the `crictl`` binary:
+
+```shell
+{
+wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.13.0/crictl-v1.13.0-linux-amd64.tar.gz
+tar xf crictl-v1.13.0-linux-amd64.tar.gz
+sudo mv crictl /usr/local/bin
+}
+```
+
+Write the `crictl` configuration file:
+
+```shell
+cat <<EOF | sudo tee /etc/crictl.yaml
+runtime-endpoint: unix:///run/containerd/containerd.sock
+EOF
+```
+
+### Create the nginx sandbox in gVisor
+
+Pull the nginx image:
+
+```shell
+sudo crictl pull nginx
+```
+
+Create the sandbox creation request:
+
+```shell
+cat <<EOF | tee sandbox.json
+{
+ "metadata": {
+ "name": "nginx-sandbox",
+ "namespace": "default",
+ "attempt": 1,
+ "uid": "hdishd83djaidwnduwk28bcsb"
+ },
+ "linux": {
+ },
+ "log_directory": "/tmp"
+}
+EOF
+```
+
+Create the pod in gVisor:
+
+```shell
+SANDBOX_ID=$(sudo crictl runp --runtime runsc sandbox.json)
+```
+
+### Run the nginx container in the sandbox
+
+Create the nginx container creation request:
+
+```shell
+cat <<EOF | tee container.json
+{
+ "metadata": {
+ "name": "nginx"
+ },
+ "image":{
+ "image": "nginx"
+ },
+ "log_path":"nginx.0.log",
+ "linux": {
+ }
+}
+EOF
+```
+
+Create the nginx container:
+
+```shell
+CONTAINER_ID=$(sudo crictl create ${SANDBOX_ID} container.json sandbox.json)
+```
+
+Start the nginx container:
+
+```shell
+sudo crictl start ${CONTAINER_ID}
+```
+
+### Validate the container
+
+Inspect the created pod:
+
+```shell
+sudo crictl inspectp ${SANDBOX_ID}
+```
+
+Inspect the nginx container:
+
+```shell
+sudo crictl inspect ${CONTAINER_ID}
+```
+
+Verify that nginx is running in gVisor:
+
+```shell
+sudo crictl exec ${CONTAINER_ID} dmesg | grep -i gvisor
+```
+
+### Set up the Kubernetes RuntimeClass
+
+Install the RuntimeClass for gVisor:
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: node.k8s.io/v1beta1
+kind: RuntimeClass
+metadata:
+ name: gvisor
+handler: runsc
+EOF
+```
+
+Create a Pod with the gVisor RuntimeClass:
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx-gvisor
+spec:
+ runtimeClassName: gvisor
+ containers:
+ - name: nginx
+ image: nginx
+EOF
+```
+
+Verify that the Pod is running:
+
+```shell
+kubectl get pod nginx-gvisor -o wide
+```
diff --git a/g3doc/user_guide/debugging.md b/g3doc/user_guide/debugging.md
index 0525fd5c0..54fdce34f 100644
--- a/g3doc/user_guide/debugging.md
+++ b/g3doc/user_guide/debugging.md
@@ -129,3 +129,13 @@ go tool pprof -top /usr/local/bin/runsc /tmp/cpu.prof
```
[pprof]: https://github.com/google/pprof/blob/master/doc/README.md
+
+### Docker Proxy
+
+When forwarding a port to the container, Docker will likely route traffic
+through the [docker-proxy][]. This proxy may make profiling noisy, so it can be
+helpful to bypass it. Do so by sending traffic directly to the container IP and
+port. e.g., if the `docker0` IP is `192.168.9.1`, the container IP is likely a
+subsequent IP, such as `192.168.9.2`.
+
+[docker-proxy]: https://windsock.io/the-docker-proxy/
diff --git a/g3doc/user_guide/quick_start/kubernetes.md b/g3doc/user_guide/quick_start/kubernetes.md
index f875d8002..395cd4b71 100644
--- a/g3doc/user_guide/quick_start/kubernetes.md
+++ b/g3doc/user_guide/quick_start/kubernetes.md
@@ -6,17 +6,15 @@ with Kubernetes.
## Using Minikube
gVisor can run sandboxed containers in a Kubernetes cluster with Minikube. After
-the gVisor addon is enabled, pods with `io.kubernetes.cri.untrusted-workload`
+the gVisor addon is enabled, pods with a `gvisor` [Runtime Class][runtimeclass]
set to true will execute with `runsc`. Follow [these instructions][minikube] to
enable gVisor addon.
## Using Containerd
-You can also setup Kubernetes nodes to run pods in gvisor using the
-[containerd][containerd] CRI runtime and the `gvisor-containerd-shim`. You can
-use either the `io.kubernetes.cri.untrusted-workload` annotation or
-[RuntimeClass][runtimeclass] to run Pods with `runsc`. You can find instructions
-[here][gvisor-containerd-shim].
+You can also setup Kubernetes nodes to run pods in gVisor using
+[containerd][containerd] and the gVisor containerd shim. You can find
+instructions in the [Containerd Quick Start][gvisor-containerd].
## Using GKE Sandbox
@@ -31,6 +29,6 @@ WordPress site. You can view the full documentation [here][gke-sandbox-docs].
[gke]: https://cloud.google.com/kubernetes-engine/
[gke-sandbox]: https://cloud.google.com/kubernetes-engine/sandbox/
[gke-sandbox-docs]: https://cloud.google.com/kubernetes-engine/docs/how-to/sandbox-pods
-[gvisor-containerd-shim]: https://github.com/google/gvisor-containerd-shim
+[gvisor-containerd]: /docs/user_guide/containerd/quick_start/
[runtimeclass]: https://kubernetes.io/docs/concepts/containers/runtime-class/
[wordpress-quick]: /docs/tutorials/kubernetes/
diff --git a/g3doc/user_guide/quick_start/oci.md b/g3doc/user_guide/quick_start/oci.md
index 877169145..e7768946b 100644
--- a/g3doc/user_guide/quick_start/oci.md
+++ b/g3doc/user_guide/quick_start/oci.md
@@ -15,8 +15,8 @@ mkdir bundle
cd bundle
```
-Create a root file system for the container. We will use the Docker hello-world
-image as the basis for our container.
+Create a root file system for the container. We will use the Docker
+`hello-world` image as the basis for our container.
```bash
mkdir rootfs
@@ -24,12 +24,10 @@ docker export $(docker create hello-world) | tar -xf - -C rootfs
```
Next, create an specification file called `config.json` that contains our
-container specification. We will update the default command it runs to `/hello`
-in the `hello-world` container.
+container specification. We tell the container to run the `/hello` program.
```bash
-runsc spec
-sed -i 's;"sh";"/hello";' config.json
+runsc spec -- /hello
```
Finally run the container.
diff --git a/g3doc/user_guide/tutorials/BUILD b/g3doc/user_guide/tutorials/BUILD
index caae98623..405026a33 100644
--- a/g3doc/user_guide/tutorials/BUILD
+++ b/g3doc/user_guide/tutorials/BUILD
@@ -11,16 +11,7 @@ doc(
category = "User Guide",
permalink = "/docs/tutorials/docker/",
subcategory = "Tutorials",
- weight = "21",
-)
-
-doc(
- name = "cni",
- src = "cni.md",
- category = "User Guide",
- permalink = "/docs/tutorials/cni/",
- subcategory = "Tutorials",
- weight = "22",
+ weight = "10",
)
doc(
@@ -33,5 +24,14 @@ doc(
],
permalink = "/docs/tutorials/kubernetes/",
subcategory = "Tutorials",
- weight = "33",
+ weight = "20",
+)
+
+doc(
+ name = "cni",
+ src = "cni.md",
+ category = "User Guide",
+ permalink = "/docs/tutorials/cni/",
+ subcategory = "Tutorials",
+ weight = "30",
)
diff --git a/g3doc/user_guide/tutorials/cni.md b/g3doc/user_guide/tutorials/cni.md
index ad6c9fa59..ce2fd09a8 100644
--- a/g3doc/user_guide/tutorials/cni.md
+++ b/g3doc/user_guide/tutorials/cni.md
@@ -128,12 +128,14 @@ sudo mkdir -p rootfs/var/www/html
sudo sh -c 'echo "Hello World!" > rootfs/var/www/html/index.html'
```
-Next create the `config.json` specifying the network namespace. `sudo
-/usr/local/bin/runsc spec sudo sed -i 's;"sh";"python", "-m", "http.server";'
-config.json sudo sed -i "s;\"cwd\": \"/\";\"cwd\": \"/var/www/html\";"
-config.json sudo sed -i "s;\"type\": \"network\";\"type\":
-\"network\",\n\t\t\t\t\"path\": \"/var/run/netns/${CNI_CONTAINERID}\";"
-config.json`
+Next create the `config.json` specifying the network namespace.
+
+```
+sudo /usr/local/bin/runsc spec \
+ --cwd /var/www/html \
+ --netns /var/run/netns/${CNI_CONTAINERID} \
+ -- python -m http.server
+```
## Run the Container
diff --git a/g3doc/user_guide/tutorials/docker.md b/g3doc/user_guide/tutorials/docker.md
index c0a3db506..705560038 100644
--- a/g3doc/user_guide/tutorials/docker.md
+++ b/g3doc/user_guide/tutorials/docker.md
@@ -1,4 +1,4 @@
-# WorkPress with Docker
+# WordPress with Docker
This page shows you how to deploy a sample [WordPress][wordpress] site using
[Docker][docker].