diff --git a/BUILD b/BUILD index c43ce206d..962d54821 100644 --- a/BUILD +++ b/BUILD @@ -1,9 +1,48 @@ load("//tools:defs.bzl", "build_test", "gazelle", "go_path") +load("//website:defs.bzl", "doc") package(licenses = ["notice"]) exports_files(["LICENSE"]) +doc( + name = "contributing", + src = "CONTRIBUTING.md", + category = "Project", + permalink = "/contributing/", + visibility = ["//website:__pkg__"], + weight = "20", +) + +doc( + name = "security", + src = "SECURITY.md", + category = "Project", + permalink = "/security/", + visibility = ["//website:__pkg__"], + weight = "30", +) + +doc( + name = "governance", + src = "GOVERNANCE.md", + category = "Project", + permalink = "/community/governance/", + subcategory = "Community", + visibility = ["//website:__pkg__"], + weight = "91", +) + +doc( + name = "code_of_conduct", + src = "CODE_OF_CONDUCT.md", + category = "Project", + permalink = "/community/code_of_conduct/", + subcategory = "Community", + visibility = ["//website:__pkg__"], + weight = "99", +) + # The sandbox filegroup is used for sandbox-internal dependencies. package_group( name = "sandbox", diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index eb6c8edae..fbf517fe5 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -87,6 +87,5 @@ harassment or threats to anyone's safety, we may take action without notice. ## Attribution -This Code of Conduct is adapted from the Contributor Covenant, version 1.4, -available at -https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the +[Contributor Covenant, version 1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 423cf7a34..3f8f4c985 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,8 +39,8 @@ Dependencies can be added by using `go mod get`. In order to keep the All Go code should conform to the [Go style guidelines][gostyle]. C++ code should conform to the [Google C++ Style Guide][cppstyle] and the guidelines -described for [tests][teststyle]. Note that code may be automatically formatted -per the guidelines when merged. +described for tests. Note that code may be automatically formatted per the +guidelines when merged. As a secure runtime, we need to maintain the safety of all of code included in gVisor. The following rules help mitigate issues. @@ -131,4 +131,3 @@ one above, the [github]: https://github.com/google/gvisor/compare [gvisor-dev-list]: https://groups.google.com/forum/#!forum/gvisor-dev [gostyle]: https://github.com/golang/go/wiki/CodeReviewComments -[teststyle]: ./test/ diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 000000000..40846bc2f --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,113 @@ +# Governance + +## Projects + +A *project* is the primary unit of collaboration. Each project may have its own +repository and contribution process. + +All projects are covered by the [Code of Conduct](CODE_OF_CONDUCT.md), and +should include an up-to-date copy in the project repository or a link here. + +## Contributors + +Anyone can be a *contributor* to a project, provided they have signed relevant +Contributor License Agreements (CLAs) and follow the project's contribution +guidelines. Contributions will be reviewed by a maintainer, and must pass all +applicable tests. + +Reviews check for code quality and style, including documentation, and enforce +other policies. Contributions may be rejected for reasons unrelated to the code +in question. For example, a change may be too complex to maintain or duplicate +existing functionality. + +Note that contributions are not limited to code alone. Bugs, documentation, +experience reports or public advocacy are all valuable ways to contribute to a +project and build trust in the community. + +## Maintainers + +Each project has one or more *maintainers*. Maintainers set technical direction, +facilitate contributions and exercise overall stewardship. + +Maintainers have write access to the project repository. Maintainers review and +approve changes. They can also assign issues and add additional reviewers. + +Note that some repositories may not allow direct commit access, which is +reserved for administrators or automated processes. In this case, maintainers +have approval rights, and a separate process exists for merging a change. + +Maintainers are responsible for upholding the code of conduct in interactions +via project communication channels. If comments or exchanges are in violation, +they may remove them at their discretion. + +### Repositories requiring synchronization + +For some projects initiated by Google, the infrastructure which synchronizes and +merges internal and external changes requires that merges are performed by a +Google employee. In such cases, Google will initiate a rotation to merge changes +once they pass tests and are approved by a maintainer. This does not preclude +non-Google contributors from becoming maintainers, in which case the maintainer +holds approval rights and the merge is an automated process. In some cases, +Google-internal tests may fail and have to be fixed: the Google employee will +work with the submitter to achieve this. + +### Becoming a maintainer + +The list of maintainers is defined by the list of people with commit access or +approval authority on a repository, typically via a Gerrit group or a GitHub +team. + +Existing maintainers may elevate a contributor to maintainer status on evidence +of previous contributions and established trust. This decision is based on lazy +consensus from existing maintainers. While contributors may ask maintainers to +make this decision, existing maintainers will also pro-actively identify +contributors who have demonstrated a sustained track record of technical +leadership and direct contributions. + +## Special Interest Groups (SIGs) + +From time-to-time, a SIG may be formed in order to solve larger, more complex +problems across one or more projects. There are many avenues for collaboration +outside a SIG, but a SIG can provide structure for collaboration on a single +topic. + +Each group will be established by a charter, and governed by the Code of +Conduct. Some resources may be provided to the group, such as mailing lists or +meeting space, and archives will be public. + +## Security disclosure + +Projects may maintain security mailing lists for vulnerability reports and +internal project audits may occasionally reveal security issues. Access to these +lists and audits will be limited to project *maintainers*; individual +maintainers should opt to participate in these lists based on need and +expertise. Once maintainers become aware of a potential security issue, they +will assess the scope and potential impact. If reported externally, maintainers +will determine a reasonable embargo period with the reporter. + +During the embargo period, the maintainers will prioritize a fix for the +security issue. They may choose to disclose the issue to additional trusted +contributors in order to facilitate a fix, subjecting them to the embargo, or +notify affected users in order to give them an advanced opportunity to mitigate +the issue. The inclusion of specific users in this disclosure is left to the +discretion of the maintainers and contributors involved, and depends on the +scale of known project use and exposure. + +Once a fix is widely available or the embargo period ends, the maintainers will +make technical details about the vulnerability and associated fixes available. + +## Mailing lists + +There are four key mailing lists that span projects. + +* [gvisor-users](mailto:gvisor-users@googlegroups.com): general purpose user + list. +* [gvisor-dev](mailto:gvisor-dev@googlegroups.com): general purpose + development list. +* [gvisor-security](mailto:gvisor-security@googlegroups.com): private security + list. Access to this list is restricted to maintainers of the core gVisor + project, subject to the security disclosure policy described above. +* [gvisor-syzkaller](mailto:gvisor-syzkaller@googlegroups.com): private + syzkaller bug tracking list. Access to this list is not limited to + maintainers, but will be granted to those who can credibly contribute to + fixes. diff --git a/Makefile b/Makefile index c56c6ed48..7f382695d 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ runsc: ## Builds the runsc binary. .PHONY: runsc smoke-test: ## Runs a simple smoke test after build runsc. - @$(MAKE) run DOCKER_RUN_OPTIONS="" ARGS="--alsologtostderr --network none --debug --TESTONLY-unsafe-nonroot=true --rootless do true" + @$(MAKE) run DOCKER_PRIVILEGED="" ARGS="--alsologtostderr --network none --debug --TESTONLY-unsafe-nonroot=true --rootless do true" .PHONY: smoke-tests unit-tests: ## Runs all unit tests in pkg runsc and tools. @@ -119,6 +119,38 @@ tests: ## Runs all local ptrace system call tests. @$(MAKE) test OPTIONS="--test_tag_filter runsc_ptrace test/syscalls/..." .PHONY: tests +## +## Website & documentation helpers. +## +## The website is built from repository documentation and wrappers, using +## using a locally-defined Docker image (see images/jekyll). The following +## variables may be set when using website-push: +## WEBSITE_IMAGE - The name of the container image. +## WEBSITE_SERVICE - The backend service. +## WEBSITE_PROJECT - The project id to use. +## WEBSITE_REGION - The region to deploy to. +## +WEBSITE_IMAGE := gcr.io/gvisordev/gvisordev +WEBSITE_SERVICE := gvisordev +WEBSITE_PROJECT := gvisordev +WEBSITE_REGION := us-central1 + +website-build: load-jekyll ## Build the site image locally. + @$(MAKE) run TARGETS="//website:website" +.PHONY: website-build + +website-server: website-build ## Run a local server for development. + @docker run -i -p 8080:8080 gvisor.dev/images/website +.PHONY: website-server + +website-push: website-build ## Push a new image and update the service. + @docker tag gvisor.dev/images/website $(WEBSITE_IMAGE) && docker push $(WEBSITE_IMAGE) +.PHONY: website-push + +website-deploy: website-push ## Deploy a new version of the website. + @gcloud run deploy $(WEBSITE_SERVICE) --platform=managed --region=$(WEBSITE_REGION) --project=$(WEBSITE_PROJECT) --image=$(WEBSITE_IMAGE) +.PHONY: website-push + ## ## Development helpers and tooling. ## diff --git a/SECURITY.md b/SECURITY.md index 154d68cb3..82cd0efb8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ the [gvisor-security mailing list][gvisor-security-list]. You should receive a prompt response, typically within 48 hours. Policies for security list access, vulnerability embargo, and vulnerability -disclosure are outlined in the [community][community] repository. +disclosure are outlined in the [governance policy](GOVERNANCE.md). [community]: https://gvisor.googlesource.com/community [gvisor-security-list]: https://groups.google.com/forum/#!forum/gvisor-security diff --git a/WORKSPACE b/WORKSPACE index ef62ca3fd..e1873e5c0 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -380,15 +380,15 @@ go_repository( go_repository( name = "org_uber_go_atomic", importpath = "go.uber.org/atomic", - version = "v1.6.0", sum = "h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=", + version = "v1.6.0", ) go_repository( name = "org_uber_go_multierr", importpath = "go.uber.org/multierr", - version = "v1.5.0", sum = "h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=", + version = "v1.5.0", ) # BigQuery Dependencies for Benchmarks diff --git a/g3doc/BUILD b/g3doc/BUILD new file mode 100644 index 000000000..24177ad06 --- /dev/null +++ b/g3doc/BUILD @@ -0,0 +1,31 @@ +load("//website:defs.bzl", "doc") + +package( + default_visibility = ["//website:__pkg__"], + licenses = ["notice"], +) + +doc( + name = "index", + src = "README.md", + category = "Project", + permalink = "/docs/", + weight = "0", +) + +doc( + name = "roadmap", + src = "roadmap.md", + category = "Project", + permalink = "/roadmap/", + weight = "10", +) + +doc( + name = "community", + src = "community.md", + category = "Project", + permalink = "/community/", + subcategory = "Community", + weight = "95", +) diff --git a/g3doc/README.md b/g3doc/README.md index 49d58cdae..7999f5d47 100644 --- a/g3doc/README.md +++ b/g3doc/README.md @@ -1,2 +1,27 @@ -The gVisor logo files are licensed under CC BY-SA 4.0 (Creative Commons -Attribution-ShareAlike 4.0 International). +# What is gVisor? + +gVisor is a user-space kernel, written in Go, that implements a substantial +portion of the [Linux system call interface][linux]. It provides an additional +layer of isolation between running applications and the host operating system. + +gVisor includes an [Open Container Initiative (OCI)][oci] runtime called `runsc` +that makes it easy to work with existing container tooling. The `runsc` runtime +integrates with Docker and Kubernetes, making it simple to run sandboxed +containers. + +gVisor takes a distinct approach to container sandboxing and makes a different +set of technical trade-offs compared to existing sandbox technologies, thus +providing new tools and ideas for the container security landscape. + +gVisor can be used with Docker, Kubernetes, or directly using `runsc`. Use the +links below to see detailed instructions for each of them: + +* [Docker](./user_guide/quick_start/docker/): The quickest and easiest way to + get started. +* [Kubernetes](./user_guide/quick_start/kubernetes/): Isolate Pods in your K8s + cluster with gVisor. +* [OCI Quick Start](./user_guide/quick_start/oci/): Expert mode. Customize + gVisor for your environment. + +[linux]: https://en.wikipedia.org/wiki/Linux_kernel_interfaces +[oci]: https://www.opencontainers.org diff --git a/g3doc/architecture_guide/BUILD b/g3doc/architecture_guide/BUILD new file mode 100644 index 000000000..72038305b --- /dev/null +++ b/g3doc/architecture_guide/BUILD @@ -0,0 +1,64 @@ +load("//website:defs.bzl", "doc") + +package( + default_visibility = ["//website:__pkg__"], + licenses = ["notice"], +) + +doc( + name = "index", + src = "README.md", + category = "Architecture Guide", + data = [ + "Layers.png", + "Layers.svg", + "Machine-Virtualization.png", + "Machine-Virtualization.svg", + "Rule-Based-Execution.png", + "Rule-Based-Execution.svg", + "Sentry-Gofer.png", + "Sentry-Gofer.svg", + ], + permalink = "/docs/architecture_guide/", + weight = "0", +) + +doc( + name = "platforms", + src = "platforms.md", + category = "Architecture Guide", + data = [ + "Sentry-Gofer.png", + "Sentry-Gofer.svg", + ], + permalink = "/docs/architecture_guide/platforms/", + weight = "40", +) + +doc( + name = "resources", + src = "resources.md", + category = "Architecture Guide", + permalink = "/docs/architecture_guide/resources/", + weight = "30", +) + +doc( + name = "security", + src = "security.md", + category = "Architecture Guide", + data = [ + "Layers.png", + "Layers.svg", + ], + permalink = "/docs/architecture_guide/security/", + weight = "10", +) + +doc( + name = "performance", + src = "performance.md", + category = "Architecture Guide", + permalink = "/docs/architecture_guide/performance/", + weight = "20", +) diff --git a/g3doc/architecture_guide/Layers.png b/g3doc/architecture_guide/Layers.png new file mode 100644 index 000000000..308c6c451 Binary files /dev/null and b/g3doc/architecture_guide/Layers.png differ diff --git a/g3doc/architecture_guide/Layers.svg b/g3doc/architecture_guide/Layers.svg new file mode 100644 index 000000000..0a366f841 --- /dev/null +++ b/g3doc/architecture_guide/Layers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/g3doc/architecture_guide/Machine-Virtualization.png b/g3doc/architecture_guide/Machine-Virtualization.png new file mode 100644 index 000000000..1ba2ed6b2 Binary files /dev/null and b/g3doc/architecture_guide/Machine-Virtualization.png differ diff --git a/g3doc/architecture_guide/Machine-Virtualization.svg b/g3doc/architecture_guide/Machine-Virtualization.svg new file mode 100644 index 000000000..5352da07b --- /dev/null +++ b/g3doc/architecture_guide/Machine-Virtualization.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/g3doc/architecture_guide/README.md b/g3doc/architecture_guide/README.md new file mode 100644 index 000000000..1364a5358 --- /dev/null +++ b/g3doc/architecture_guide/README.md @@ -0,0 +1,80 @@ +# Overview + +gVisor provides a virtualized environment in order to sandbox untrusted +containers. The system interfaces normally implemented by the host kernel are +moved into a distinct, per-sandbox user space kernel in order to minimize the +risk of an exploit. gVisor does not introduce large fixed overheads however, and +still retains a process-like model with respect to resource utilization. + +## How is this different? + +Two other approaches are commonly taken to provide stronger isolation than +native containers. + +**Machine-level virtualization**, such as [KVM][kvm] and [Xen][xen], exposes +virtualized hardware to a guest kernel via a Virtual Machine Monitor (VMM). This +virtualized hardware is generally enlightened (paravirtualized) and additional +mechanisms can be used to improve the visibility between the guest and host +(e.g. balloon drivers, paravirtualized spinlocks). Running containers in +distinct virtual machines can provide great isolation, compatibility and +performance (though nested virtualization may bring challenges in this area), +but for containers it often requires additional proxies and agents, and may +require a larger resource footprint and slower start-up times. + +![Machine-level virtualization](Machine-Virtualization.png "Machine-level virtualization") + +**Rule-based execution**, such as [seccomp][seccomp], [SELinux][selinux] and +[AppArmor][apparmor], allows the specification of a fine-grained security policy +for an application or container. These schemes typically rely on hooks +implemented inside the host kernel to enforce the rules. If the surface can be +made small enough (i.e. a sufficiently complete policy defined), then this is an +excellent way to sandbox applications and maintain native performance. However, +in practice it can be extremely difficult (if not impossible) to reliably define +a policy for arbitrary, previously unknown applications, making this approach +challenging to apply universally. + +![Rule-based execution](Rule-Based-Execution.png "Rule-based execution") + +Rule-based execution is often combined with additional layers for +defense-in-depth. + +**gVisor** provides a third isolation mechanism, distinct from those above. + +gVisor intercepts application system calls and acts as the guest kernel, without +the need for translation through virtualized hardware. gVisor may be thought of +as either a merged guest kernel and VMM, or as seccomp on steroids. This +architecture allows it to provide a flexible resource footprint (i.e. one based +on threads and memory mappings, not fixed guest physical resources) while also +lowering the fixed costs of virtualization. However, this comes at the price of +reduced application compatibility and higher per-system call overhead. + +![gVisor](Layers.png "gVisor") + +On top of this, gVisor employs rule-based execution to provide defense-in-depth +(details below). + +gVisor's approach is similar to [User Mode Linux (UML)][uml], although UML +virtualizes hardware internally and thus provides a fixed resource footprint. + +Each of the above approaches may excel in distinct scenarios. For example, +machine-level virtualization will face challenges achieving high density, while +gVisor may provide poor performance for system call heavy workloads. + +### Why Go? + +gVisor is written in [Go][golang] in order to avoid security pitfalls that can +plague kernels. With Go, there are strong types, built-in bounds checks, no +uninitialized variables, no use-after-free, no stack overflow, and a built-in +race detector. (The use of Go has its challenges too, and isn't free.) + +### What about Gofers? + + + +[apparmor]: https://wiki.ubuntu.com/AppArmor +[golang]: https://golang.org +[kvm]: https://www.linux-kvm.org +[seccomp]: https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt +[selinux]: https://selinuxproject.org +[uml]: http://user-mode-linux.sourceforge.net/ +[xen]: https://www.xenproject.org diff --git a/g3doc/architecture_guide/Rule-Based-Execution.png b/g3doc/architecture_guide/Rule-Based-Execution.png new file mode 100644 index 000000000..b42654a90 Binary files /dev/null and b/g3doc/architecture_guide/Rule-Based-Execution.png differ diff --git a/g3doc/architecture_guide/Rule-Based-Execution.svg b/g3doc/architecture_guide/Rule-Based-Execution.svg new file mode 100644 index 000000000..bd6717043 --- /dev/null +++ b/g3doc/architecture_guide/Rule-Based-Execution.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/g3doc/architecture_guide/Sentry-Gofer.png b/g3doc/architecture_guide/Sentry-Gofer.png new file mode 100644 index 000000000..ca2c27ef7 Binary files /dev/null and b/g3doc/architecture_guide/Sentry-Gofer.png differ diff --git a/g3doc/architecture_guide/Sentry-Gofer.svg b/g3doc/architecture_guide/Sentry-Gofer.svg new file mode 100644 index 000000000..5c10750d2 --- /dev/null +++ b/g3doc/architecture_guide/Sentry-Gofer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/g3doc/architecture_guide/performance.md b/g3doc/architecture_guide/performance.md new file mode 100644 index 000000000..3862d78ee --- /dev/null +++ b/g3doc/architecture_guide/performance.md @@ -0,0 +1,274 @@ +# Performance Guide + +[TOC] + +gVisor is designed to provide a secure, virtualized environment while preserving +key benefits of containerization, such as small fixed overheads and a dynamic +resource footprint. For containerized infrastructure, this can provide a +turn-key solution for sandboxing untrusted workloads: there are no changes to +the fundamental resource model. + +gVisor imposes runtime costs over native containers. These costs come in two +forms: additional cycles and memory usage, which may manifest as increased +latency, reduced throughput or density, or not at all. In general, these costs +come from two different sources. + +First, the existence of the [Sentry](../) means that additional memory will be +required, and application system calls must traverse additional layers of +software. The design emphasizes [security](../security/) and therefore we chose +to use a language for the Sentry that provides benefits in this domain but may +not yet offer the raw performance of other choices. Costs imposed by these +design choices are **structural costs**. + +Second, as gVisor is an independent implementation of the system call surface, +many of the subsystems or specific calls are not as optimized as more mature +implementations. A good example here is the network stack, which is continuing +to evolve but does not support all the advanced recovery mechanisms offered by +other stacks and is less CPU efficient. This is an **implementation cost** and +is distinct from **structural costs**. Improvements here are ongoing and driven +by the workloads that matter to gVisor users and contributors. + +This page provides a guide for understanding baseline performance, and calls out +distint **structural costs** and **implementation costs**, highlighting where +improvements are possible and not possible. + +While we include a variety of workloads here, it’s worth emphasizing that gVisor +may not be an appropriate solution for every workload, for reasons other than +performance. For example, a sandbox may provide minimal benefit for a trusted +database, since _user data would already be inside the sandbox_ and there is no +need for an attacker to break out in the first place. + +## Methodology + +All data below was generated using the [benchmark tools][benchmark-tools] +repository, and the machines under test are uniform [Google Compute Engine][gce] +Virtual Machines (VMs) with the following specifications: + + Machine type: n1-standard-4 (broadwell) + Image: Debian GNU/Linux 9 (stretch) 4.19.0-0 + BootDisk: 2048GB SSD persistent disk + +Through this document, `runsc` is used to indicate the runtime provided by +gVisor. When relevant, we use the name `runsc-platform` to describe a specific +[platform choice](../platforms/). + +**Except where specified, all tests below are conducted with the `ptrace` +platform. The `ptrace` platform works everywhere and does not require hardware +virtualization or kernel modifications but suffers from the highest structural +costs by far. This platform is used to provide a clear understanding of the +performance model, but in no way represents an ideal scenario. In the future, +this guide will be extended to bare metal environments and include additional +platforms.** + +## Memory access + +gVisor does not introduce any additional costs with respect to raw memory +accesses. Page faults and other Operating System (OS) mechanisms are translated +through the Sentry, but once mappings are installed and available to the +application, there is no additional overhead. + +{% include graph.html id="sysbench-memory" +url="/performance/sysbench-memory.csv" title="perf.py sysbench.memory +--runtime=runc --runtime=runsc" %} + +The above figure demonstrates the memory transfer rate as measured by +`sysbench`. + +## Memory usage + +The Sentry provides an additional layer of indirection, and it requires memory +in order to store state associated with the application. This memory generally +consists of a fixed component, plus an amount that varies with the usage of +operating system resources (e.g. how many sockets or files are opened). + +For many use cases, fixed memory overheads are a primary concern. This may be +because sandboxed containers handle a low volume of requests, and it is +therefore important to achieve high densities for efficiency. + +{% include graph.html id="density" url="/performance/density.csv" title="perf.py +density --runtime=runc --runtime=runsc" log="true" y_min="100000" %} + +The above figure demonstrates these costs based on three sample applications. +This test is the result of running many instances of a container (50, or 5 in +the case of redis) and calculating available memory on the host before and +afterwards, and dividing the difference by the number of containers. This +technique is used for measuring memory usage over the `usage_in_bytes` value of +the container cgroup because we found that some container runtimes, other than +`runc` and `runsc`, do not use an individual container cgroup. + +The first application is an instance of `sleep`: a trivial application that does +nothing. The second application is a synthetic `node` application which imports +a number of modules and listens for requests. The third application is a similar +synthetic `ruby` application which does the same. Finally, we include an +instance of `redis` storing approximately 1GB of data. In all cases, the sandbox +itself is responsible for a small, mostly fixed amount of memory overhead. + +## CPU performance + +gVisor does not perform emulation or otherwise interfere with the raw execution +of CPU instructions by the application. Therefore, there is no runtime cost +imposed for CPU operations. + +{% include graph.html id="sysbench-cpu" url="/performance/sysbench-cpu.csv" +title="perf.py sysbench.cpu --runtime=runc --runtime=runsc" %} + +The above figure demonstrates the `sysbench` measurement of CPU events per +second. Events per second is based on a CPU-bound loop that calculates all prime +numbers in a specified range. We note that `runsc` does not impose a performance +penalty, as the code is executing natively in both cases. + +This has important consequences for classes of workloads that are often +CPU-bound, such as data processing or machine learning. In these cases, `runsc` +will similarly impose minimal runtime overhead. + +{% include graph.html id="tensorflow" url="/performance/tensorflow.csv" +title="perf.py tensorflow --runtime=runc --runtime=runsc" %} + +For example, the above figure shows a sample TensorFlow workload, the +[convolutional neural network example][cnn]. The time indicated includes the +full start-up and run time for the workload, which trains a model. + +## System calls + +Some **structural costs** of gVisor are heavily influenced by the +[platform choice](../platforms/), which implements system call interception. +Today, gVisor supports a variety of platforms. These platforms present distinct +performance, compatibility and security trade-offs. For example, the KVM +platform has low overhead system call interception but runs poorly with nested +virtualization. + +{% include graph.html id="syscall" url="/performance/syscall.csv" title="perf.py +syscall --runtime=runc --runtime=runsc-ptrace --runtime=runsc-kvm" y_min="100" +log="true" %} + +The above figure demonstrates the time required for a raw system call on various +platforms. The test is implemented by a custom binary which performs a large +number of system calls and calculates the average time required. + +This cost will principally impact applications that are system call bound, which +tend to be high-performance data stores and static network services. In general, +the impact of system call interception will be lower the more work an +application does. + +{% include graph.html id="redis" url="/performance/redis.csv" title="perf.py +redis --runtime=runc --runtime=runsc" %} + +For example, `redis` is an application that performs relatively little work in +userspace: in general it reads from a connected socket, reads or modifies some +data, and writes a result back to the socket. The above figure shows the results +of running [comprehensive set of benchmarks][redis-benchmark]. We can see that +small operations impose a large overhead, while larger operations, such as +`LRANGE`, where more work is done in the application, have a smaller relative +overhead. + +Some of these costs above are **structural costs**, and `redis` is likely to +remain a challenging performance scenario. However, optimizing the +[platform](../platforms/) will also have a dramatic impact. + +## Start-up time + +For many use cases, the ability to spin-up containers quickly and efficiently is +important. A sandbox may be short-lived and perform minimal user work (e.g. a +function invocation). + +{% include graph.html id="startup" url="/performance/startup.csv" title="perf.py +startup --runtime=runc --runtime=runsc" %} + +The above figure indicates how total time required to start a container through +[Docker][docker]. This benchmark uses three different applications. First, an +alpine Linux-container that executes `true`. Second, a `node` application that +loads a number of modules and binds an HTTP server. The time is measured by a +successful request to the bound port. Finally, a `ruby` application that +similarly loads a number of modules and binds an HTTP server. + +> Note: most of the time overhead above is associated Docker itself. This is +> evident with the empty `runc` benchmark. To avoid these costs with `runsc`, +> you may also consider using `runsc do` mode or invoking the +> [OCI runtime](../../user_guide/quick_start/oci/) directly. + +## Network + +Networking is mostly bound by **implementation costs**, and gVisor's network +stack is improving quickly. + +While typically not an important metric in practice for common sandbox use +cases, nevertheless `iperf` is a common microbenchmark used to measure raw +throughput. + +{% include graph.html id="iperf" url="/performance/iperf.csv" title="perf.py +iperf --runtime=runc --runtime=runsc" %} + +The above figure shows the result of an `iperf` test between two instances. For +the upload case, the specified runtime is used for the `iperf` client, and in +the download case, the specified runtime is the server. A native runtime is +always used for the other endpoint in the test. + +{% include graph.html id="applications" metric="requests_per_second" +url="/performance/applications.csv" title="perf.py http.(node|ruby) +--connections=25 --runtime=runc --runtime=runsc" %} + +The above figure shows the result of simple `node` and `ruby` web services that +render a template upon receiving a request. Because these synthetic benchmarks +do minimal work per request, must like the `redis` case, they suffer from high +overheads. In practice, the more work an application does the smaller the impact +of **structural costs** become. + +## File system + +Some aspects of file system performance are also reflective of **implementation +costs**, and an area where gVisor's implementation is improving quickly. + +In terms of raw disk I/O, gVisor does not introduce significant fundamental +overhead. For general file operations, gVisor introduces a small fixed overhead +for data that transitions across the sandbox boundary. This manifests as +**structural costs** in some cases, since these operations must be routed +through the [Gofer](../) as a result of our [security model](../security/), but +in most cases are dominated by **implementation costs**, due to an internal +[Virtual File System][vfs] (VFS) implementation that needs improvement. + +{% include graph.html id="fio-bw" url="/performance/fio.csv" title="perf.py fio +--engine=sync --runtime=runc --runtime=runsc" log="true" %} + +The above figures demonstrate the results of `fio` for reads and writes to and +from the disk. In this case, the disk quickly becomes the bottleneck and +dominates other costs. + +{% include graph.html id="fio-tmpfs-bw" url="/performance/fio-tmpfs.csv" +title="perf.py fio --engine=sync --runtime=runc --tmpfs=True --runtime=runsc" +log="true" %} + +The above figure shows the raw I/O performance of using a `tmpfs` mount which is +sandbox-internal in the case of `runsc`. Generally these operations are +similarly bound to the cost of copying around data in-memory, and we don't see +the cost of VFS operations. + +{% include graph.html id="httpd100k" metric="transfer_rate" +url="/performance/httpd100k.csv" title="perf.py http.httpd --connections=1 +--connections=5 --connections=10 --connections=25 --runtime=runc +--runtime=runsc" %} + +The high costs of VFS operations can manifest in benchmarks that execute many +such operations in the hot path for serving requests, for example. The above +figure shows the result of using gVisor to serve small pieces of static content +with predictably poor results. This workload represents `apache` serving a +single file sized 100k from the container image to a client running +[ApacheBench][ab] with varying levels of concurrency. The high overhead comes +principally from the VFS implementation that needs improvement, with several +internal serialization points (since all requests are reading the same file). +Note that some of some of network stack performance issues also impact this +benchmark. + +{% include graph.html id="ffmpeg" url="/performance/ffmpeg.csv" title="perf.py +media.ffmpeg --runtime=runc --runtime=runsc" %} + +For benchmarks that are bound by raw disk I/O and a mix of compute, file system +operations are less of an issue. The above figure shows the total time required +for an `ffmpeg` container to start, load and transcode a 27MB input video. + +[ab]: https://en.wikipedia.org/wiki/ApacheBench +[benchmark-tools]: https://github.com/google/gvisor/tree/master/benchmarks +[gce]: https://cloud.google.com/compute/ +[cnn]: https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/3_NeuralNetworks/convolutional_network.py +[docker]: https://docker.io +[redis-benchmark]: https://redis.io/topics/benchmarks +[vfs]: https://en.wikipedia.org/wiki/Virtual_file_system diff --git a/g3doc/architecture_guide/platforms.md b/g3doc/architecture_guide/platforms.md new file mode 100644 index 000000000..6e63da8ce --- /dev/null +++ b/g3doc/architecture_guide/platforms.md @@ -0,0 +1,86 @@ +# Platform Guide + +A gVisor sandbox consists of multiple processes when running. These processes +collectively comprise a shared environment in which one or more containers can +be run. + +Each sandbox has its own isolated instance of: + +* The **Sentry**, A user-space kernel that runs the container and intercepts + and responds to system calls made by the application. + +Each container running in the sandbox has its own isolated instance of: + +* A **Gofer** which provides file system access to the container. + +![gVisor architecture diagram](Sentry-Gofer.png "gVisor architecture diagram") + +## runsc + +The entrypoint to running a sandboxed container is the `runsc` executable. +`runsc` implements the [Open Container Initiative (OCI)][oci] runtime +specification. This means that OCI compatible _filesystem bundles_ can be run by +`runsc`. Filesystem bundles are comprised of a `config.json` file containing +container configuration, and a root filesystem for the container. Please see the +[OCI runtime spec][runtime-spec] 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 + +The Sentry is the largest component of gVisor. It can be thought of as a +userspace OS kernel. The Sentry implements all the kernel functionality needed +by the untrusted application. It implements all of the supported system calls, +signal delivery, memory management and page faulting logic, the threading model, +and more. + +When the untrusted application makes a system call, the currently used platform +redirects the call to the Sentry, which will do the necessary work to service +it. It is important to note that the Sentry will not simply pass through system +calls to the host kernel. As a userspace application, the Sentry will make some +host system calls to support its operation, but it will not allow the +application to directly control the system calls it makes. + +The Sentry aims to present an equivalent environment to (upstream) Linux v4.4. + +File system operations that extend beyond the sandbox (not internal /proc files, +pipes, etc) are sent to the Gofer, described below. + +## Platforms + +gVisor requires a platform to implement interception of syscalls, basic context +switching, and memory mapping functionality. + +### ptrace + +The ptrace platform uses `PTRACE_SYSEMU` to execute user code without allowing +it to execute host system calls. This platform can run anywhere that ptrace +works (even VMs without nested virtualization). + +### KVM (experimental) + +The KVM platform allows the Sentry to act as both guest OS and VMM, switching +back and forth between the two worlds seamlessly. The KVM platform can run on +bare-metal or in a VM with nested virtualization enabled. While there is no +virtualized hardware layer -- the sandbox retains a process model -- gVisor +leverages virtualization extensions available on modern processors in order to +improve isolation and performance of address space switches. + +## Gofer + +The Gofer is a normal host Linux process. The Gofer is started with each sandbox +and connected to the Sentry. The Sentry process is started in a restricted +seccomp container without access to file system resources. The Gofer provides +the Sentry access to file system resources via the 9P protocol and provides an +additional level of isolation. + +## Application + +The application (aka the untrusted 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. + +[oci]: https://www.opencontainers.org +[runtime-spec]: https://github.com/opencontainers/runtime-spec diff --git a/g3doc/architecture_guide/resources.md b/g3doc/architecture_guide/resources.md new file mode 100644 index 000000000..894f995ae --- /dev/null +++ b/g3doc/architecture_guide/resources.md @@ -0,0 +1,143 @@ +# Resource Model + +[TOC] + +The resource model for gVisor does not assume a fixed number of threads of +execution (i.e. vCPUs) or amount of physical memory. Where possible, decisions +about underlying physical resources are delegated to the host system, where +optimizations can be made with global information. This delegation allows the +sandbox to be highly dynamic in terms of resource usage: spanning a large number +of cores and large amount of memory when busy, and yielding those resources back +to the host when not. + +Some of the details here may depend on the [platform](../platforms/), but in +general this page describes the resource model used by gVisor. If you're not +familiar with the terms here, uou may want to start with the [Overview](../). + +## Processes + +Much like a Virtual Machine (VM), a gVisor sandbox appears as an opaque process +on the system. Processes within the sandbox do not manifest as processes on the +host system, and process-level interactions within the sandbox requires entering +the sandbox (e.g. via a [Docker exec][exec]). + +## Networking + +Similarly to processes, the sandbox attaches a network endpoint to the system, +but runs it's own network stack. All network resources, other than packets in +flight, exist only inside the sandbox, bound by relevant resource limits. + +You can interact with network endpoints exposed by the sandbox, just as you +would any other container, but network introspection similarly requires entering +the sandbox. + +## Files + +Files may be backed by different implementations. For host-native files (where a +file descriptor is available), the Gofer may return a file descriptor to the +Sentry via [SCM_RIGHTS][scmrights][^1]. + +These files may be read from and written to through standard system calls, and +also mapped into the associated application's address space. This allows the +same host memory to be shared across multiple sandboxes, although this mechanism +does not preclude the use of side-channels (see the +[security model](../security/)). + +Note that some file systems exist only within the context of the sandbox. For +example, in many cases a `tmpfs` mount will be available at `/tmp` or +`/dev/shm`, which allocates memory directly from the sandbox memory file (see +below). Ultimately, these will be accounted against relevant limits in a similar +way as the host native case. + +## Threads + +The Sentry models individual task threads with [goroutines][goroutine]. As a +result, each task thread is a lightweight [green thread][greenthread], and may +not correspond to an underlying host thread. + +However, application execution is modelled as a blocking system call with the +Sentry. This means that additional host threads may be created, *depending on +the number of active application threads*. In practice, a busy application will +converge on the number of active threads, and the host will be able to make +scheduling decisions about all application threads. + +## Time + +Time in the sandbox is provided by the Sentry, through its own [vDSO][vdso] and +timekeeping implementation. This is divorced from the host time, and no state is +shared with the host, although the time will be initialized with the host clock. + +The Sentry runs timers to note the passage of time, much like a kernel running +on hardware (though the timers are software timers, in this case). These timers +provide updates to the vDSO, the time returned through system calls, and the +time recorded for usage or limit tracking (e.g. [RLIMIT_CPU][rlimit]). + +When all application threads are idle, the Sentry disables timers until an event +occurs that wakes either the Sentry or an application thread, similar to a +[tickless kernel][tickless]. This allows the Sentry to achieve near zero CPU +usage for idle applications. + +## Memory + +The Sentry implements its own memory management, including demand-paging and a +Sentry internal page cache for files that cannot be used natively. A single +[memfd][memfd] backs all application memory. + +### Address spaces + +The creation of address spaces is platform-specific. For some platforms, +additional "stub" processes may be created on the host in order to support +additional address spaces. These stubs are subject to various limits applied at +the sandbox level (e.g. PID limits). + +### Physical memory + +The host is able to manage physical memory using regular means (e.g. tracking +working sets, reclaiming and swapping under pressure). The Sentry lazily +populates host mappings for applications, and allow the host to demand-page +those regions, which is critical for the functioning of those mechanisms. + +In order to avoid excessive overhead, the Sentry does not demand-page individual +pages. Instead, it selects appropriate regions based on heuristics. There is a +trade-off here: the Sentry is unable to trivially determine which pages are +active and which are not. Even if pages were individually faulted, the host may +select pages to be reclaimed or swapped without the Sentry's knowledge. + +Therefore, memory usage statistics within the sandbox (e.g. via `proc`) are +approximations. The Sentry maintains an internal breakdown of memory usage, and +can collect accurate information but only through a relatively expensive API +call. In any case, it would likely be considered unwise to share precise +information about how the host is managing memory with the sandbox. + +Finally, when an application marks a region of memory as no longer needed, for +example via a call to [madvise][madvise], the Sentry *releases this memory back +to the host*. There can be performance penalties for this, since it may be +cheaper in many cases to retain the memory and use it to satisfy some other +request. However, releasing it immediately to the host allows the host to more +effectively multiplex resources and apply an efficient global policy. + +## Limits + +All Sentry threads and Sentry memory are subject to a container cgroup. However, +application usage will not appear as anonymous memory usage, and will instead be +accounted to the `memfd`. All anonymous memory will correspond to Sentry usage, +and host memory charged to the container will work as standard. + +The cgroups can be monitored for standard signals: pressure indicators, +threshold notifiers, etc. and can also be adjusted dynamically. Note that the +Sentry itself may listen for pressure signals in its containing cgroup, in order +to purge internal caches. + +[goroutine]: https://tour.golang.org/concurrency/1 +[greenthread]: https://en.wikipedia.org/wiki/Green_threads +[scheduler]: https://morsmachine.dk/go-scheduler +[vdso]: https://en.wikipedia.org/wiki/VDSO +[rlimit]: http://man7.org/linux/man-pages/man2/getrlimit.2.html +[tickless]: https://en.wikipedia.org/wiki/Tickless_kernel +[memfd]: http://man7.org/linux/man-pages/man2/memfd_create.2.html +[scmrights]: http://man7.org/linux/man-pages/man7/unix.7.html +[madvise]: http://man7.org/linux/man-pages/man2/madvise.2.html +[exec]: https://docs.docker.com/engine/reference/commandline/exec/ +[^1]: Unless host networking is enabled, the Sentry is not able to create or + open host file descriptors itself, it can only receive them in this way + from the Gofer. diff --git a/g3doc/architecture_guide/security.md b/g3doc/architecture_guide/security.md new file mode 100644 index 000000000..f78586291 --- /dev/null +++ b/g3doc/architecture_guide/security.md @@ -0,0 +1,253 @@ +# Security Model + +[TOC] + +gVisor was created in order to provide additional defense against the +exploitation of kernel bugs by untrusted userspace code. In order to understand +how gVisor achieves this goal, it is first necessary to understand the basic +threat model. + +## Threats: The Anatomy of an Exploit + +An exploit takes advantage of a software or hardware bug in order to escalate +privileges, gain access to privileged data, or disrupt services. All of the +possible interactions that a malicious application can have with the rest of the +system (attack vectors) define the attack surface. We categorize these attack +vectors into several common classes. + +### System API + +An operating system or hypervisor exposes an abstract System API in the form of +system calls and traps. This API may be documented and stable, as with Linux, or +it may be abstracted behind a library, as with Windows (i.e. win32.dll or +ntdll.dll). The System API includes all standard interfaces that application +code uses to interact with the system. This includes high-level abstractions +that are derived from low-level system calls, such as system files, sockets and +namespaces. + +Although the System API is exposed to applications by design, bugs and race +conditions within the kernel or hypervisor may occasionally be exploitable via +the API. This is common in part due to the fact that most kernels and +hypervisors are written in [C][clang], which is well-suited to interfacing with +hardware but often prone to security issues. In order to exploit these issues, a +typical attack might involve some combination of the following: + +1. Opening or creating some combination of files, sockets or other descriptors. +1. Passing crafted, malicious arguments, structures or packets. +1. Racing with multiple threads in order to hit specific code paths. + +For example, for the [Dirty Cow][dirtycow] privilege escalation bug, an +application would open a specific file in `/proc` or use a specific `ptrace` +system call, and use multiple threads in order to trigger a race condition when +touching a fresh page of memory. The attacker then gains control over a page of +memory belonging to the system. With additional privileges or access to +privileged data in the kernel, an attacker will often be able to employ +additional techniques to gain full access to the rest of the system. + +While bugs in the implementation of the System API are readily fixed, they are +also the most common form of exploit. The exposure created by this class of +exploit is what gVisor aims to minimize and control, described in detail below. + +### System ABI + +Hardware and software exploits occasionally exist in execution paths that are +not part of an intended System API. In this case, exploits may be found as part +of implicit actions the hardware or privileged system code takes in response to +certain events, such as traps or interrupts. For example, the recent +[POPSS][popss] flaw required only native code execution (no specific system call +or file access). In that case, the Xen hypervisor was similarly vulnerable, +highlighting that hypervisors are not immune to this vector. + +### Side Channels + +Hardware side channels may be exploitable by any code running on a system: +native, sandboxed, or virtualized. However, many host-level mitigations against +hardware side channels are still effective with a sandbox. For example, kernels +built with retpoline protect against some speculative execution attacks +(Spectre) and frame poisoning may protect against L1 terminal fault (L1TF) +attacks. Hypervisors may introduce additional complications in this regard, as +there is no mitigation against an application in a normally functioning Virtual +Machine (VM) exploiting the L1TF vulnerability for another VM on the sibling +hyperthread. + +### Other Vectors + +The above categories in no way represent an exhaustive list of exploits, as we +focus only on running untrusted code from within the operating system or +hypervisor. We do not consider other ways that a more generic adversary may +interact with a system, such as inserting a portable storage device with a +malicious filesystem image, using a combination of crafted keyboard or touch +inputs, or saturating a network device with ill-formed packets. + +Furthermore, high-level systems may contain exploitable components. An attacker +need not escalate privileges within a container if there’s an exploitable +network-accessible service on the host or some other API path. *A sandbox is not +a substitute for a secure architecture*. + +## Goals: Limiting Exposure + +gVisor’s primary design goal is to minimize the System API attack vector while +still providing a process model. There are two primary security principles that +inform this design. First, the application’s direct interactions with the host +System API are intercepted by the Sentry, which implements the System API +instead. Second, the System API accessible to the Sentry itself is minimized to +a safer, restricted set. The first principle minimizes the possibility of direct +exploitation of the host System API by applications, and the second principle +minimizes indirect exploitability, which is the exploitation by an exploited or +buggy Sentry (e.g. chaining an exploit). + +The first principle is similar to the security basis for a Virtual Machine (VM). +With a VM, an application’s interactions with the host are replaced by +interactions with a guest operating system and a set of virtualized hardware +devices. These hardware devices are then implemented via the host System API by +a Virtual Machine Monitor (VMM). The Sentry similarly prevents direct +interactions by providing its own implementation of the System API that the +application must interact with. Applications are not able to to directly craft +specific arguments or flags for the host System API, or interact directly with +host primitives. + +For both the Sentry and a VMM, it’s worth noting that while direct interactions +are not possible, indirect interactions are still possible. For example, a read +on a host-backed file in the Sentry may ultimately result in a host read system +call (made by the Sentry, not by passing through arguments from the +application), similar to how a read on a block device in a VM may result in the +VMM issuing a corresponding host read system call from a backing file. + +An important distinction from a VM is that the Sentry implements a System API +based directly on host System API primitives instead of relying on virtualized +hardware and a guest operating system. This selects a distinct set of +trade-offs, largely in the performance, efficiency and compatibility domains. +Since transitions in and out of the sandbox are relatively expensive, a guest +operating system will typically take ownership of resources. For example, in the +above case, the guest operating system may read the block device data in a local +page cache, to avoid subsequent reads. This may lead to better performance but +lower efficiency, since memory may be wasted or duplicated. The Sentry opts +instead to defer to the host for many operations during runtime, for improved +efficiency but lower performance in some use cases. + +### What can a sandbox do? + +An application in a gVisor sandbox is permitted to do most things a standard +container can do: for example, applications can read and write files mapped +within the container, make network connections, etc. As described above, +gVisor's primary goal is to limit exposure to bugs and exploits while still +allowing most applications to run. Even so, gVisor will limit some operations +that might be permitted with a standard container. Even with appropriate +capabilities, a user in a gVisor sandbox will only be able to manipulate +virtualized system resources (e.g. the system time, kernel settings or +filesystem attributes) and not underlying host system resources. + +While the sandbox virtualizes many operations for the application, we limit the +sandbox's own interactions with the host to the following high-level operations: + +1. Communicate with a Gofer process via a connected socket. The sandbox may + receive new file descriptors from the Gofer process, corresponding to opened + files. These files can then be read from and written to by the sandbox. +1. Make a minimal set of host system calls. The calls do not include the + creation of new sockets (unless host networking mode is enabled) or opening + files. The calls include duplication and closing of file descriptors, + synchronization, timers and signal management. +1. Read and write packets to a virtual ethernet device. This is not required if + host networking is enabled (or networking is disabled). + +### System ABI, Side Channels and Other Vectors + +gVisor relies on the host operating system and the platform for defense against +hardware-based attacks. Given the nature of these vulnerabilities, there is +little defense that gVisor can provide (there’s no guarantee that additional +hardware measures, such as virtualization, memory encryption, etc. would +actually decrease the attack surface). Note that this is true even when using +hardware virtualization for acceleration, as the host kernel or hypervisor is +ultimately responsible for defending against attacks from within malicious +guests. + +gVisor similarly relies on the host resource mechanisms (cgroups) for defense +against resource exhaustion and denial of service attacks. Network policy +controls should be applied at the container level to ensure appropriate network +policy enforcement. Note that the sandbox itself is not capable of altering or +configuring these mechanisms, and the sandbox itself should make an attacker +less likely to exploit or override these controls through other means. + +## Principles: Defense-in-Depth + +For gVisor development, there are several engineering principles that are +employed in order to ensure that the system meets its design goals. + +1. No system call is passed through directly to the host. Every supported call + has an independent implementation in the Sentry, that is unlikely to suffer + from identical vulnerabilities that may appear in the host. This has the + consequence that all kernel features used by applications require an + implementation within the Sentry. +1. Only common, universal functionality is implemented. Some filesystems, + network devices or modules may expose specialized functionality to user + space applications via mechanisms such as extended attributes, raw sockets + or ioctls. Since the Sentry is responsible for implementing the full system + call surface, we do not implement or pass through these specialized APIs. +1. The host surface exposed to the Sentry is minimized. While the system call + surface is not trivial, it is explicitly enumerated and controlled. The + Sentry is not permitted to open new files, create new sockets or do many + other interesting things on the host. + +Additionally, we have practical restrictions that are imposed on the project to +minimize the risk of Sentry exploitability. For example: + +1. Unsafe code is carefully controlled. All unsafe code is isolated in files + that end with "unsafe.go", in order to facilitate validation and auditing. + No file without the unsafe suffix may import the unsafe package. +1. No CGo is allowed. The Sentry must be a pure Go binary. +1. External imports are not generally allowed within the core packages. Only + limited external imports are used within the setup code. The code available + inside the Sentry is carefully controlled, to ensure that the above rules + are effective. + +Finally, we recognize that security is a process, and that vigilance is +critical. Beyond our security disclosure process, the Sentry is fuzzed +continuously to identify potential bugs and races proactively, and production +crashes are recorded and triaged to similarly identify material issues. + +## FAQ + +### Is this more or less secure than a Virtual Machine? + +The security of a VM depends to a large extent on what is exposed from the host +kernel and user space support code. For example, device emulation code in the +host kernel (e.g. APIC) or optimizations (e.g. vhost) can be more complex than a +simple system call, and exploits carry the same risks. Similarly, the user space +support code is frequently unsandboxed, and exploits, while rare, may allow +unfettered access to the system. + +Some platforms leverage the same virtualization hardware as VMs in order to +provide better system call interception performance. However, gVisor does not +implement any device emulation, and instead opts to use a sandboxed host System +API directly. Both approaches significantly reduce the original attack surface. +Ultimately, since gVisor is capable of using the same hardware mechanism, one +should not assume that the mere use of virtualization hardware makes a system +more or less secure, just as it would be a mistake to make the claim that the +use of a unibody alone makes a car safe. + +### Does this stop hardware side channels? + +In general, gVisor does not provide protection against hardware side channels, +although it may make exploits that rely on direct access to the host System API +more difficult to use. To minimize exposure, you should follow relevant guidance +from vendors and keep your host kernel and firmware up-to-date. + +### Is this just a ptrace sandbox? + +No: the term “ptrace sandbox” generally refers to software that uses the Linux +ptrace facility to inspect and authorize system calls made by applications, +enforcing a specific policy. These commonly suffer from two issues. First, +vulnerable system calls may be authorized by the sandbox, as the application +still has direct access to some System API. Second, it’s impossible to avoid +time-of-check, time-of-use race conditions without disabling multi-threading. + +In gVisor, the platforms that use ptrace operate differently. The stubs that are +traced are never allowed to continue execution into the host kernel and complete +a call directly. Instead, all system calls are interpreted and handled by the +Sentry itself, who reflects resulting register state back into the tracee before +continuing execution in user space. This is very similar to the mechanism used +by User-Mode Linux (UML). + +[dirtycow]: https://en.wikipedia.org/wiki/Dirty_COW +[clang]: https://en.wikipedia.org/wiki/C_(programming_language) +[popss]: https://nvd.nist.gov/vuln/detail/CVE-2018-8897 diff --git a/g3doc/community.md b/g3doc/community.md new file mode 100644 index 000000000..76f4d87c3 --- /dev/null +++ b/g3doc/community.md @@ -0,0 +1,31 @@ +# Participation + +To contribute code, please read the [contributing guide](../CONTRIBUTING.md). + +Please note that the [Code of Conduct](../CODE_OF_CONDUCT.md) applies to +community forums as well as technical participation. + +## Communication channels + +The project maintains two mailing lists: + +* [gvisor-users][gvisor-users] for accouncements and general discussion. +* [gvisor-dev][gvisor-dev] for development and contribution. + +We also have a [chat room hosted on Gitter][gitter-chat]. + +We'd love to hear from you! + +## Community meetings + +The community calendar shows upcoming public meetings and opportunities to +collaborate or discuss the project. Meetings are planned and announced ahead of +time via the [gvisor-users][gvisor-users] mailing list. + +These meetings are public: anyone can join. + + + +[gitter-chat]: https://gitter.im/gvisor/community +[gvisor-dev]: https://groups.google.com/forum/#!forum/gvisor-dev +[gvisor-users]: https://groups.google.com/forum/#!forum/gvisor-users diff --git a/g3doc/logo.txt b/g3doc/logo.txt new file mode 100644 index 000000000..92f9cad5f --- /dev/null +++ b/g3doc/logo.txt @@ -0,0 +1 @@ +The gVisor logo files are licensed under CC BY-SA 4.0 (Creative Commons Attribution-ShareAlike 4.0 International). diff --git a/g3doc/roadmap.md b/g3doc/roadmap.md new file mode 100644 index 000000000..06ea25a8b --- /dev/null +++ b/g3doc/roadmap.md @@ -0,0 +1,49 @@ +# Roadmap + +gVisor [GitHub Issues][issues] serve as the source-of-truth for most work in +flight. Specific performance and compatibility issues are generally tracked +there. [GitHub Milestones][milestones] may be used to track larger features that +span many issues. However, labels are also used to aggregate cross-cutting +feature work. + +## Core Improvements + +Most gVisor work is focused on four areas. + +* [Performance][performance]: overall sandbox performance, including platform + performance, is a critical area for investment. This includes: network + performance (throughput and latency), file system performance (metadata and + data I/O), application switch and fault costs, etc. The goal of gVisor is to + provide sandboxing without a material performance or efficiency impact on + all but the most performance-sensitive applications. + +* [Compatibility][compatibility]: supporting a wide range of applications + requires supporting a large system API, including special system files (e.g. + proc, sys, dev, etc.). The goal of gVisor is to support the broad set of + applications that depend on a generic Linux API, rather than a specific + kernel version. + +* [Infrastructure & tooling][infrastructure]: the above goals require + aggressive testing and coverage, and well-established processes. This + includes adding appropriate system call coverage, end-to-end suites and + runtime tests. + +* [Integration][integration]: Container infrastructure is evolving rapidly and + becoming more complex, and gVisor must continuously implement relevant and + popular features to ensure that integration points remain robust and + feature-complete while preserving security guarantees. + +## Releases + +Releases are available on [GitHub][releases]. + +As a convenience, binary packages are also published. Instructions for their use +are available via the [Installation instructions](./user_guide/install.md). + +[issues]: https://github.com/google/gvisor/issues +[milestones]: https://github.com/google/gvisor/milestones +[releases]: https://github.com/google/gvisor/releases +[performance]: https://github.com/google/gvisor/issues?q=is%3Aopen+is%3Aissue+label%3A%22area%3A+performance%22 +[integration]: https://github.com/google/gvisor/issues?q=is%3Aopen+is%3Aissue+label%3A%22area%3A+integration%22 +[compatibility]: https://github.com/google/gvisor/issues?q=is%3Aopen+is%3Aissue+label%3A%22area%3A+compatibility%22 +[infrastructure]: https://github.com/google/gvisor/issues?q=is%3Aopen+is%3Aissue+label%3A%22area%3A+tooling%22 diff --git a/g3doc/user_guide/BUILD b/g3doc/user_guide/BUILD new file mode 100644 index 000000000..5568e1ba4 --- /dev/null +++ b/g3doc/user_guide/BUILD @@ -0,0 +1,70 @@ +load("//website:defs.bzl", "doc") + +package( + default_visibility = ["//website:__pkg__"], + licenses = ["notice"], +) + +doc( + name = "compatibility", + src = "compatibility.md", + category = "Compatibility", + permalink = "/docs/user_guide/compatibility/", + weight = "0", +) + +doc( + name = "checkpoint_restore", + src = "checkpoint_restore.md", + category = "User Guide", + permalink = "/docs/user_guide/checkpoint_restore/", + weight = "60", +) + +doc( + name = "debugging", + src = "debugging.md", + category = "User Guide", + permalink = "/docs/user_guide/debugging/", + weight = "70", +) + +doc( + name = "FAQ", + src = "FAQ.md", + category = "User Guide", + permalink = "/docs/user_guide/FAQ/", + weight = "90", +) + +doc( + name = "filesystem", + src = "filesystem.md", + category = "User Guide", + permalink = "/docs/user_guide/filesystem/", + weight = "40", +) + +doc( + name = "networking", + src = "networking.md", + category = "User Guide", + permalink = "/docs/user_guide/networking/", + weight = "50", +) + +doc( + name = "install", + src = "install.md", + category = "User Guide", + permalink = "/docs/user_guide/install/", + weight = "10", +) + +doc( + name = "platforms", + src = "platforms.md", + category = "User Guide", + permalink = "/docs/user_guide/platforms/", + weight = "30", +) diff --git a/g3doc/user_guide/FAQ.md b/g3doc/user_guide/FAQ.md new file mode 100644 index 000000000..89df65e99 --- /dev/null +++ b/g3doc/user_guide/FAQ.md @@ -0,0 +1,122 @@ +# FAQ + +[TOC] + +### What operating systems are supported? {#supported-os} + +Today, gVisor requires Linux. + +### What CPU architectures are supported? {#supported-cpus} + +gVisor currently supports [x86_64/AMD64](https://en.wikipedia.org/wiki/X86-64) +compatible processors. Preliminary support is also available for +[ARM64](https://en.wikipedia.org/wiki/ARM_architecture#AArch64). + +### Do I need to modify my Linux application to use gVisor? {#modify-app} + +No. gVisor is capable of running unmodified Linux binaries. + +### What binary formats does gVisor support? {#supported-binaries} + +gVisor supports Linux +[ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) binaries. + +Binaries run in gVisor should be built for the +[AMD64](https://en.wikipedia.org/wiki/X86-64) or +[AArch64](https://en.wikipedia.org/wiki/ARM_architecture#AArch64) CPU +architectures. + +### Can I run Docker images using gVisor? {#docker-images} + +Yes. Please see the [Docker Quick Start][docker]. + +### Can I run Kubernetes pods using gVisor? {#k8s-pods} + +Yes. Please see the [Kubernetes Quick Start][k8s]. + +### What's the security model? {#security-model} + +See the [Security Model][security-model]. + +## Troubleshooting + +### My container runs fine with `runc` but fails with `runsc` {#app-compatibility} + +If you’re having problems running a container with `runsc` it’s most likely due +to a compatibility issue or a missing feature in gVisor. See +[Debugging][debugging]. + +### When I run my container, docker fails with: `open /run/containerd/...//log.json: no such file or directory` {#memfd-create} + +You are using an older version of Linux which doesn't support `memfd_create`. + +This is tracked in [bug #268](https://gvisor.dev/issue/268). + +### When I run my container, docker fails with: `flag provided but not defined: -console` {#old-docker} + +You're using an old version of Docker. See [Docker Quick Start][docker]. + +### I can’t see a file copied with: `docker cp` {#fs-cache} + +For performance reasons, gVisor caches directory contents, and therefore it may +not realize a new file was copied to a given directory. To invalidate the cache +and force a refresh, create a file under the directory in question and list the +contents again. + +As a workaround, shared root filesystem can be enabled. See +[Filesystem][filesystem]. + +This bug is tracked in [bug #4](https://gvisor.dev/issue/4). + +Note that `kubectl cp` works because it does the copy by exec'ing inside the +sandbox, and thus gVisor's internal cache is made aware of the new files and +directories. + +### I'm getting an error like: `panic: unable to attach: operation not permitted` or `fork/exec /proc/self/exe: invalid argument: unknown` {#runsc-perms} + +Make sure that permissions and the owner is correct on the `runsc` binary. + +```bash +sudo chown root:root /usr/local/bin/runsc +sudo chmod 0755 /usr/local/bin/runsc +``` + +### I'm getting an error like `mount submount "/etc/hostname": creating mount with source ".../hostname": input/output error: unknown.` {#memlock} + +There is a bug in Linux kernel versions 5.1 to 5.3.15, 5.4.2, and 5.5. Upgrade +to a newer kernel or add the following to +`/lib/systemd/system/containerd.service` as a workaround. + +``` +LimitMEMLOCK=infinity +``` + +And run `systemctl daemon-reload && systemctl restart containerd` to restart +containerd. + +See [issue #1765](https://gvisor.dev/issue/1765) for more details. + +### My container cannot resolve another container's name when using Docker user defined bridge {#docker-bridge} + +This is normally indicated by errors like `bad address 'container-name'` when +trying to communicate to another container in the same network. + +Docker user defined bridge uses an embedded DNS server bound to the loopback +interface on address 127.0.0.10. This requires access to the host network in +order to communicate to the DNS server. runsc network is isolated from the host +and cannot access the DNS server on the host network without breaking the +sandbox isolation. There are a few different workarounds you can try: + +* Use default bridge network with `--link` to connect containers. Default + bridge doesn't use embedded DNS. +* Use [`--network=host`][host-net] option in runsc, however beware that it + will use the host network stack and is less secure. +* Use IPs instead of container names. +* Use [Kubernetes][k8s]. Container name lookup works fine in Kubernetes. + +[security-model]: /docs/architecture_guide/security/ +[host-net]: /docs/user_guide/networking/#network-passthrough +[debugging]: /docs/user_guide/debugging/ +[filesystem]: /docs/user_guide/filesystem/ +[docker]: /docs/user_guide/quick_start/docker/ +[k8s]: /docs/user_guide/quick_start/kubernetes/ diff --git a/g3doc/user_guide/checkpoint_restore.md b/g3doc/user_guide/checkpoint_restore.md new file mode 100644 index 000000000..0ab0911b0 --- /dev/null +++ b/g3doc/user_guide/checkpoint_restore.md @@ -0,0 +1,101 @@ +# Checkpoint/Restore + +[TOC] + +gVisor has the ability to checkpoint a process, save its current state in a +state file, and restore into a new container using the state file. + +## How to use checkpoint/restore + +Checkpoint/restore functionality is currently available via raw `runsc` +commands. To use the checkpoint command, first run a container. + +```bash +runsc run +``` + +To checkpoint the container, the `--image-path` flag must be provided. This is +the directory path within which the checkpoint state-file will be created. The +file will be called `checkpoint.img` and necessary directories will be created +if they do not yet exist. + +> Note: Two checkpoints cannot be saved to the same directory; every image-path +> provided must be unique. + +```bash +runsc checkpoint --image-path= +``` + +There is also an optional `--leave-running` flag that allows the container to +continue to run after the checkpoint has been made. (By default, containers stop +their processes after committing a checkpoint.) + +> Note: All top-level runsc flags needed when calling run must be provided to +> checkpoint if --leave-running is used. + +> Note: --leave-running functions by causing an immediate restore so the +> container, although will maintain its given container id, may have a different +> process id. + +```bash +runsc checkpoint --image-path= --leave-running +``` + +To restore, provide the image path to the `checkpoint.img` file created during +the checkpoint. Because containers stop by default after checkpointing, restore +needs to happen in a new container (restore is a command which parallels start). + +```bash +runsc create + +runsc restore --image-path= +``` + +## How to use checkpoint/restore in Docker: + +Currently checkpoint/restore through `runsc` is not entirely compatible with +Docker, although there has been progress made from both gVisor and Docker to +enable compatibility. Here, we document the ideal workflow. + +Run a container: + +```bash +docker run [options] --runtime=runsc ` +``` + +Checkpoint a container: + +```bash +docker checkpoint create ` +``` + +Create a new container into which to restore: + +```bash +docker create [options] --runtime=runsc +``` + +Restore a container: + +```bash +docker start --checkpoint --checkpoint-dir= +``` + +### Issues Preventing Compatibility with Docker + +- **[Moby #37360][leave-running]:** Docker version 18.03.0-ce and earlier + hangs when checkpointing and does not create the checkpoint. To successfully + use this feature, install a custom version of docker-ce from the moby + repository. This issue is caused by an improper implementation of the + `--leave-running` flag. This issue is fixed in newer releases. +- **Docker does not support restoration into new containers:** Docker + currently expects the container which created the checkpoint to be the same + container used to restore which is not possible in runsc. When Docker + supports container migration and therefore restoration into new containers, + this will be the flow. +- **[Moby #37344][checkpoint-dir]:** Docker does not currently support the + `--checkpoint-dir` flag but this will be required when restoring from a + checkpoint made in another container. + +[leave-running]: https://github.com/moby/moby/pull/37360 +[checkpoint-dir]: https://github.com/moby/moby/issues/37344 diff --git a/g3doc/user_guide/compatibility.md b/g3doc/user_guide/compatibility.md new file mode 100644 index 000000000..9d3e3680f --- /dev/null +++ b/g3doc/user_guide/compatibility.md @@ -0,0 +1,93 @@ +# Applications + +[TOC] + +gVisor implements a large portion of the Linux surface and while we strive to +make it broadly compatible, there are (and always will be) unimplemented +features and bugs. The only real way to know if it will work is to try. If you +find a container that doesn’t work and there is no known issue, please +[file a bug][bug] indicating the full command you used to run the image. You can +view open issues related to compatibility [here][issues]. + +If you're able to provide the [debug logs](../debugging/), the problem likely to +be fixed much faster. + +## What works? + +The following applications/images have been tested: + +* elasticsearch +* golang +* httpd +* java8 +* jenkins +* mariadb +* memcached +* mongo +* mysql +* nginx +* node +* php +* postgres +* prometheus +* python +* redis +* registry +* tomcat +* wordpress + +## Utilities + +Most common utilities work. Note that: + +* Some tools, such as `tcpdump` and old versions of `ping`, require explicitly + enabling raw sockets via the unsafe `--net-raw` runsc flag. +* Different Docker images can behave differently. For example, Alpine Linux + and Ubuntu have different `ip` binaries. + + Specific tools include: + + + +| Tool | Status | +|:--------:|:-----------------------------------------:| +| apt-get | Working. | +| bundle | Working. | +| cat | Working. | +| curl | Working. | +| dd | Working. | +| df | Working. | +| dig | Working. | +| drill | Working. | +| env | Working. | +| find | Working. | +| gdb | Working. | +| gosu | Working. | +| grep | Working (unless stdin is a pipe and stdout is /dev/null). | +| ifconfig | Works partially, like ip. Full support [in progress](https://gvisor.dev/issue/578). | +| ip | Some subcommands work (e.g. addr, route). Full support [in progress](https://gvisor.dev/issue/578). | +| less | Working. | +| ls | Working. | +| lsof | Working. | +| mount | Works in readonly mode. gVisor doesn't currently support creating new mounts at runtime. | +| nc | Working. | +| nmap | Not working. | +| netstat | [In progress](https://gvisor.dev/issue/2112). | +| nslookup | Working. | +| ping | Working. | +| ps | Working. | +| route | Working. | +| ss | [In progress](https://gvisor.dev/issue/2114). | +| sshd | Partially working. Job control [in progress](https://gvisor.dev/issue/154). | +| strace | Working. | +| tar | Working. | +| tcpdump | [In progress](https://gvisor.dev/issue/173). | +| top | Working. | +| uptime | Working. | +| vim | Working. | +| wget | Working. | + + + +[bug]: https://github.com/google/gvisor/issues/new?title=Compatibility%20Issue: +[issues]: https://github.com/google/gvisor/issues?q=is%3Aissue+is%3Aopen+label%3A%22area%3A+compatibility%22 diff --git a/g3doc/user_guide/debugging.md b/g3doc/user_guide/debugging.md new file mode 100644 index 000000000..0525fd5c0 --- /dev/null +++ b/g3doc/user_guide/debugging.md @@ -0,0 +1,131 @@ +# Debugging + +[TOC] + +To enable debug and system call logging, add the `runtimeArgs` below to your +[Docker](../quick_start/docker/) configuration (`/etc/docker/daemon.json`): + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--debug-log=/tmp/runsc/", + "--debug", + "--strace" + ] + } + } +} +``` + +> Note: the last `/` in `--debug-log` is needed to interpret it as a directory. +> Then each `runsc` command executed will create a separate log file. Otherwise, +> log messages from all commands will be appended to the same file. + +You may also want to pass `--log-packets` to troubleshoot network problems. Then +restart the Docker daemon: + +```bash +sudo systemctl restart docker +``` + +Run your container again, and inspect the files under `/tmp/runsc`. The log file +ending with `.boot` will contain the strace logs from your application, which +can be useful for identifying missing or broken system calls in gVisor. If you +are having problems starting the container, the log file ending with `.create` +may have the reason for the failure. + +## Stack traces + +The command `runsc debug --stacks` collects stack traces while the sandbox is +running which can be useful to troubleshoot issues or just to learn more about +gVisor. It connects to the sandbox process, collects a stack dump, and writes it +to the console. For example: + +```bash +docker run --runtime=runsc --rm -d alpine sh -c "while true; do echo running; sleep 1; done" +63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b + +sudo runsc --root /var/run/docker/runtime-runsc/moby debug --stacks 63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b +``` + +> Note: `--root` variable is provided by docker and is normally set to +> `/var/run/docker/runtime-[runtime-name]/moby`. If in doubt, `--root` is logged +> to `runsc` logs. + +## Debugger + +You can debug gVisor like any other Golang program. If you're running with +Docker, you'll need to find the sandbox PID and attach the debugger as root. +Here is an example: + +```bash +# Get a runsc with debug symbols (download nightly or build with symbols). +bazel build -c dbg //runsc:runsc + +# Start the container you want to debug. +docker run --runtime=runsc --rm --name=test -d alpine sleep 1000 + +# Find the sandbox PID. +docker inspect test | grep Pid | head -n 1 + +# Attach your favorite debugger. +sudo dlv attach + +# Set a breakpoint and resume. +break mm.MemoryManager.MMap +continue +``` + +## Profiling + +`runsc` integrates with Go profiling tools and gives you easy commands to +profile CPU and heap usage. First you need to enable `--profile` in the command +line options before starting the container: + +```json +{ + "runtimes": { + "runsc-prof": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--profile" + ] + } + } +} +``` + +> Note: Enabling profiling loosens the seccomp protection added to the sandbox, +> and should not be run in production under normal circumstances. + +Then restart docker to refresh the runtime options. While the container is +running, execute `runsc debug` to collect profile information and save to a +file. Here are the options available: + +* **--profile-heap:** Generates heap profile to the speficied file. +* **--profile-cpu:** Enables CPU profiler, waits for `--duration` seconds and + generates CPU profile to the speficied file. + +For example: + +```bash +docker run --runtime=runsc-prof --rm -d alpine sh -c "while true; do echo running; sleep 1; done" +63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b + +sudo runsc --root /var/run/docker/runtime-runsc-prof/moby debug --profile-heap=/tmp/heap.prof 63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b +sudo runsc --root /var/run/docker/runtime-runsc-prof/moby debug --profile-cpu=/tmp/cpu.prof --duration=30s 63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b +``` + +The resulting files can be opened using `go tool pprof` or [pprof][]. The +examples below create image file (`.svg`) with the heap profile and writes the +top functions using CPU to the console: + +```bash +go tool pprof -svg /usr/local/bin/runsc /tmp/heap.prof +go tool pprof -top /usr/local/bin/runsc /tmp/cpu.prof +``` + +[pprof]: https://github.com/google/pprof/blob/master/doc/README.md diff --git a/g3doc/user_guide/filesystem.md b/g3doc/user_guide/filesystem.md new file mode 100644 index 000000000..6c69f42a1 --- /dev/null +++ b/g3doc/user_guide/filesystem.md @@ -0,0 +1,60 @@ +# Filesystem + +[TOC] + +gVisor accesses the filesystem through a file proxy, called the Gofer. The gofer +runs as a separate process, that is isolated from the sandbox. Gofer instances +communicate with their respective sentry using the 9P protocol. For a more +detailed explanation see [Overview > Gofer](../../architecture_guide/#gofer). + +## Sandbox overlay + +To isolate the host filesystem from the sandbox, you can set a writable tmpfs +overlay on top of the entire filesystem. All modifications are made to the +overlay, keeping the host filesystem unmodified. + +> Note: All created and modified files are stored in memory inside the sandbox. + +To use the tmpfs overlay, add the following `runtimeArgs` to your Docker +configuration (`/etc/docker/daemon.json`) and restart the Docker daemon: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--overlay" + ] + } + } +} +``` + +## Shared root filesystem + +The root filesystem is where the image is extracted and is not generally +modified from outside the sandbox. This allows for some optimizations, like +skipping checks to determine if a directory has changed since the last time it +was cached, thus missing updates that may have happened. If you need to `docker +cp` files inside the root filesystem, you may want to enable shared mode. Just +be aware that file system access will be slower due to the extra checks that are +required. + +> Note: External mounts are always shared. + +To use set the root filesystem shared, add the following `runtimeArgs` to your +Docker configuration (`/etc/docker/daemon.json`) and restart the Docker daemon: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--file-access=shared" + ] + } + } +} +``` diff --git a/g3doc/user_guide/install.md b/g3doc/user_guide/install.md new file mode 100644 index 000000000..0de2b9932 --- /dev/null +++ b/g3doc/user_guide/install.md @@ -0,0 +1,160 @@ +# Installation + +[TOC] + +> Note: gVisor supports only x86\_64 and requires Linux 4.14.77+ +> ([older Linux](./networking.md#gso)). + +## Versions + +The `runsc` binaries and repositories are available in multiple versions and +release channels. You should pick the version you'd like to install. For +experimentation, the nightly release is recommended. For production use, the +latest release is recommended. + +After selecting an appropriate release channel from the options below, proceed +to the preferred installation mechanism: manual or from an `apt` repository. + +### HEAD + +Binaries are available for every commit on the `master` branch, and are +available at the following URL: + +`https://storage.googleapis.com/gvisor/releases/master/latest/runsc` + +Checksums for the release binary are at: + +`https://storage.googleapis.com/gvisor/releases/master/latest/runsc.sha512` + +For `apt` installation, use the `master` as the `${DIST}` below. + +### Nightly + +Nightly releases are built most nights from the master branch, and are available +at the following URL: + +`https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc` + +Checksums for the release binary are at: + +`https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc.sha512` + +Specific nightly releases can be found at: + +`https://storage.googleapis.com/gvisor/releases/nightly/${yyyy-mm-dd}/runsc` + +Note that a release may not be available for every day. + +For `apt` installation, use the `nightly` as the `${DIST}` below. + +### Latest release + +The latest official release is available at the following URL: + +`https://storage.googleapis.com/gvisor/releases/release/latest` + +For `apt` installation, use the `release` as the `${DIST}` below. + +### Specific release + +A given release release is available at the following URL: + +`https://storage.googleapis.com/gvisor/releases/release/${yyyymmdd}` + +See the [releases][releases] page for information about specific releases. + +For `apt` installation of a specific release, which may include point updates, +use the date of the release, e.g. `${yyyymmdd}`, as the `${DIST}` below. + +> Note: only newer releases may be available as `apt` repositories. + +### Point release + +A given point release is available at the following URL: + +`https://storage.googleapis.com/gvisor/releases/release/${yyyymmdd}.${rc}` + +Note that `apt` installation of a specific point release is not supported. + +## Install from an `apt` repository + +First, appropriate dependencies must be installed to allow `apt` to install +packages via https: + +```bash +sudo apt-get update && \ +sudo apt-get install -y \ + apt-transport-https \ + ca-certificates \ + curl \ + gnupg-agent \ + software-properties-common +``` + +Next, the key used to sign archives should be added to your `apt` keychain: + +```bash +curl -fsSL https://gvisor.dev/archive.key | sudo apt-key add - +``` + +Based on the release type, you will need to substitute `${DIST}` below, using +one of: + +* `master`: For HEAD. +* `nightly`: For nightly releases. +* `release`: For the latest release. +* `${yyyymmdd}`: For a specific releases (see above). + +The repository for the release you wish to install should be added: + +```bash +sudo add-apt-repository "deb https://storage.googleapis.com/gvisor/releases ${DIST} main" +``` + +For example, to install the latest official release, you can use: + +```bash +sudo add-apt-repository "deb https://storage.googleapis.com/gvisor/releases release main" +``` + +Now the runsc package can be installed: + +```bash +sudo apt-get update && sudo apt-get install -y runsc +``` + +If you have Docker installed, it will be automatically configured. + +## Install directly + +The binary URLs provided above can be used to install directly. For example, the +latest nightly binary can be downloaded, validated, and placed in an appropriate +location by running: + +```bash +( + set -e + URL=https://storage.googleapis.com/gvisor/releases/nightly/latest + wget ${URL}/runsc + wget ${URL}/runsc.sha512 + sha512sum -c runsc.sha512 + rm -f runsc.sha512 + sudo mv runsc /usr/local/bin + sudo chown root:root /usr/local/bin/runsc + sudo chmod 0755 /usr/local/bin/runsc +) +``` + +**It is important to copy this binary to a location that is accessible to all +users, and ensure it is executable by all users**, since `runsc` executes itself +as user `nobody` to avoid unnecessary privileges. The `/usr/local/bin` directory +is a good place to put the `runsc` binary. + +After installation, the`runsc` binary comes with an `install` command that can +optionally automatically configure Docker: + +```bash +runsc install +``` + +[releases]: https://github.com/google/gvisor/releases diff --git a/g3doc/user_guide/networking.md b/g3doc/user_guide/networking.md new file mode 100644 index 000000000..4aa394c91 --- /dev/null +++ b/g3doc/user_guide/networking.md @@ -0,0 +1,85 @@ +# Networking + +[TOC] + +gVisor implements its own network stack called [netstack][netstack]. All aspects +of the network stack are handled inside the Sentry — including TCP connection +state, control messages, and packet assembly — keeping it isolated from the host +network stack. Data link layer packets are written directly to the virtual +device inside the network namespace setup by Docker or Kubernetes. + +The IP address and routes configured for the device are transferred inside the +sandbox. The loopback device runs exclusively inside the sandbox and does not +use the host. You can inspect them by running: + +```bash +docker run --rm --runtime=runsc alpine ip addr +``` + +## Network passthrough + +For high-performance networking applications, you may choose to disable the user +space network stack and instead use the host network stack, including the +loopback. Note that this mode decreases the isolation to the host. + +Add the following `runtimeArgs` to your Docker configuration +(`/etc/docker/daemon.json`) and restart the Docker daemon: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--network=host" + ] + } + } +} +``` + +## Disabling external networking + +To completely isolate the host and network from the sandbox, external networking +can be disabled. The sandbox will still contain a loopback provided by netstack. + +Add the following `runtimeArgs` to your Docker configuration +(`/etc/docker/daemon.json`) and restart the Docker daemon: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--network=none" + ] + } + } +} +``` + +### Disable GSO {#gso} + +If your Linux is older than 4.14.17, you can disable Generic Segmentation +Offload (GSO) to run with a kernel that is newer than 3.17. Add the +`--gso=false` flag to your Docker runtime configuration +(`/etc/docker/daemon.json`) and restart the Docker daemon: + +> Note: Network performance, especially for large payloads, will be greatly +> reduced. + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--gso=false" + ] + } + } +} +``` + +[netstack]: https://github.com/google/netstack diff --git a/g3doc/user_guide/platforms.md b/g3doc/user_guide/platforms.md new file mode 100644 index 000000000..eefb6b222 --- /dev/null +++ b/g3doc/user_guide/platforms.md @@ -0,0 +1,119 @@ +# Platforms (KVM) + +[TOC] + +This document will help you set up your system to use a different gVisor +platform. + +## What is a Platform? + +gVisor requires a *platform* to implement interception of syscalls, basic +context switching, and memory mapping functionality. These are described in more +depth in the [Platform Design](../../architecture_guide/platforms/). + +## Selecting a Platform + +The platform is selected by the `--platform` command line flag passed to +`runsc`. By default, the ptrace platform is selected. To select a different +platform, modify your Docker configuration (`/etc/docker/daemon.json`) to pass +this argument: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--platform=kvm" + ] + } + } +} +``` + +You must restart the Docker daemon after making changes to this file, typically +this is done via `systemd`: + +```bash +sudo systemctl restart docker +``` + +## Example: Using the KVM Platform + +The KVM platform is currently experimental; however, it provides several +benefits over the default ptrace platform. + +### Prerequisites + +You will also to have KVM installed on your system. If you are running a Debian +based system like Debian or Ubuntu you can usually do this by installing the +`qemu-kvm` package. + +```bash +sudo apt-get install qemu-kvm +``` + +If you are using a virtual machine you will need to make sure that nested +virtualization is configured. Here are links to documents on how to set up +nested virtualization in several popular environments: + +* Google Cloud: [Enabling Nested Virtualization for VM Instances][nested-gcp] +* Microsoft Azure: + [How to enable nested virtualization in an Azure VM][nested-azure] +* VirtualBox: [Nested Virtualization][nested-virtualbox] +* KVM: [Nested Guests][nested-kvm] + +***Note: nested virtualization will have poor performance and is historically a +cause of security issues (e.g. +[CVE-2018-12904](https://nvd.nist.gov/vuln/detail/CVE-2018-12904)). It is not +recommended for production.*** + +### Configuring Docker + +Per above, you will need to configure Docker to use `runsc` with the KVM +platform. You will remember from the Docker Quick Start that you configured +Docker to use `runsc` as the runtime. Docker allows you to add multiple runtimes +to the Docker configuration. + +Add a new entry for the KVM platform entry to your Docker configuration +(`/etc/docker/daemon.json`) in order to provide the `--platform=kvm` runtime +argument. + +In the end, the file should look something like: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc" + }, + "runsc-kvm": { + "path": "/usr/local/bin/runsc", + "runtimeArgs": [ + "--platform=kvm" + ] + } + } +} +``` + +You must restart the Docker daemon after making changes to this file, typically +this is done via `systemd`: + +```bash +sudo systemctl restart docker +``` + +## Running a container + +Now run your container using the `runsc-kvm` runtime. This will run the +container using the KVM platform: + +```bash +docker run --runtime=runsc-kvm --rm hello-world +``` + +[nested-azure]: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/nested-virtualization +[nested-gcp]: https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances +[nested-virtualbox]: https://www.virtualbox.org/manual/UserManual.html#nested-virt +[nested-kvm]: https://www.linux-kvm.org/page/Nested_Guests diff --git a/g3doc/user_guide/quick_start/BUILD b/g3doc/user_guide/quick_start/BUILD new file mode 100644 index 000000000..63f17f9cb --- /dev/null +++ b/g3doc/user_guide/quick_start/BUILD @@ -0,0 +1,33 @@ +load("//website:defs.bzl", "doc") + +package( + default_visibility = ["//website:__pkg__"], + licenses = ["notice"], +) + +doc( + name = "docker", + src = "docker.md", + category = "User Guide", + permalink = "/docs/user_guide/quick_start/docker/", + subcategory = "Quick Start", + weight = "11", +) + +doc( + name = "oci", + src = "oci.md", + category = "User Guide", + permalink = "/docs/user_guide/quick_start/oci/", + subcategory = "Quick Start", + weight = "12", +) + +doc( + name = "kubernetes", + src = "kubernetes.md", + category = "User Guide", + permalink = "/docs/user_guide/quick_start/kubernetes/", + subcategory = "Quick Start", + weight = "13", +) diff --git a/g3doc/user_guide/quick_start/docker.md b/g3doc/user_guide/quick_start/docker.md new file mode 100644 index 000000000..5228db4c0 --- /dev/null +++ b/g3doc/user_guide/quick_start/docker.md @@ -0,0 +1,92 @@ +# Docker + +> Note: This guide requires Docker version 17.09.0 or greater. Refer to the +> [Docker documentation][docker] for how to install it. + +This guide will help you quickly get started running Docker containers using +gVisor. + +First, follow the [Installation guide][install]. + +If you use the `apt` repository or the `automated` install, then you can skip +the next section and proceed straight to running a container. + +## Configuring Docker + +First you will need to configure Docker to use `runsc` by adding a runtime entry +to your Docker configuration (`/etc/docker/daemon.json`). You may have to create +this file if it does not exist. Also, some Docker versions also require you to +[specify the `storage-driver` field][storage-driver]. + +In the end, the file should look something like: + +```json +{ + "runtimes": { + "runsc": { + "path": "/usr/local/bin/runsc" + } + } +} +``` + +You must restart the Docker daemon after making changes to this file, typically +this is done via `systemd`: + +```bash +sudo systemctl restart docker +``` + +## Running a container + +Now run your container using the `runsc` runtime: + +```bash +docker run --runtime=runsc --rm hello-world +``` + +You can also run a terminal to explore the container. + +```bash +docker run --runtime=runsc --rm -it ubuntu /bin/bash +``` + +Many docker options are compatible with gVisor, try them out. Here is an +example: + +```bash +docker run --runtime=runsc --rm --link backend:database -v ~/bin:/tools:ro -p 8080:80 --cpus=0.5 -it busybox telnet towel.blinkenlights.nl +``` + +## Verify the runtime + +You can verify that you are running in gVisor using the `dmesg` command. + +```text +$ docker run --runtime=runsc -it ubuntu dmesg +[ 0.000000] Starting gVisor... +[ 0.354495] Daemonizing children... +[ 0.564053] Constructing home... +[ 0.976710] Preparing for the zombie uprising... +[ 1.299083] Creating process schedule... +[ 1.479987] Committing treasure map to memory... +[ 1.704109] Searching for socket adapter... +[ 1.748935] Generating random numbers by fair dice roll... +[ 2.059747] Digging up root... +[ 2.259327] Checking naughty and nice process list... +[ 2.610538] Rewriting operating system in Javascript... +[ 2.613217] Ready! +``` + +Note that this is easily replicated by an attacker so applications should never +use `dmesg` to verify the runtime in a security sensitive context. + +Next, look at the different options available for gVisor: [platform][platforms], +[network][networking], [filesystem][filesystem]. + +[docker]: https://docs.docker.com/install/ +[storage-driver]: https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-storage-driver +[install]: /docs/user_guide/install/ +[filesystem]: /docs/user_guide/filesystem/ +[networking]: /docs/user_guide/networking/ +[platforms]: /docs/user_guide/platforms/ diff --git a/g3doc/user_guide/quick_start/kubernetes.md b/g3doc/user_guide/quick_start/kubernetes.md new file mode 100644 index 000000000..b1f67252e --- /dev/null +++ b/g3doc/user_guide/quick_start/kubernetes.md @@ -0,0 +1,36 @@ +# Kubernetes + +gVisor can be used to run Kubernetes pods and has several integration points +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` +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]. + +## Using GKE Sandbox + +[GKE Sandbox][gke-sandbox] is available in [Google Kubernetes Engine][gke]. You +just need to deploy a node pool with gVisor enabled in your cluster, and it will +run pods annotated with `runtimeClassName: gvisor` inside a gVisor sandbox for +you. [Here][wordpress-quick] is a quick example showing how to deploy a +WordPress site. You can view the full documentation [here][gke-sandbox-docs]. + +[containerd]: https://containerd.io/ +[minikube]: https://github.com/kubernetes/minikube/blob/master/deploy/addons/gvisor/README.md +[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 +[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 new file mode 100644 index 000000000..57bcc4f63 --- /dev/null +++ b/g3doc/user_guide/quick_start/oci.md @@ -0,0 +1,45 @@ +# OCI + +This guide will quickly get you started running your first gVisor sandbox +container using the runtime directly with the default platform. + +First, follow the [Installation guide][install]. + +## Run an OCI compatible container + +Now we will create an [OCI][oci] container bundle to run our container. First we +will create a root directory for our bundle. + +```bash +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. + +```bash +mkdir rootfs +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. + +```bash +runsc spec +sed -i 's;"sh";"/hello";' config.json +``` + +Finally run the container. + +```bash +sudo runsc run hello +``` + +Next try [using CNI to set up networking](../../../tutorials/cni/) or +[running gVisor using Docker](../docker/). + +[oci]: https://opencontainers.org/ +[install]: /docs/user_guide/install diff --git a/g3doc/user_guide/tutorials/BUILD b/g3doc/user_guide/tutorials/BUILD new file mode 100644 index 000000000..caae98623 --- /dev/null +++ b/g3doc/user_guide/tutorials/BUILD @@ -0,0 +1,37 @@ +load("//website:defs.bzl", "doc") + +package( + default_visibility = ["//website:__pkg__"], + licenses = ["notice"], +) + +doc( + name = "docker", + src = "docker.md", + 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", +) + +doc( + name = "kubernetes", + src = "kubernetes.md", + category = "User Guide", + data = [ + "add-node-pool.png", + "node-pool-button.png", + ], + permalink = "/docs/tutorials/kubernetes/", + subcategory = "Tutorials", + weight = "33", +) diff --git a/g3doc/user_guide/tutorials/add-node-pool.png b/g3doc/user_guide/tutorials/add-node-pool.png new file mode 100644 index 000000000..e4560359b Binary files /dev/null and b/g3doc/user_guide/tutorials/add-node-pool.png differ diff --git a/g3doc/user_guide/tutorials/cni.md b/g3doc/user_guide/tutorials/cni.md new file mode 100644 index 000000000..ad6c9fa59 --- /dev/null +++ b/g3doc/user_guide/tutorials/cni.md @@ -0,0 +1,172 @@ +# Using CNI + +This tutorial will show you how to set up networking for a gVisor sandbox using +the +[Container Networking Interface (CNI)](https://github.com/containernetworking/cni). + +## Install CNI Plugins + +First you will need to install the CNI plugins. CNI plugins are used to set up a +network namespace that `runsc` can use with the sandbox. + +Start by creating the directories for CNI plugin binaries: + +``` +sudo mkdir -p /opt/cni/bin +``` + +Download the CNI plugins: + +``` +wget https://github.com/containernetworking/plugins/releases/download/v0.8.3/cni-plugins-linux-amd64-v0.8.3.tgz +``` + +Next, unpack the plugins into the CNI binary directory: + +``` +sudo tar -xvf cni-plugins-linux-amd64-v0.8.3.tgz -C /opt/cni/bin/ +``` + +## Configure CNI Plugins + +This section will show you how to configure CNI plugins. This tutorial will use +the "bridge" and "loopback" plugins which will create the necessary bridge and +loopback devices in our network namespace. However, you should be able to use +any CNI compatible plugin to set up networking for gVisor sandboxes. + +The bridge plugin configuration specifies the IP address subnet range for IP +addresses that will be assigned to sandboxes as well as the network routing +configuration. This tutorial will assign IP addresses from the `10.22.0.0/16` +range and allow all outbound traffic, however you can modify this configuration +to suit your use case. + +Create the bridge and loopback plugin configurations: + +``` +sudo mkdir -p /etc/cni/net.d + +sudo sh -c 'cat > /etc/cni/net.d/10-bridge.conf << EOF +{ + "cniVersion": "0.4.0", + "name": "mynet", + "type": "bridge", + "bridge": "cni0", + "isGateway": true, + "ipMasq": true, + "ipam": { + "type": "host-local", + "subnet": "10.22.0.0/16", + "routes": [ + { "dst": "0.0.0.0/0" } + ] + } +} +EOF' + +sudo sh -c 'cat > /etc/cni/net.d/99-loopback.conf << EOF +{ + "cniVersion": "0.4.0", + "name": "lo", + "type": "loopback" +} +EOF' +``` + +## Create a Network Namespace + +For each gVisor sandbox you will create a network namespace and configure it +using CNI. First, create a random network namespace name and then create the +namespace. + +The network namespace path will then be `/var/run/netns/${CNI_CONTAINERID}`. + +``` +export CNI_PATH=/opt/cni/bin +export CNI_CONTAINERID=$(printf '%x%x%x%x' $RANDOM $RANDOM $RANDOM $RANDOM) +export CNI_COMMAND=ADD +export CNI_NETNS=/var/run/netns/${CNI_CONTAINERID} + +sudo ip netns add ${CNI_CONTAINERID} +``` + +Next, run the bridge and loopback plugins to apply the configuration that was +created earlier to the namespace. Each plugin outputs some JSON indicating the +results of executing the plugin. For example, The bridge plugin's response +includes the IP address assigned to the ethernet device created in the network +namespace. Take note of the IP address for use later. + +``` +export CNI_IFNAME="eth0" +sudo -E /opt/cni/bin/bridge < /etc/cni/net.d/10-bridge.conf +export CNI_IFNAME="lo" +sudo -E /opt/cni/bin/loopback < /etc/cni/net.d/99-loopback.conf +``` + +Get the IP address assigned to our sandbox: + +``` +POD_IP=$(sudo ip netns exec ${CNI_CONTAINERID} ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') +``` + +## Create the OCI Bundle + +Now that our network namespace is created and configured, we can create the OCI +bundle for our container. As part of the bundle's `config.json` we will specify +that the container use the network namespace that we created. + +The container will run a simple python webserver that we will be able to connect +to via the IP address assigned to it via the bridge CNI plugin. + +Create the bundle and root filesystem directories: + +``` +sudo mkdir -p bundle +cd bundle +sudo mkdir rootfs +sudo docker export $(docker create python) | sudo tar --same-owner -pxf - -C rootfs +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` + +## Run the Container + +Now we can run and connect to the webserver. Run the container in gVisor. Use +the same ID used for the network namespace to be consistent: + +``` +sudo runsc run -detach ${CNI_CONTAINERID} +``` + +Connect to the server via the sandbox's IP address: + +``` +curl http://${POD_IP}:8000/ +``` + +You should see the server returning `Hello World!`. + +## Cleanup + +After you are finished running the container, you can clean up the network +namespace . + +``` +sudo runsc kill ${CNI_CONTAINERID} +sudo runsc delete ${CNI_CONTAINERID} + +export CNI_COMMAND=DEL + +export CNI_IFNAME="lo" +sudo -E /opt/cni/bin/loopback < /etc/cni/net.d/99-loopback.conf +export CNI_IFNAME="eth0" +sudo -E /opt/cni/bin/bridge < /etc/cni/net.d/10-bridge.conf + +sudo ip netns delete ${CNI_CONTAINERID} +``` diff --git a/g3doc/user_guide/tutorials/docker.md b/g3doc/user_guide/tutorials/docker.md new file mode 100644 index 000000000..c0a3db506 --- /dev/null +++ b/g3doc/user_guide/tutorials/docker.md @@ -0,0 +1,68 @@ +# WorkPress with Docker + +This page shows you how to deploy a sample [WordPress][wordpress] site using +[Docker][docker]. + +### Before you begin + +[Follow these instructions][docker-install] to install runsc with Docker. This +document assumes that the runtime name chosen is `runsc`. + +### Running WordPress + +Now, let's deploy a WordPress site using Docker. WordPress site requires two +containers: web server in the frontend, MySQL database in the backend. + +First, let's define a few environment variables that are shared between both +containers: + +```bash +export MYSQL_PASSWORD=${YOUR_SECRET_PASSWORD_HERE?} +export MYSQL_DB=wordpress +export MYSQL_USER=wordpress +``` + +Next, let's start the database container running MySQL and wait until the +database is initialized: + +```bash +docker run --runtime=runsc --name mysql -d \ + -e MYSQL_RANDOM_ROOT_PASSWORD=1 \ + -e MYSQL_PASSWORD="${MYSQL_PASSWORD}" \ + -e MYSQL_DATABASE="${MYSQL_DB}" \ + -e MYSQL_USER="${MYSQL_USER}" \ + mysql:5.7 + +# Wait until this message appears in the log. +docker logs mysql |& grep 'port: 3306 MySQL Community Server (GPL)' +``` + +Once the database is running, you can start the WordPress frontend. We use the +`--link` option to connect the frontend to the database, and expose the +WordPress to port 8080 on the localhost. + +```bash +docker run --runtime=runsc --name wordpress -d \ + --link mysql:mysql \ + -p 8080:80 \ + -e WORDPRESS_DB_HOST=mysql \ + -e WORDPRESS_DB_USER="${MYSQL_USER}" \ + -e WORDPRESS_DB_PASSWORD="${MYSQL_PASSWORD}" \ + -e WORDPRESS_DB_NAME="${MYSQL_DB}" \ + -e WORDPRESS_TABLE_PREFIX=wp_ \ + wordpress +``` + +Now, you can access the WordPress website pointing your favorite browser to +. + +Congratulations! You have just deployed a WordPress site using Docker. + +### What's next + +[Learn how to deploy WordPress with Kubernetes][wordpress-k8s]. + +[docker]: https://www.docker.com/ +[docker-install]: /docs/user_guide/quick_start/docker/ +[wordpress]: https://wordpress.com/ +[wordpress-k8s]: /docs/tutorials/kubernetes/ diff --git a/g3doc/user_guide/tutorials/kubernetes.md b/g3doc/user_guide/tutorials/kubernetes.md new file mode 100644 index 000000000..d2a94b1b7 --- /dev/null +++ b/g3doc/user_guide/tutorials/kubernetes.md @@ -0,0 +1,134 @@ +# WordPress with Kubernetes + +This page shows you how to deploy a sample [WordPress][wordpress] site using +[GKE Sandbox][gke-sandbox]. + +### Before you begin + +Take the following steps to enable the Kubernetes Engine API: + +1. Visit the [Kubernetes Engine page][project-selector] in the Google Cloud + Platform Console. +1. Create or select a project. + +### Creating a node pool with gVisor enabled + +Create a node pool inside your cluster with option `--sandbox type=gvisor` added +to the command, like below: + +```bash +gcloud beta container node-pools create sandbox-pool --cluster=${CLUSTER_NAME} --image-type=cos_containerd --sandbox type=gvisor +``` + +If you prefer to use the console, select your cluster and select the **ADD NODE +POOL** button: + +![+ ADD NODE POOL](./node-pool-button.png) + +Then select the **Image type** with **Containerd** and select **Enable sandbox +with gVisor** option. Select other options as you like: + +![+ NODE POOL](./add-node-pool.png) + +### Check that gVisor is enabled + +The gvisor RuntimeClass is instantiated during node creation. You can check for +the existence of the gvisor RuntimeClass using the following command: + +```bash +kubectl get runtimeclasses +``` + +### Wordpress deployment + +Now, let's deploy a WordPress site using GKE Sandbox. WordPress site requires +two pods: web server in the frontend, MySQL database in the backend. Both +applications use PersistentVolumes to store the site data data. In addition, +they use secret store to share MySQL password between them. + +First, let's download the deployment configuration files to add the runtime +class annotation to them: + +```bash +curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml +curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml +``` + +Add a **spec.template.spec.runtimeClassName** set to **gvisor** to both files, +as shown below: + +**wordpress-deployment.yaml:** ```yaml apiVersion: v1 kind: Service metadata: +name: wordpress labels: app: wordpress spec: ports: - port: 80 selector: app: +wordpress tier: frontend + +## type: LoadBalancer + +apiVersion: v1 kind: PersistentVolumeClaim metadata: name: wp-pv-claim labels: +app: wordpress spec: accessModes: - ReadWriteOnce resources: requests: + +## storage: 20Gi + +apiVersion: apps/v1 kind: Deployment metadata: name: wordpress labels: app: +wordpress spec: selector: matchLabels: app: wordpress tier: frontend strategy: +type: Recreate template: metadata: labels: app: wordpress tier: frontend spec: +runtimeClassName: gvisor # ADD THIS LINE containers: - image: +wordpress:4.8-apache name: wordpress env: - name: WORDPRESS_DB_HOST value: +wordpress-mysql - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: +mysql-pass key: password ports: - containerPort: 80 name: wordpress +volumeMounts: - name: wordpress-persistent-storage mountPath: /var/www/html +volumes: - name: wordpress-persistent-storage persistentVolumeClaim: claimName: +wp-pv-claim ``` + +**mysql-deployment.yaml:** ```yaml apiVersion: v1 kind: Service metadata: name: +wordpress-mysql labels: app: wordpress spec: ports: - port: 3306 selector: app: +wordpress tier: mysql + +## clusterIP: None + +apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pv-claim +labels: app: wordpress spec: accessModes: - ReadWriteOnce resources: requests: + +## storage: 20Gi + +apiVersion: apps/v1 kind: Deployment metadata: name: wordpress-mysql labels: +app: wordpress spec: selector: matchLabels: app: wordpress tier: mysql strategy: +type: Recreate template: metadata: labels: app: wordpress tier: mysql spec: +runtimeClassName: gvisor # ADD THIS LINE containers: - image: mysql:5.6 name: +mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-pass +key: password ports: - containerPort: 3306 name: mysql volumeMounts: - name: +mysql-persistent-storage mountPath: /var/lib/mysql volumes: - name: +mysql-persistent-storage persistentVolumeClaim: claimName: mysql-pv-claim ``` + +Note that apart from `runtimeClassName: gvisor`, nothing else about the +Deployment has is changed. + +You are now ready to deploy the entire application. Just create a secret to +store MySQL's password and *apply* both deployments: + +```bash +kubectl create secret generic mysql-pass --from-literal=password=${YOUR_SECRET_PASSWORD_HERE?} +kubectl apply -f mysql-deployment.yaml +kubectl apply -f wordpress-deployment.yaml +``` + +Wait for the deployments to be ready and an external IP to be assigned to the +Wordpress service: + +```bash +watch kubectl get service wordpress +``` + +Now, copy the service `EXTERNAL-IP` from above to your favorite browser to view +and configure your new WordPress site. + +Congratulations! You have just deployed a WordPress site using GKE Sandbox. + +### What's next + +To learn more about GKE Sandbox and how to run your deployment securely, take a +look at the [documentation][gke-sandbox-docs]. + +[gke-sandbox-docs]: https://cloud.google.com/kubernetes-engine/docs/how-to/sandbox-pods +[gke-sandbox]: https://cloud.google.com/kubernetes-engine/sandbox/ +[project-selector]: https://console.cloud.google.com/projectselector/kubernetes +[wordpress]: https://wordpress.com/ diff --git a/g3doc/user_guide/tutorials/node-pool-button.png b/g3doc/user_guide/tutorials/node-pool-button.png new file mode 100644 index 000000000..bee0c11dc Binary files /dev/null and b/g3doc/user_guide/tutorials/node-pool-button.png differ diff --git a/images/default/Dockerfile b/images/default/Dockerfile index 2d0bb5ba5..397082b02 100644 --- a/images/default/Dockerfile +++ b/images/default/Dockerfile @@ -1,11 +1,16 @@ FROM fedora:31 +# Install bazel. RUN dnf install -y dnf-plugins-core && dnf copr enable -y vbatts/bazel RUN dnf install -y git gcc make golang gcc-c++ glibc-devel python3 which python3-pip python3-devel libffi-devel openssl-devel pkg-config glibc-static libstdc++-static patch RUN pip install pycparser RUN dnf install -y bazel3 +# Install gcloud. RUN curl https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-289.0.0-linux-x86_64.tar.gz | \ tar zxvf - google-cloud-sdk && \ google-cloud-sdk/install.sh && \ ln -s /google-cloud-sdk/bin/gcloud /usr/bin/gcloud +# Install Docker client for the website build. +RUN dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo +RUN dnf install -y docker-ce-cli WORKDIR /workspace ENTRYPOINT ["/usr/bin/bazel"] diff --git a/images/jekyll/Dockerfile b/images/jekyll/Dockerfile new file mode 100644 index 000000000..cefd949a6 --- /dev/null +++ b/images/jekyll/Dockerfile @@ -0,0 +1,12 @@ +FROM jekyll/jekyll:4.0.0 +USER root +RUN gem install \ + html-proofer:3.10.2 \ + nokogiri:1.10.1 \ + jekyll-autoprefixer:1.0.2 \ + jekyll-inline-svg:1.1.4 \ + jekyll-paginate:1.1.0 \ + kramdown-parser-gfm:1.1.0 \ + jekyll-relative-links:0.6.1 \ + jekyll-feed:0.13.0 +CMD ["/usr/gem/gems/jekyll-4.0.0/exe/jekyll", "build", "-t", "-s", "/input", "-d", "/output"] diff --git a/tools/bazel.mk b/tools/bazel.mk index dbe0ff77a..4d9bbf0ee 100644 --- a/tools/bazel.mk +++ b/tools/bazel.mk @@ -22,7 +22,7 @@ BRANCH_NAME := $(shell (git branch --show-current 2>/dev/null || \ # Bazel container configuration (see below). USER ?= gvisor DOCKER_NAME ?= gvisor-bazel-$(shell readlink -m $(CURDIR) | md5sum | cut -c1-8) -DOCKER_RUN_OPTIONS ?= --privileged +DOCKER_PRIVILEGED ?= --privileged BAZEL_CACHE := $(shell readlink -m ~/.cache/bazel/) GCLOUD_CONFIG := $(shell readlink -m ~/.config/gcloud/) DOCKER_SOCKET := /var/run/docker.sock @@ -30,10 +30,19 @@ DOCKER_SOCKET := /var/run/docker.sock # Non-configurable. UID := $(shell id -u ${USER}) GID := $(shell id -g ${USER}) +USERADD_OPTIONS := FULL_DOCKER_RUN_OPTIONS := $(DOCKER_RUN_OPTIONS) FULL_DOCKER_RUN_OPTIONS += -v "$(BAZEL_CACHE):$(BAZEL_CACHE)" FULL_DOCKER_RUN_OPTIONS += -v "$(GCLOUD_CONFIG):$(GCLOUD_CONFIG)" +FULL_DOCKER_RUN_OPTIONS += -v "/tmp:/tmp" +ifneq ($(DOCKER_PRIVILEGED),) FULL_DOCKER_RUN_OPTIONS += -v "$(DOCKER_SOCKET):$(DOCKER_SOCKET)" +DOCKER_GROUP := $(shell stat -c '%g' $(DOCKER_SOCKET)) +ifneq ($(GID),$(DOCKER_GROUP)) +USERADD_OPTIONS += --groups $(DOCKER_GROUP) +FULL_DOCKER_RUN_OPTIONS += --group-add $(DOCKER_GROUP) +endif +endif SHELL=/bin/bash -o pipefail ## @@ -53,15 +62,14 @@ bazel-server-start: load-default ## Starts the bazel server. docker run -d --rm \ --init \ --name $(DOCKER_NAME) \ - --user 0:0 \ + --user 0:0 $(DOCKER_GROUP_OPTIONS) \ -v "$(CURDIR):$(CURDIR)" \ --workdir "$(CURDIR)" \ - --tmpfs /tmp:rw,exec \ --entrypoint "" \ $(FULL_DOCKER_RUN_OPTIONS) \ gvisor.dev/images/default \ sh -c "groupadd --gid $(GID) --non-unique $(USER) && \ - useradd --uid $(UID) --non-unique --no-create-home --gid $(GID) -d $(HOME) $(USER) && \ + useradd --uid $(UID) --non-unique --no-create-home --gid $(GID) $(USERADD_OPTIONS) -d $(HOME) $(USER) && \ bazel version && \ exec tail --pid=\$$(bazel info server_pid) -f /dev/null" @while :; do if docker logs $(DOCKER_NAME) 2>/dev/null | grep "Build label:" >/dev/null; then break; fi; sleep 1; done diff --git a/website/BUILD b/website/BUILD new file mode 100644 index 000000000..d6afd5f44 --- /dev/null +++ b/website/BUILD @@ -0,0 +1,181 @@ +load("//tools:defs.bzl", "pkg_tar") +load("//website:defs.bzl", "doc", "docs") + +package(licenses = ["notice"]) + +# website is the full container image. Note that this actually just collects +# other dependendcies and runs Docker locally to import and tag the image. +sh_binary( + name = "website", + srcs = ["import.sh"], + data = [":files"], + tags = [ + "local", + "manual", + ], +) + +# files is the full file system of the generated container. +# +# It must collect the all tarballs (produced by the rules below), and run it +# through the Dockerfile to generate the site. Note that this checks all links, +# and therefore requires all static content to be present as well. +# +# Note that this rule violates most aspects of hermetic builds. However, this +# works much more reliably than depending on the container_image rules from +# bazel itself, which are convoluted and seem to have a hard time even finding +# the toolchain. +genrule( + name = "files", + srcs = [ + ":config", + ":css", + ":docs", + ":static", + ":syscallmd", + "//website/blog:posts", + "//website/cmd/server", + ], + outs = ["files.tgz"], + cmd = "set -x; " + + "T=$$(mktemp -d); " + + "mkdir -p $$T/input && " + + "mkdir -p $$T/output/_site && " + + "tar -xf $(location :config) -C $$T/input && " + + "tar -xf $(location :css) -C $$T/input && " + + "tar -xf $(location :docs) -C $$T/input && " + + "tar -xf $(location :syscallmd) -C $$T/input && " + + "tar -xf $(location //website/blog:posts) -C $$T/input && " + + "find $$T/input -type f -exec chmod u+rw {} \\; && " + + "docker run -i --user $$(id -u):$$(id -g) " + + "-v $$(readlink -m $$T/input):/input " + + "-v $$(readlink -m $$T/output/_site):/output " + + "gvisor.dev/images/jekyll && " + + "tar -xf $(location :static) -C $$T/output/_site && " + + "docker run -i --user $$(id -u):$$(id -g) " + + "-v $$(readlink -m $$T/output/_site):/output " + + "gvisor.dev/images/jekyll " + + "/usr/gem/bin/htmlproofer " + + "--disable-external " + + "--check-html " + + "/output && " + + "cp $(location //website/cmd/server) $$T/output/server && " + + "tar -zcf $@ -C $$T/output . && " + + "rm -rf $$T", + tags = [ + "local", + "manual", + "nosandbox", + ], +) + +# static are the purely static parts of the site. These are effectively copied +# in after jekyll generates all the dynamic content. +pkg_tar( + name = "static", + srcs = [ + "archive.key", + ] + glob([ + "performance/**", + ]), + strip_prefix = "./", +) + +# main.scss requires front-matter to be processed. +genrule( + name = "css", + srcs = glob([ + "css/**", + ]), + outs = [ + "css.tar", + ], + cmd = "T=$$(mktemp -d); " + + "mkdir -p $$T/css && " + + "for file in $(SRCS); do " + + "echo -en '---\\n---\\n' > $$T/css/$$(basename $$file) && " + + "cat $$file >> $$T/css/$$(basename $$file); " + + "done && " + + "tar -C $$T -czf $@ . && " + + "rm -rf $$T", +) + +# config is "mostly" static content. These are parts of the site that are +# present when jekyll runs, but are not dynamically generated. +pkg_tar( + name = "config", + srcs = [ + ":css", + "_config.yml", + "//website/blog:index.html", + ] + glob([ + "assets/**", + "_includes/**", + "_layouts/**", + "_plugins/**", + "_sass/**", + ]), + strip_prefix = "./", +) + +# index is the index file. +doc( + name = "index", + src = "index.md", + layout = "base", + permalink = "/", +) + +# docs is the dynamic content of the site. +docs( + name = "docs", + deps = [ + ":index", + "//:code_of_conduct", + "//:contributing", + "//:governance", + "//:security", + "//g3doc:community", + "//g3doc:index", + "//g3doc:roadmap", + "//g3doc/architecture_guide:index", + "//g3doc/architecture_guide:performance", + "//g3doc/architecture_guide:platforms", + "//g3doc/architecture_guide:resources", + "//g3doc/architecture_guide:security", + "//g3doc/user_guide:FAQ", + "//g3doc/user_guide:checkpoint_restore", + "//g3doc/user_guide:compatibility", + "//g3doc/user_guide:debugging", + "//g3doc/user_guide:filesystem", + "//g3doc/user_guide:install", + "//g3doc/user_guide:networking", + "//g3doc/user_guide:platforms", + "//g3doc/user_guide/quick_start:docker", + "//g3doc/user_guide/quick_start:kubernetes", + "//g3doc/user_guide/quick_start:oci", + "//g3doc/user_guide/tutorials:cni", + "//g3doc/user_guide/tutorials:docker", + "//g3doc/user_guide/tutorials:kubernetes", + ], +) + +# Generate JSON for system call tables +genrule( + name = "syscalljson", + outs = ["syscalls.json"], + cmd = "$(location //runsc) -- help syscalls -format json -filename $@", + tools = ["//runsc"], +) + +# Generate markdown from the json dump. +genrule( + name = "syscallmd", + srcs = [":syscalljson"], + outs = ["syscallsmd"], + cmd = "T=$$(mktemp -d) && " + + "$(location //website/cmd/syscalldocs) -in $< -out $$T && " + + "tar -C $$T -czf $@ . && " + + "rm -rf $$T", + tools = ["//website/cmd/syscalldocs"], +) diff --git a/website/_config.yml b/website/_config.yml new file mode 100644 index 000000000..3241e458c --- /dev/null +++ b/website/_config.yml @@ -0,0 +1,35 @@ +destination: _site +markdown: kramdown +kramdown: + syntax_highlighter: rouge + toc_levels: "2,3" +highlighter: rouge +paginate: 5 +paginate_path: "/blog/page:num/" +plugins: + - jekyll-paginate + - jekyll-autoprefixer + - jekyll-inline-svg + - jekyll-relative-links + - jekyll-feed +site_url: https://gvisor.dev +feed: + path: blog/index.xml +svg: + optimize: true +defaults: + - scope: + path: "" + values: + layout: default +analytics: "UA-150193582-1" +authors: + jsprad: + name: Jeremiah Spradlin + email: jsprad@google.com + zkoopmans: + name: Zach Koopmans + email: zkoopmans@google.com + igudger: + name: Ian Gudger + email: igudger@google.com diff --git a/website/_includes/byline.html b/website/_includes/byline.html new file mode 100644 index 000000000..d8ae22cb0 --- /dev/null +++ b/website/_includes/byline.html @@ -0,0 +1,18 @@ +By +{% assign last_pos=include.authors.size | minus: 1 %} +{% assign and_pos=include.authors.size | minus: 2 %} +{% for i in (0..last_pos) %} + {% assign author_id=include.authors[i] %} + {% assign author=site.authors[author_id] %} + {% if author %} + {{ author.name }} + {% else %} + {{ author_id }} + {% endif %} + {% if i == and_pos %} + and + {% elsif i < and_pos %} + , + {% endif %} +{% endfor %} +on {{ include.date | date_to_long_string }} diff --git a/website/_includes/footer-links.html b/website/_includes/footer-links.html new file mode 100644 index 000000000..10c28ead4 --- /dev/null +++ b/website/_includes/footer-links.html @@ -0,0 +1,43 @@ +
+
+ +
+

Support

+ +
+ +
+ +
+
+
+

© {{ 'now' | date: "%Y" }} The gVisor Authors

+
+
+
diff --git a/website/_includes/footer.html b/website/_includes/footer.html new file mode 100644 index 000000000..5d9267f35 --- /dev/null +++ b/website/_includes/footer.html @@ -0,0 +1,72 @@ +
+ {% include footer-links.html %} +
+ + + + + + +{% if site.analytics %} + + +{% endif %} + + diff --git a/website/_includes/graph.html b/website/_includes/graph.html new file mode 100644 index 000000000..f3a999341 --- /dev/null +++ b/website/_includes/graph.html @@ -0,0 +1,205 @@ +{::nomarkdown} +{% assign fn = include.id | remove: " " | remove: "-" | downcase %} +
{{ include.title }}
+ +{:/} diff --git a/website/_includes/header-links.html b/website/_includes/header-links.html new file mode 100644 index 000000000..467bb1e72 --- /dev/null +++ b/website/_includes/header-links.html @@ -0,0 +1,19 @@ + diff --git a/website/_includes/header.html b/website/_includes/header.html new file mode 100644 index 000000000..c80310069 --- /dev/null +++ b/website/_includes/header.html @@ -0,0 +1,30 @@ + + + + + {% if page.title %} + {{ page.title }} - gVisor + {% else %} + gVisor + {% endif %} + + + + + + + + + + + + {% if page.title %} + + {% else %} + + {% endif %} + {% if page.description %} + + {% endif %} + + diff --git a/website/_includes/paginator.html b/website/_includes/paginator.html new file mode 100644 index 000000000..b4ff4c3b1 --- /dev/null +++ b/website/_includes/paginator.html @@ -0,0 +1,10 @@ + diff --git a/website/_includes/required_linux.html b/website/_includes/required_linux.html new file mode 100644 index 000000000..e9d1b7548 --- /dev/null +++ b/website/_includes/required_linux.html @@ -0,0 +1,2 @@ +> Note: gVisor supports only x86\_64 and requires Linux 4.14.77+ +> ([older Linux](/docs/user_guide/networking/#gso)). diff --git a/website/_layouts/base.html b/website/_layouts/base.html new file mode 100644 index 000000000..b30bee0dc --- /dev/null +++ b/website/_layouts/base.html @@ -0,0 +1,9 @@ + + + {% include header.html %} + + {% include header-links.html %} + {{ content }} + {% include footer.html %} + + diff --git a/website/_layouts/blog.html b/website/_layouts/blog.html new file mode 100644 index 000000000..6c371ab50 --- /dev/null +++ b/website/_layouts/blog.html @@ -0,0 +1,17 @@ +--- +layout: base +--- + +
+
+
+
+

{{ page.title }}

+ {% if page.feed %} + Feed  + {% endif %} + {{ content }} +
+
+
+
diff --git a/website/_layouts/default.html b/website/_layouts/default.html new file mode 100644 index 000000000..e5523e3fc --- /dev/null +++ b/website/_layouts/default.html @@ -0,0 +1,14 @@ +--- +layout: base +--- +{% if page.title %} +
+ +
+{% endif %} + +
+ {{ content }} +
diff --git a/website/_layouts/docs.html b/website/_layouts/docs.html new file mode 100644 index 000000000..e11492915 --- /dev/null +++ b/website/_layouts/docs.html @@ -0,0 +1,57 @@ +--- +layout: base +categories: + - Project + - User Guide + - Architecture Guide + - Compatibility +--- + +
+
+
+ +
+ +
+

{{ page.title }}

+ {% if page.editpath %} +

+ Edit this page + Create issue +

+ {% endif %} + {{ content }} +
+
+
diff --git a/website/_layouts/post.html b/website/_layouts/post.html new file mode 100644 index 000000000..640bee5af --- /dev/null +++ b/website/_layouts/post.html @@ -0,0 +1,10 @@ +--- +layout: blog +--- + +
+ {% include byline.html authors=page.authors date=page.date %} +
+
+ {{ content }} +
diff --git a/website/_plugins/svg_mime_type.rb b/website/_plugins/svg_mime_type.rb new file mode 100644 index 000000000..ad6bb6480 --- /dev/null +++ b/website/_plugins/svg_mime_type.rb @@ -0,0 +1,3 @@ +require 'webrick' +include WEBrick +WEBrick::HTTPUtils::DefaultMimeTypes.store 'svg', 'image/svg+xml' diff --git a/website/_sass/footer.scss b/website/_sass/footer.scss new file mode 100644 index 000000000..ec2ba5e20 --- /dev/null +++ b/website/_sass/footer.scss @@ -0,0 +1,15 @@ +.footer { + margin-top: 40px; + background-color: #222; + color: #fff; + padding: 20px; + + a { + color: $inverse-link-color; + + &:hover, + &:focus { + color: $inverse-link-hover-color; + } + } +} diff --git a/website/_sass/front.scss b/website/_sass/front.scss new file mode 100644 index 000000000..44a7e3473 --- /dev/null +++ b/website/_sass/front.scss @@ -0,0 +1,15 @@ +.jumbotron { + background-image: url(/assets/images/background.jpg); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + background-blend-mode: darken; + background-color: rgba(0, 0, 0, 0.1); + + p { + color: #fff; + margin-top: 0; + margin-bottom: 0; + font-weight: 300; + } +} diff --git a/website/_sass/navbar.scss b/website/_sass/navbar.scss new file mode 100644 index 000000000..65bc573ac --- /dev/null +++ b/website/_sass/navbar.scss @@ -0,0 +1,26 @@ +.navbar-inverse { + background-color: $primary; + border-bottom: 1px solid $primary; + + .navbar-brand > a { + color: #fff; + + &:focus, + &:hover { + color: #fff; + } + } + + .navbar-nav > li > a { + color: $inverse-link-color; + + &:focus, + &:hover { + color: $inverse-link-hover-color; + } + } + + .navbar-nav .nav-icon { + font-size: 18px; + } +} diff --git a/website/_sass/sidebar.scss b/website/_sass/sidebar.scss new file mode 100644 index 000000000..f4ca05df9 --- /dev/null +++ b/website/_sass/sidebar.scss @@ -0,0 +1,61 @@ +$sidebar-border-color: #fff; +$sidebar-hover-border-color: #66bb6a; + +.sidebar { + margin-top: 40px; + + ul.sidebar-nav { + list-style-type: none; + padding: 0; + transition: height 0.01s; + + li { + &.sidebar-nav-heading { + padding: 10px 0; + margin: 0; + display: block; + font-size: 16px; + font-weight: 300; + } + + a { + padding: 4px 0; + display: block; + border-right: 2px solid $sidebar-border-color; + + &:focus { + text-decoration: none; + } + + .caret { + float: right; + margin-top: 8px; + margin-right: 10px; + } + } + + &.active { + a { + border-left: 2px solid $sidebar-hover-border-color; + padding-left: 6px; + } + } + } + + ul.sidebar-nav { + padding-left: 10px; + } + } +} + +@media (min-width: 992px) { + .sidebar-toggle { + display: none; + } + + .sidebar { + &.collapse { + display: block; + } + } +} diff --git a/website/_sass/style.scss b/website/_sass/style.scss new file mode 100644 index 000000000..520ea469a --- /dev/null +++ b/website/_sass/style.scss @@ -0,0 +1,144 @@ +$primary: #262362; +$secondary: #fff; +$link-color: #286fd7; +$inverse-link-color: #fff; + +$link-hover-color: darken($link-color, 10%); +$inverse-link-hover-color: darken($inverse-link-color, 10%); + +$text-color: #444; + +$body-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; +$code-font-family: 'Source Code Pro', monospace; + +html { + position: relative; + min-height: 100%; +} + +body { + color: $text-color; + font-family: $body-font-family; + padding-top: 40px; +} + +a { + color: $link-color; + + &:hover, + &:focus { + color: $link-hover-color; + text-decoration: none; + } + + code { + color: $link-color; + } +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: $text-color; + font-weight: 400; +} + +h1 code, +h2 code, +h3 code, +h4 code, +h5 code, +h6 code { + color: $text-color; + background: transparent; +} + +h1 { + font-size: 30px; + margin-top: 40px; + margin-bottom: 40px; +} + +h2 { + font-size: 24px; + margin-top: 30px; + margin-bottom: 30px; + + code { + font-size: 24px; + } +} + +h3 { + font-size: 20px; + margin-top: 24px; + margin-bottom: 24px; + + code { + font-size: 20px; + } +} + +h4 { + font-size: 18px; + margin-top: 20px; + margin-bottom: 20px; + + code { + font-size: 18px; + } +} + +p, +li { + font-size: 14px; + line-height: 22px; +} + +code { + font-family: $code-font-family; + font-size: 13px; +} + +.btn { + color: $text-color; + background-color: $inverse-link-color; +} + +.btn-inverse { + color: $text-color; + background-color: #fff; +} + +.well { + box-shadow: none; +} + +table { + width: 100%; +} + +table td, +table th { + border: 1px solid #ddd; + padding: 8px; +} + +table tr:nth-child(even) { + background-color: #eee; +} + +table th { + padding-top: 12px; + padding-bottom: 12px; + background-color: $primary; + color: $secondary; +} + +.blog-meta { + margin-top: 10px; + margin-bottom: 20px; +} diff --git a/website/archive.key b/website/archive.key new file mode 100644 index 000000000..1a91698bf --- /dev/null +++ b/website/archive.key @@ -0,0 +1,29 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF0meAYBEACcBYPOSBiKtid+qTQlbgKGPxUYt0cNZiQqWXylhYUT4PuNlNx5 +s+sBLFvNTpdTrXMmZ8NkekyjD1HardWvebvJT4u+Ho/9jUr4rP71cNwNtocz/w8G +DsUXSLgH8SDkq6xw0L+5eGc78BBg9cOeBeFBm3UPgxTBXS9Zevoi2w1lzSxkXvjx +cGzltzMZfPXERljgLzp9AAfhg/2ouqVQm37fY+P/NDzFMJ1XHPIIp9KJl/prBVud +jJJteFZ5sgL6MwjBQq2kw+q2Jb8Zfjl0BeXDgGMN5M5lGhX2wTfiMbfo7KWyzRnB +RpSP3BxlLqYeQUuLG5Yx8z3oA3uBkuKaFOKvXtiScxmGM/+Ri2YM3m66imwDhtmP +AKwTPI3Re4gWWOffglMVSv2sUAY32XZ74yXjY1VhK3bN3WFUPGrgQx4X7GP0A1Te +lzqkT3VSMXieImTASosK5L5Q8rryvgCeI9tQLn9EpYFCtU3LXvVgTreGNEEjMOnL +dR7yOU+Fs775stn6ucqmdYarx7CvKUrNAhgEeHMonLe1cjYScF7NfLO1GIrQKJR2 +DE0f+uJZ52inOkO8ufh3WVQJSYszuS3HCY7w5oj1aP38k/y9zZdZvVvwAWZaiqBQ +iwjVs6Kub76VVZZhRDf4iYs8k1Zh64nXdfQt250d8U5yMPF3wIJ+c1yhxwARAQAB +tCpUaGUgZ1Zpc29yIEF1dGhvcnMgPGd2aXNvci1ib3RAZ29vZ2xlLmNvbT6JAlQE +EwEKAD4WIQRvHfheOnHCSRjnJ9VvxtVU4yvZQwUCXSZ4BgIbAwUJA8JnAAULCQgH +AgYVCgkICwIEFgIDAQIeAQIXgAAKCRBvxtVU4yvZQ5WFD/9VZXMW5I2rKV+2gTHT +CsW74kZVi1VFdAVYiUJZXw2jJNtcg3xdgBcscYPyecyka/6TS2q7q2fOGAzCZkcR +e3lLzkGAngMlZ7PdHAE0PDMNFaeMZW0dxNH68vn7AiA1y2XwENnxVec7iXQH6aX5 +xUNg2OCiv5f6DJItHc/Q4SvFUi8QK7TT/GYE1RJXVJlLqfO6y4V8SeqfM+FHpHZM +gzrwdTgsNiEm4lMjWcgb2Ib4i2JUVAjIRPfcpysiV5E7c3SPXyu4bOovKKlbhiJ1 +Q1M9M0zHik34Kjf4YNO1EW936j7Msd181CJt5Bl9XvlhPb8gey/ygpIvcicLx6M5 +lRJTy4z1TtkmtZ7E8EbJZWoPTaHlA6hoMtGeE35j3vMZN1qZYaYt26eFOxxhh7PA +J0h1lS7T2O8u1c2JKhKvajtdmbqbJgI8FRhVsMoVBnqDK5aE9MOAso36OibfweEL +8iV2z8JnBpWtbbUEaWro4knPtbLJbQFvXVietm3cFsbGg+DMIwI6x6HcU91IEFYI +Sv4orK7xgLuM+f6dxo/Wel3ht18dg3x3krBLALTYBidRfnQYYR3sTfLquB8b5WaY +o829L2Bop9GBygdLevkHHN5It6q8CVpn0H5HEJMNaDOX1LcPbf0CKwkkAVCBd9YZ +eAX38ds9LliK7XPXdC4c+zEkGA== +=x8TG +-----END PGP PUBLIC KEY BLOCK----- diff --git a/website/assets/favicons/apple-touch-icon-180x180.png b/website/assets/favicons/apple-touch-icon-180x180.png new file mode 100644 index 000000000..bf4b6ce9b Binary files /dev/null and b/website/assets/favicons/apple-touch-icon-180x180.png differ diff --git a/website/assets/favicons/favicon-16x16.png b/website/assets/favicons/favicon-16x16.png new file mode 100644 index 000000000..083264206 Binary files /dev/null and b/website/assets/favicons/favicon-16x16.png differ diff --git a/website/assets/favicons/favicon-32x32.png b/website/assets/favicons/favicon-32x32.png new file mode 100644 index 000000000..b8e4caff1 Binary files /dev/null and b/website/assets/favicons/favicon-32x32.png differ diff --git a/website/assets/favicons/favicon.ico b/website/assets/favicons/favicon.ico new file mode 100644 index 000000000..9238b79d9 Binary files /dev/null and b/website/assets/favicons/favicon.ico differ diff --git a/website/assets/favicons/pwa-192x192.png b/website/assets/favicons/pwa-192x192.png new file mode 100644 index 000000000..5d2fab785 Binary files /dev/null and b/website/assets/favicons/pwa-192x192.png differ diff --git a/website/assets/favicons/pwa-512x512.png b/website/assets/favicons/pwa-512x512.png new file mode 100644 index 000000000..23824439e Binary files /dev/null and b/website/assets/favicons/pwa-512x512.png differ diff --git a/website/assets/favicons/tile150x150.png b/website/assets/favicons/tile150x150.png new file mode 100644 index 000000000..f76fcffae Binary files /dev/null and b/website/assets/favicons/tile150x150.png differ diff --git a/website/assets/favicons/tile310x150.png b/website/assets/favicons/tile310x150.png new file mode 100644 index 000000000..4f87e4c12 Binary files /dev/null and b/website/assets/favicons/tile310x150.png differ diff --git a/website/assets/favicons/tile310x310.png b/website/assets/favicons/tile310x310.png new file mode 100644 index 000000000..a2926d0bd Binary files /dev/null and b/website/assets/favicons/tile310x310.png differ diff --git a/website/assets/favicons/tile70x70.png b/website/assets/favicons/tile70x70.png new file mode 100644 index 000000000..96cc69fc4 Binary files /dev/null and b/website/assets/favicons/tile70x70.png differ diff --git a/website/assets/images/2019-11-18-security-basics-figure1.png b/website/assets/images/2019-11-18-security-basics-figure1.png new file mode 100644 index 000000000..2a8134a7a Binary files /dev/null and b/website/assets/images/2019-11-18-security-basics-figure1.png differ diff --git a/website/assets/images/2019-11-18-security-basics-figure2.png b/website/assets/images/2019-11-18-security-basics-figure2.png new file mode 100644 index 000000000..f8b416e1d Binary files /dev/null and b/website/assets/images/2019-11-18-security-basics-figure2.png differ diff --git a/website/assets/images/2019-11-18-security-basics-figure3.png b/website/assets/images/2019-11-18-security-basics-figure3.png new file mode 100644 index 000000000..833e3e2b5 Binary files /dev/null and b/website/assets/images/2019-11-18-security-basics-figure3.png differ diff --git a/website/assets/images/2020-04-02-networking-security-figure1.png b/website/assets/images/2020-04-02-networking-security-figure1.png new file mode 100644 index 000000000..b49cb0242 Binary files /dev/null and b/website/assets/images/2020-04-02-networking-security-figure1.png differ diff --git a/website/assets/images/background.jpg b/website/assets/images/background.jpg new file mode 100644 index 000000000..81f8e332b Binary files /dev/null and b/website/assets/images/background.jpg differ diff --git a/website/assets/logos/Makefile b/website/assets/logos/Makefile new file mode 100644 index 000000000..49289ecc1 --- /dev/null +++ b/website/assets/logos/Makefile @@ -0,0 +1,13 @@ +#!/usr/bin/make -f + +srcs := $(wildcard *.svg) +dsts := $(patsubst %.svg,%.png,$(srcs)) + +all: $(dsts) +.PHONY: all + +%.png %-16.png %-128.png %-1024.png: %.svg + @inkscape -z -e $*.png $< + @inkscape -z -w 16 -e $*-16.png $< + @inkscape -z -w 128 -e $*-128.png $< + @inkscape -z -w 1024 -e $*-1024.png $< diff --git a/website/assets/logos/README.md b/website/assets/logos/README.md new file mode 100644 index 000000000..2964982dd --- /dev/null +++ b/website/assets/logos/README.md @@ -0,0 +1,10 @@ +# Logos + +This directory contains logo assets. + +The colors used are: + +* Background (blue): #262262 +* Highlight (yellow): #FBB03B + +Use `make` to generate sized PNGs from SVGs. diff --git a/website/assets/logos/logo_solo_monochrome.png b/website/assets/logos/logo_solo_monochrome.png new file mode 100644 index 000000000..e09c5ad5e Binary files /dev/null and b/website/assets/logos/logo_solo_monochrome.png differ diff --git a/website/assets/logos/logo_solo_monochrome.svg b/website/assets/logos/logo_solo_monochrome.svg new file mode 100644 index 000000000..73126fd8f --- /dev/null +++ b/website/assets/logos/logo_solo_monochrome.svg @@ -0,0 +1,73 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_solo_on_dark-1024.png b/website/assets/logos/logo_solo_on_dark-1024.png new file mode 100644 index 000000000..6df428c65 Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark-1024.png differ diff --git a/website/assets/logos/logo_solo_on_dark-128.png b/website/assets/logos/logo_solo_on_dark-128.png new file mode 100644 index 000000000..78a85475f Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark-128.png differ diff --git a/website/assets/logos/logo_solo_on_dark-16.png b/website/assets/logos/logo_solo_on_dark-16.png new file mode 100644 index 000000000..4f1e91c02 Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark-16.png differ diff --git a/website/assets/logos/logo_solo_on_dark.png b/website/assets/logos/logo_solo_on_dark.png new file mode 100644 index 000000000..da20756f7 Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark.png differ diff --git a/website/assets/logos/logo_solo_on_dark.svg b/website/assets/logos/logo_solo_on_dark.svg new file mode 100644 index 000000000..ae8d9e879 --- /dev/null +++ b/website/assets/logos/logo_solo_on_dark.svg @@ -0,0 +1,73 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_solo_on_dark_full-1024.png b/website/assets/logos/logo_solo_on_dark_full-1024.png new file mode 100644 index 000000000..8d597dd3d Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark_full-1024.png differ diff --git a/website/assets/logos/logo_solo_on_dark_full-128.png b/website/assets/logos/logo_solo_on_dark_full-128.png new file mode 100644 index 000000000..fe6dd5dea Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark_full-128.png differ diff --git a/website/assets/logos/logo_solo_on_dark_full-16.png b/website/assets/logos/logo_solo_on_dark_full-16.png new file mode 100644 index 000000000..f9aa7dfdd Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark_full-16.png differ diff --git a/website/assets/logos/logo_solo_on_dark_full.png b/website/assets/logos/logo_solo_on_dark_full.png new file mode 100644 index 000000000..611b0565e Binary files /dev/null and b/website/assets/logos/logo_solo_on_dark_full.png differ diff --git a/website/assets/logos/logo_solo_on_dark_full.svg b/website/assets/logos/logo_solo_on_dark_full.svg new file mode 100644 index 000000000..6440835b1 --- /dev/null +++ b/website/assets/logos/logo_solo_on_dark_full.svg @@ -0,0 +1,79 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_solo_on_white.png b/website/assets/logos/logo_solo_on_white.png new file mode 100644 index 000000000..ca539cdff Binary files /dev/null and b/website/assets/logos/logo_solo_on_white.png differ diff --git a/website/assets/logos/logo_solo_on_white.svg b/website/assets/logos/logo_solo_on_white.svg new file mode 100644 index 000000000..d794ad8e7 --- /dev/null +++ b/website/assets/logos/logo_solo_on_white.svg @@ -0,0 +1,73 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_solo_on_white_bordered-1024.png b/website/assets/logos/logo_solo_on_white_bordered-1024.png new file mode 100644 index 000000000..62bb88d50 Binary files /dev/null and b/website/assets/logos/logo_solo_on_white_bordered-1024.png differ diff --git a/website/assets/logos/logo_solo_on_white_bordered-128.png b/website/assets/logos/logo_solo_on_white_bordered-128.png new file mode 100644 index 000000000..a8988766c Binary files /dev/null and b/website/assets/logos/logo_solo_on_white_bordered-128.png differ diff --git a/website/assets/logos/logo_solo_on_white_bordered-16.png b/website/assets/logos/logo_solo_on_white_bordered-16.png new file mode 100644 index 000000000..a545c49cf Binary files /dev/null and b/website/assets/logos/logo_solo_on_white_bordered-16.png differ diff --git a/website/assets/logos/logo_solo_on_white_bordered.png b/website/assets/logos/logo_solo_on_white_bordered.png new file mode 100644 index 000000000..cc99b7c51 Binary files /dev/null and b/website/assets/logos/logo_solo_on_white_bordered.png differ diff --git a/website/assets/logos/logo_solo_on_white_bordered.svg b/website/assets/logos/logo_solo_on_white_bordered.svg new file mode 100644 index 000000000..2e26f144a --- /dev/null +++ b/website/assets/logos/logo_solo_on_white_bordered.svg @@ -0,0 +1,82 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_with_text_monochrome.png b/website/assets/logos/logo_with_text_monochrome.png new file mode 100644 index 000000000..17442f55d Binary files /dev/null and b/website/assets/logos/logo_with_text_monochrome.png differ diff --git a/website/assets/logos/logo_with_text_monochrome.svg b/website/assets/logos/logo_with_text_monochrome.svg new file mode 100644 index 000000000..4648e06c0 --- /dev/null +++ b/website/assets/logos/logo_with_text_monochrome.svg @@ -0,0 +1,116 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_with_text_on_dark-1024.png b/website/assets/logos/logo_with_text_on_dark-1024.png new file mode 100644 index 000000000..a02a9014b Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark-1024.png differ diff --git a/website/assets/logos/logo_with_text_on_dark-128.png b/website/assets/logos/logo_with_text_on_dark-128.png new file mode 100644 index 000000000..efae725b8 Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark-128.png differ diff --git a/website/assets/logos/logo_with_text_on_dark-16.png b/website/assets/logos/logo_with_text_on_dark-16.png new file mode 100644 index 000000000..a6069f98f Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark-16.png differ diff --git a/website/assets/logos/logo_with_text_on_dark.png b/website/assets/logos/logo_with_text_on_dark.png new file mode 100644 index 000000000..24de18c11 Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark.png differ diff --git a/website/assets/logos/logo_with_text_on_dark.svg b/website/assets/logos/logo_with_text_on_dark.svg new file mode 100644 index 000000000..52d8e52da --- /dev/null +++ b/website/assets/logos/logo_with_text_on_dark.svg @@ -0,0 +1,116 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_with_text_on_dark_full-1024.png b/website/assets/logos/logo_with_text_on_dark_full-1024.png new file mode 100644 index 000000000..eb2e63981 Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark_full-1024.png differ diff --git a/website/assets/logos/logo_with_text_on_dark_full-128.png b/website/assets/logos/logo_with_text_on_dark_full-128.png new file mode 100644 index 000000000..4ed21e5cb Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark_full-128.png differ diff --git a/website/assets/logos/logo_with_text_on_dark_full-16.png b/website/assets/logos/logo_with_text_on_dark_full-16.png new file mode 100644 index 000000000..d3968da5e Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark_full-16.png differ diff --git a/website/assets/logos/logo_with_text_on_dark_full.png b/website/assets/logos/logo_with_text_on_dark_full.png new file mode 100644 index 000000000..21feea356 Binary files /dev/null and b/website/assets/logos/logo_with_text_on_dark_full.png differ diff --git a/website/assets/logos/logo_with_text_on_dark_full.svg b/website/assets/logos/logo_with_text_on_dark_full.svg new file mode 100644 index 000000000..017e72414 --- /dev/null +++ b/website/assets/logos/logo_with_text_on_dark_full.svg @@ -0,0 +1,120 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_with_text_on_white.png b/website/assets/logos/logo_with_text_on_white.png new file mode 100644 index 000000000..bf420a057 Binary files /dev/null and b/website/assets/logos/logo_with_text_on_white.png differ diff --git a/website/assets/logos/logo_with_text_on_white.svg b/website/assets/logos/logo_with_text_on_white.svg new file mode 100644 index 000000000..4275efe83 --- /dev/null +++ b/website/assets/logos/logo_with_text_on_white.svg @@ -0,0 +1,116 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/logo_with_text_on_white_bordered.png b/website/assets/logos/logo_with_text_on_white_bordered.png new file mode 100644 index 000000000..bd1a1e4b7 Binary files /dev/null and b/website/assets/logos/logo_with_text_on_white_bordered.png differ diff --git a/website/assets/logos/logo_with_text_on_white_bordered.svg b/website/assets/logos/logo_with_text_on_white_bordered.svg new file mode 100644 index 000000000..08125629d --- /dev/null +++ b/website/assets/logos/logo_with_text_on_white_bordered.svg @@ -0,0 +1,122 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/website/assets/logos/powered-gvisor.png b/website/assets/logos/powered-gvisor.png new file mode 100644 index 000000000..e00c74a33 Binary files /dev/null and b/website/assets/logos/powered-gvisor.png differ diff --git a/website/blog/2019-11-18-security-basics.md b/website/blog/2019-11-18-security-basics.md new file mode 100644 index 000000000..ed6d97ffe --- /dev/null +++ b/website/blog/2019-11-18-security-basics.md @@ -0,0 +1,319 @@ +# gVisor Security Basics - Part 1 + +This blog is a space for engineers and community members to share perspectives +and deep dives on technology and design within the gVisor project. Though our +logo suggests we're in the business of space exploration (or perhaps fighting +sea monsters), we're actually in the business of sandboxing Linux containers. +When we created gVisor, we had three specific goals in mind; _container-native +security_, _resource efficiency_, and _platform portability_. To put it simply, +gVisor provides _efficient defense-in-depth for containers anywhere_. + +This post addresses gVisor's _container-native security_, specifically how +gVisor provides strong isolation between an application and the host OS. Future +posts will address _resource efficiency_ (how gVisor preserves container +benefits like fast starts, smaller snapshots, and less memory overhead than VMs) +and _platform portability_ (run gVisor wherever Linux OCI containers run). +Delivering on each of these goals requires careful security considerations and a +robust design. + +## What does "sandbox" mean? + +gVisor allows the execution of untrusted containers, preventing them from +adversely affecting the host. This means that the untrusted container is +prevented from attacking or spying on either the host kernel or any other peer +userspace processes on the host. + +For example, if you are a cloud container hosting service, running containers +from different customers on the same virtual machine means that compromises +expose customer data. Properly configured, gVisor can provide sufficient +isolation to allow different customers to run containers on the same host. There +are many aspects to the proper configuration, including limiting file and +network access, which we will discuss in future posts. + +## The cost of compromise + +gVisor was designed around the premise that any security boundary could +potentially be compromised with enough time and resources. We tried to optimize +for a solution that was as costly and time-consuming for an attacker as +possible, at every layer. + +Consequently, gVisor was built through a combination of intentional design +principles and specific technology choices that work together to provide the +security isolation needed for running hostile containers on a host. We'll dig +into it in the next section! + +# Design Principles + +gVisor was designed with some +[common secure design principles](https://www.owasp.org/index.php/Security_by_Design_Principles) +in mind: Defense-in-Depth, Principle of Least-Privilege, Attack Surface +Reduction and Secure-by-Default[^1]. + +In general, Design Principles outline good engineering practices, but in the +case of security, they also can be thought of as a set of tactics. In a +real-life castle, there is no single defensive feature. Rather, there are many +in combination: redundant walls, scattered draw bridges, small bottle-neck +entrances, moats, etc. + +A simplified version of the design is below +([more detailed version](/docs/architecture_guide/))[^2]: + +-------------------------------------------------------------------------------- + +![Figure 1](/assets/images/2019-11-18-security-basics-figure1.png) + +Figure 1: Simplified design of gVisor. + +-------------------------------------------------------------------------------- + +In order to discuss design principles, the following components are important to +know: + +* runsc - binary that packages the Sentry, platform, and Gofer(s) that run + containers. runsc is the drop-in binary for running gVisor in Docker and + Kubernetes. +* Untrusted Application - container running in the sandbox. Untrusted + application/container are used interchangeably in this article. +* Platform Syscall Switcher - intercepts syscalls from the application and + passes them to the Sentry with no further handling. +* Sentry - The "application kernel" in userspace that serves the untrusted + application. Each application instance has its own Sentry. The Sentry + handles syscalls, routes I/O to gofers, and manages memory and CPU, all in + userspace. The Sentry is allowed to make limited, filtered syscalls to the + host OS. +* Gofer - a process that specifically handles different types of I/O for the + Sentry (usually disk I/O). Gofers are also allowed to make filtered syscalls + to the Host OS. +* Host OS - the actual OS on which gVisor containers are running, always some + flavor of Linux (sorry, Windows/MacOS users). + +It is important to emphasize what is being protected from the untrusted +application in this diagram: the host OS and other userspace applications. + +In this post, we are only discussing security-related features of gVisor, and +you might ask, "What about performance, compatibility and stability?" We will +cover these considerations in future posts. + +## Defense-in-Depth + +For gVisor, Defense-in-Depth means each component of the software stack trusts +the other components as little as possible. + +It may seem strange that we would want our own software components to distrust +each other. But by limiting the trust between small, discrete components, each +component is forced to defend itself against potentially malicious input. And +when you stack these components on top of each other, you can ensure that +multiple security barriers must be overcome by an attacker. + +And this leads us to how Defense-in-Depth is applied to gVisor: no single +vulnerability should compromise the host. + +In the "Attacker's Advantage / Defender's Dilemma," the defender must succeed +all the time while the attacker only needs to succeed once. Defense in Depth +inverts this principle: once the attacker successfully compromises any given +software component, they are immediately faced with needing to compromise a +subsequent, distinct layer in order to move laterally or acquire more privilege. + +For example, the untrusted container is isolated from the Sentry. The Sentry is +isolated from host I/O operations by serving those requests in separate +processes called Gofers. And both the untrusted container and its associated +Gofers are isolated from the host process that is running the sandbox. + +An additional benefit is that this generally leads to more robust and stable +software, forcing interfaces to be strictly defined and tested to ensure all +inputs are properly parsed and bounds checked. + +## Least-Privilege + +The principle of Least-Privilege implies that each software component has only +the permissions it needs to function, and no more. + +Least-Privilege is applied throughout gVisor. Each component and more +importantly, each interface between the components, is designed so that only the +minimum level of permission is required for it to perform its function. +Specifically, the closer you are to the untrusted application, the less +privilege you have. + +-------------------------------------------------------------------------------- + +![Figure 2](/assets/images/2019-11-18-security-basics-figure2.png) + +Figure 2: runsc components and their privileges. + +-------------------------------------------------------------------------------- + +This is evident in how runsc (the drop in gVisor binary for Docker/Kubernetes) +constructs the sandbox. The Sentry has the least privilege possible (it can't +even open a file!). Gofers are only allowed file access, so even if it were +compromised, the host network would be unavailable. Only the runsc binary itself +has full access to the host OS, and even runsc's access to the host OS is often +limited through capabilities / chroot / namespacing. + +Designing a system with Defense-in-Depth and Least-Privilege in mind encourages +small, separate, single-purpose components, each with very restricted +privileges. + +## Attack Surface Reduction + +There are no bugs in unwritten code. In other words, gVisor supports a feature +if and only if it is needed to run host Linux containers. + +### Host Application/Sentry Interface: + +There are a lot of things gVisor does not need to do. For example, it does not +need to support arbitrary device drivers, nor does it need to support video +playback. By not implementing what will not be used, we avoid introducing +potential bugs in our code. + +That is not to say gVisor has limited functionality! Quite the opposite, we +analyzed what is actually needed to run Linux containers and today the Sentry +supports 237 syscalls[^3],[^4], along with the range of critical +/proc and /dev files. However, gVisor does not support every syscall in the +Linux kernel. There are about 350 syscalls[^5] within the 5.3.11 version of the +Linux kernel, many of which do not apply to Linux containers that typically host +cloud-like workloads. For example, we don't support old versions of epoll +(epoll_ctl_old, epoll_wait_old), because they are deprecated in Linux and no +supported workloads use them. + +Furthermore, any exploited vulnerabilities in the implemented syscalls (or +Sentry code in general) only apply to gaining control of the Sentry. More on +this in a later post. + +### Sentry/Host OS Interface: + +The Sentry's interactions with the Host OS are restricted in many ways. For +instance, no syscall is "passed-through" from the untrusted application to the +host OS. All syscalls are intercepted and interpreted. In the case where the +Sentry needs to call the Host OS, we severely limit the syscalls that the Sentry +itself is allowed to make to the host kernel[^6]. + +For example, there are many file-system based attacks, where manipulation of +files or their paths, can lead to compromise of the host[^7]. As a result, the +Sentry does not allow any syscall that creates or opens a file descriptor. All +file descriptors must be donated to the sandbox. By disallowing open or creation +of file descriptors, we eliminate entire categories of these file-based attacks. + +This does not affect functionality though. For example, during startup, runsc +will donate FDs the Sentry that allow for mapping STDIN/STDOUT/STDERR to the +sandboxed application. Also the Gofer may donate an FD to the Sentry, allowing +for direct access to some files. And most files will be remotely accessed +through the Gofers, in which case no FDs are donated to the Sentry. + +The Sentry itself is only allowed access to specific +[whitelisted syscalls](https://github.com/google/gvisor/blob/master/runsc/boot/config.go). +Without networking, the Sentry needs 53 host syscalls in order to function, and +with networking, it uses an additional 15[^8]. By limiting the whitelist to only +these needed syscalls, we radically reduce the amount of host OS attack surface. +If any attempts are made to call something outside the whitelist, it is +immediately blocked and the sandbox is killed by the Host OS. + +### Sentry/Gofer Interface: + +The Sentry communicates with the Gofer through a local unix domain socket (UDS) +via a version of the 9P protocol[^9]. The UDS file descriptor is passed to the +sandbox during initialization and all communication between the Sentry and Gofer +happens via 9P. We will go more into how Gofers work in future posts. + +### End Result + +So, of the 350 syscalls in the Linux kernel, the Sentry needs to implement only +237 of them to support containers. At most, the Sentry only needs to call 68 of +the host Linux syscalls. In other words, with gVisor, applications get the vast +majority (and growing) functionality of Linux containers for only 68 possible +syscalls to the Host OS. 350 syscalls to 68 is attack surface reduction. + +-------------------------------------------------------------------------------- + +![Figure 3](/assets/images/2019-11-18-security-basics-figure3.png) + +Figure 3: Reduction of Attack Surface of the Syscall Table. Note that the +Senty's Syscall Emulation Layer keeps the Containerized Process from ever +calling the Host OS. + +-------------------------------------------------------------------------------- + +## Secure-by-default + +The default choice for a user should be safe. If users need to run a less secure +configuration of the sandbox for the sake of performance or application +compatibility, they must make the choice explicitly. + +An example of this might be a networking application that is performance +sensitive. Instead of using the safer, Go-based Netstack in the Sentry, the +untrusted container can instead use the host Linux networking stack directly. +However, this means the untrusted container will be directly interacting with +the host, without the safety benefits of the sandbox. It also means that an +attack could directly compromise the host through his path. + +These less secure configurations are **not** the default. In fact, the user must +take action to change the configuration and run in a less secure mode. +Additionally, these actions make it very obvious that a less secure +configuration is being used. + +This can be as simple as forcing a default runtime flag option to the secure +option. gVisor does this by always using its internal netstack by default. +However, for certain performance sensitive applications, we allow the usage of +the host OS networking stack, but it requires the user to actively set a +flag[^10]. + +# Technology Choices + +Technology choices for gVisor mainly involve things that will give us a security +boundary. + +At a higher level, boundaries in software might be describing a great many +things. It may be discussing the boundaries between threads, boundaries between +processes, boundaries between CPU privilege levels, and more. + +Security boundaries are interfaces that are designed and built so that entire +classes of bugs/vulnerabilities are eliminated. + +For example, the Sentry and Gofers are implemented using Go. Go was chosen for a +number of the features it provided. Go is a fast, statically-typed, compiled +language that has efficient multi-threading support, garbage collection and a +constrained set of "unsafe" operations. + +Using these features enabled safe array and pointer handling. This means entire +classes of vulnerabilities were eliminated, such as buffer overflows and +use-after-free. + +Another example is our use of very strict syscall switching to ensure that the +Sentry is always the first software component that parses and interprets the +calls being made by the untrusted container. Here is an instance where different +platforms use different solutions, but all of them share this common trait, +whether it is through the use of ptrace "a la PTRACE_ATTACH"[^11] or kvm's +ring0[^12]. + +Finally, one of the most restrictive choices was to use seccomp, to restrict the +Sentry from being able to open or create a file descriptor on the host. All file +I/O is required to go through Gofers. Preventing the opening or creation of file +descriptions eliminates whole categories of bugs around file permissions +[like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557)[^13]. + +# To be continued - Part 2 + +In part 2 of this blog post, we will explore gVisor from an attacker's point of +view. We will use it as an opportunity to examine the specific strengths and +weaknesses of each gVisor component. + +We will also use it to introduce Google's Vulnerability Reward Program[^14], and +other ways the community can contribute to help make gVisor safe, fast and +stable. + +## Notes + +[^1]: [https://www.owasp.org/index.php/Security_by_Design_Principles](https://www.owasp.org/index.php/Security_by_Design_Principles) +[^2]: [https://gvisor.dev/docs/architecture_guide](https://gvisor.dev/docs/architecture_guide/) +[^3]: [https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/linux/linux64_amd64.go](https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/syscalls.go) +[^4]: Internally that is, it doesn't call to the Host OS to implement them, in + fact that is explicitly disallowed, more on that in the future. +[^5]: [https://elixir.bootlin.com/linux/latest/source/arch/x86/entry/syscalls/syscall_64.tbl#L345](https://elixir.bootlin.com/linux/latest/source/arch/x86/entry/syscalls/syscall_64.tbl#L345) +[^6]: [https://github.com/google/gvisor/tree/master/runsc/boot/filter](https://github.com/google/gvisor/tree/master/runsc/boot/filter) +[^7]: [https://en.wikipedia.org/wiki/Dirty_COW](https://en.wikipedia.org/wiki/Dirty_COW) +[^8]: [https://github.com/google/gvisor/blob/master/runsc/boot/config.go](https://github.com/google/gvisor/blob/master/runsc/boot/config.go) +[^9]: [https://en.wikipedia.org/wiki/9P_(protocol)](https://en.wikipedia.org/wiki/9P_\(protocol\)) +[^10]: [https://gvisor.dev/docs/user_guide/networking/#network-passthrough](https://gvisor.dev/docs/user_guide/networking/#network-passthrough) +[^11]: [https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390) +[^12]: [https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182) +[^13]: [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557) +[^14]: [https://www.google.com/about/appsecurity/reward-program/index.html](https://www.google.com/about/appsecurity/reward-program/index.html) diff --git a/website/blog/2020-04-02-networking-security.md b/website/blog/2020-04-02-networking-security.md new file mode 100644 index 000000000..78f0a6714 --- /dev/null +++ b/website/blog/2020-04-02-networking-security.md @@ -0,0 +1,189 @@ +# gVisor Networking Security + +In our +[first blog post](https://gvisor.dev/blog/2019/11/18/gvisor-security-basics-part-1/), +we covered some secure design principles and how they guided the architecture of +gVisor as a whole. In this post, we will cover how these principles guided the +networking architecture of gVisor, and the tradeoffs involved. In particular, we +will cover how these principles culminated in two networking modes, how they +work, and the properties of each. + +## gVisor's security architecture in the context of networking + +Linux networking is complicated. The TCP protocol is over 40 years old, and has +been repeatedly extended over the years to keep up with the rapid pace of +network infrastructure improvements, all while maintaining compatibility. On top +of that, Linux networking has a fairly large API surface. Linux supports +[over 150 options](https://github.com/google/gvisor/blob/960f6a975b7e44c0efe8fd38c66b02017c4fe137/pkg/sentry/strace/socket.go#L476-L644) +for the most common socket types alone. In fact, the net subsystem is one of the +largest and fastest growing in Linux at approximately 1.1 million lines of code. +For comparison, that is several times the size of the entire gVisor codebase. + +At the same time, networking is increasingly important. The cloud era is +arguably about making everything a network service, and in order to make that +work, the interconnect performance is critical. Adding networking support to +gVisor was difficult, not just due to the inherent complexity, but also because +it has the potential to significantly weaken gVisor's security model. + +As outlined in the previous blog post, gVisor's +[secure design principles](https://gvisor.dev/blog/2019/11/18/gvisor-security-basics-part-1/#design-principles) +are: + +1. Defense in Depth: each component of the software stack trusts each other + component as little as possible. +1. Least Privilege: each software component has only the permissions it needs + to function, and no more. +1. Attack Surface Reduction: limit the surface area of the host exposed to the + sandbox. +1. Secure by Default: the default choice for a user should be safe. + +gVisor manifests these principles as a multi-layered system. An application +running in the sandbox interacts with the Sentry, a userspace kernel, which +mediates all interactions with the Host OS and beyond. The Sentry is written in +pure Go with minimal unsafe code, making it less vulnerable to buffer overflows +and related memory bugs that can lead to a variety of compromises including code +injection. It emulates Linux using only a minimal and audited set of Host OS +syscalls that limit the Host OS's attack surface exposed to the Sentry itself. +The syscall restrictions are enforced by running the Sentry with seccomp +filters, which enforce that the Sentry can only use the expected set of +syscalls. The Sentry runs as an unprivileged user and in namespaces, which, +along with the seccomp filters, ensure that the Sentry is run with the Least +Privilege required. + +gVisor's multi-layered design provides Defense in Depth. The Sentry, which does +not trust the application because it may attack the Sentry and try to bypass it, +is the first layer. The sandbox that the Sentry runs in is the second layer. If +the Sentry were compromised, the attacker would still be in a highly restrictive +sandbox which they must also break out of in order to compromise the Host OS. + +To enable networking functionality while preserving gVisor's security +properties, we implemented a +[userspace network stack](https://github.com/google/gvisor/tree/master/pkg/tcpip) +in the Sentry, which we creatively named Netstack. Netstack is also written in +Go, not only to avoid unsafe code in the network stack itself, but also to avoid +a complicated and unsafe Foreign Function Interface. Having its own integrated +network stack allows the Sentry to implement networking operations using up to +three Host OS syscalls to read and write packets. These syscalls allow a very +minimal set of operations which are already allowed (either through the same or +a similar syscall). Moreover, because packets typically come from off-host (e.g. +the internet), the Host OS's packet processing code has received a lot of +scrutiny, hopefully resulting in a high degree of hardening. + +-------------------------------------------------------------------------------- + +![Figure 1](/assets/images/2020-04-02-networking-security-figure1.png) + +Figure 1: Netstack and gVisor + +-------------------------------------------------------------------------------- + +## Writing a network stack + +Netstack was written from scratch specifically for gVisor. Because Netstack was +designed and implemented to be modular, flexible and self-contained, there are +now several more projects using Netstack in creative and exciting ways. As we +discussed, a custom network stack has enabled a variety of security-related +goals which would not have been possible any other way. This came at a cost +though. Network stacks are complex and writing a new one comes with many +challenges, mostly related to application compatibility and performance. + +Compatibility issues typically come in two forms: missing features, and features +with behavior that differs from Linux (usually due to bugs). Both of these are +inevitable in an implementation of a complex system spanning many quickly +evolving and ambiguous standards. However, we have invested heavily in this +area, and the vast majority of applications have no issues using Netstack. For +example, +[we now support setting 34 different socket options](https://github.com/google/gvisor/blob/815df2959a76e4a19f5882e40402b9bbca9e70be/pkg/sentry/socket/netstack/netstack.go#L830-L1764) +versus +[only 7 in our initial git commit](https://github.com/google/gvisor/blob/d02b74a5dcfed4bfc8f2f8e545bca4d2afabb296/pkg/sentry/socket/epsocket/epsocket.go#L445-L702). +We are continuing to make good progress in this area. + +Performance issues typically come from TCP behavior and packet processing speed. +To improve our TCP behavior, we are working on implementing the full set of TCP +RFCs. There are many RFCs which are significant to performance (e.g. +[RACK](https://tools.ietf.org/id/draft-ietf-tcpm-rack-03.html) and +[BBR](https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00)) +that we have yet to implement. This mostly affects TCP performance with +non-ideal network conditions (e.g. cross continent connections). Faster packet +processing mostly improves TCP performance when network conditions are very good +(e.g. within a datacenter). Our primary strategy here is to reduce interactions +with the Go runtime, specifically the garbage collector (GC) and scheduler. We +are currently optimizing buffer management to reduce the amount of garbage, +which will lower the GC cost. To reduce scheduler interactions, we are +re-architecting the TCP implementation to use fewer goroutines. Performance +today is good enough for most applications and we are making steady +improvements. For example, since May of 2019, we have improved the Netstack +runsc +[iperf3 download benchmark](https://github.com/google/gvisor/blob/master/benchmarks/suites/network.py) +score by roughly 15% and upload score by around 10,000X. Current numbers are +about 17 Gbps download and about 8 Gbps upload versus about 42 Gbps and 43 Gbps +for native (Linux) respectively. + +## An alternative + +We also offer an alternative network mode: passthrough. This name can be +misleading as syscalls are never passed through from the app to the Host OS. +Instead, the passthrough mode implements networking in gVisor using the Host +OS's network stack. (This mode is called +[hostinet](https://github.com/google/gvisor/tree/master/pkg/sentry/socket/hostinet) +in the codebase.) Passthrough mode can improve performance for some use cases as +the Host OS's network stack has had an enormous number of person-years poured +into making it highly performant. However, there is a rather large downside to +using passthrough mode: it weakens gVisor's security model by increasing the +Host OS's Attack Surface. This is because using the Host OS's network stack +requires the Sentry to use the Host OS's +[Berkeley socket interface](https://en.wikipedia.org/wiki/Berkeley_sockets). The +Berkeley socket interface is a much larger API surface than the packet interface +that our network stack uses. When passthrough mode is in use, the Sentry is +allowed to use +[15 additional syscalls](https://github.com/google/gvisor/blob/b1576e533223e98ebe4bd1b82b04e3dcda8c4bf1/runsc/boot/filter/config.go#L312-L517). +Further, this set of syscalls includes some that allow the Sentry to create file +descriptors, something that +[we don't normally allow](https://gvisor.dev/blog/2019/11/18/gvisor-security-basics-part-1/#sentry-host-os-interface) +as it opens up classes of file-based attacks. + +There are some networking features that we can't implement on top of syscalls +that we feel are safe (most notably those behind +[ioctl](http://man7.org/linux/man-pages/man2/ioctl.2.html)) and therefore are +not supported. Because of this, we actually support fewer networking features in +passthrough mode than we do in Netstack, reducing application compatibility. +That's right: using our networking stack provides better overall application +compatibility than using our passthrough mode. + +That said, gVisor with passthrough networking still provides a high level of +isolation. Applications cannot specify host syscall arguments directly, and the +sentry's seccomp policy restricts its syscall use significantly more than a +general purpose seccomp policy. + +## Secure by Default + +The goal of the Secure by Default principle is to make it easy to securely +sandbox containers. Of course, disabling network access entirely is the most +secure option, but that is not practical for most applications. To make gVisor +Secure by Default, we have made Netstack the default networking mode in gVisor +as we believe that it provides significantly better isolation. For this reason +we strongly caution users from changing the default unless Netstack flat out +won't work for them. The passthrough mode option is still provided, but we want +users to make an informed decision when selecting it. + +Another way in which gVisor makes it easy to securely sandbox containers is by +allowing applications to run unmodified, with no special configuration needed. +In order to do this, gVisor needs to support all of the features and syscalls +that applications use. Neither seccomp nor gVisor's passthrough mode can do this +as applications commonly use syscalls which are too dangerous to be included in +a secure policy. Even if this dream isn't fully realized today, gVisor's +architecture with Netstack makes this possible. + +## Give Netstack a Try + +If you haven't already, try running a workload in gVisor with Netstack. You can +find instructions on how to get started in our +[Quick Start](/docs/user_guide/quick_start/docker/). We want to hear about both +your successes and any issues you encounter. We welcome your contributions, +whether that be verbal feedback or code contributions, via our +[Gitter channel](https://gitter.im/gvisor/community), +[email list](https://groups.google.com/forum/#!forum/gvisor-users), +[issue tracker](https://gvisor.dev/issue/new), and +[Github repository](https://github.com/google/gvisor). Feel free to express +interest in an [open issue](https://gvisor.dev/issue/), or reach out if you +aren't sure where to start. diff --git a/website/blog/BUILD b/website/blog/BUILD new file mode 100644 index 000000000..01c1f5a6e --- /dev/null +++ b/website/blog/BUILD @@ -0,0 +1,37 @@ +load("//website:defs.bzl", "doc", "docs") + +package( + default_visibility = ["//website:__pkg__"], + licenses = ["notice"], +) + +exports_files(["index.html"]) + +doc( + name = "security_basics", + src = "2019-11-18-security-basics.md", + authors = [ + "jsprad", + "zkoopmans", + ], + layout = "post", + permalink = "/blog/2019/11/18/gvisor-security-basics-part-1/", +) + +doc( + name = "networking_security", + src = "2020-04-02-networking-security.md", + authors = [ + "igudger", + ], + layout = "post", + permalink = "/blog/2020/04/02/gvisor-networking-security/", +) + +docs( + name = "posts", + deps = [ + ":" + rule + for rule in existing_rules() + ], +) diff --git a/website/blog/index.html b/website/blog/index.html new file mode 100644 index 000000000..5c67c95fc --- /dev/null +++ b/website/blog/index.html @@ -0,0 +1,22 @@ +--- +title: Blog +layout: blog +feed: true +pagination: + enabled: true +--- + +{% for post in paginator.posts %} +
+

{{ post.title }}

+
+ {% include byline.html authors=post.authors date=post.date %} +
+

{{ post.excerpt | strip_html }}

+

Full Post »

+
+{% endfor %} + +{% if paginator.total_pages > 1 %} +{% include paginator.html %} +{% endif %} diff --git a/website/cmd/server/BUILD b/website/cmd/server/BUILD new file mode 100644 index 000000000..6b5a08f0d --- /dev/null +++ b/website/cmd/server/BUILD @@ -0,0 +1,10 @@ +load("//tools:defs.bzl", "go_binary") + +package(licenses = ["notice"]) + +go_binary( + name = "server", + srcs = ["main.go"], + pure = True, + visibility = ["//website:__pkg__"], +) diff --git a/website/cmd/server/main.go b/website/cmd/server/main.go new file mode 100644 index 000000000..7c8bc9bfa --- /dev/null +++ b/website/cmd/server/main.go @@ -0,0 +1,211 @@ +// Copyright 2019 The gVisor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Server is the main gvisor.dev binary. +package main + +import ( + "flag" + "fmt" + "log" + "net/http" + "os" + "regexp" + "strings" +) + +var redirects = map[string]string{ + // GitHub redirects. + "/change": "https://github.com/google/gvisor", + "/issue": "https://github.com/google/gvisor/issues", + "/issue/new": "https://github.com/google/gvisor/issues/new", + "/pr": "https://github.com/google/gvisor/pulls", + + // For links. + "/faq": "/docs/user_guide/faq/", + + // Redirects to compatibility docs. + "/c": "/docs/user_guide/compatibility/", + "/c/linux/amd64": "/docs/user_guide/compatibility/linux/amd64/", + + // Redirect for old URLs. + "/docs/user_guide/compatibility/amd64/": "/docs/user_guide/compatibility/linux/amd64/", + "/docs/user_guide/compatibility/amd64": "/docs/user_guide/compatibility/linux/amd64/", + "/docs/user_guide/kubernetes/": "/docs/user_guide/quick_start/kubernetes/", + "/docs/user_guide/kubernetes": "/docs/user_guide/quick_start/kubernetes/", + "/docs/user_guide/oci/": "/docs/user_guide/quick_start/oci/", + "/docs/user_guide/oci": "/docs/user_guide/quick_start/oci/", + "/docs/user_guide/docker/": "/docs/user_guide/quick_start/docker/", + "/docs/user_guide/docker": "/docs/user_guide/quick_start/docker/", + + // Deprecated, but links continue to work. + "/cl": "https://gvisor-review.googlesource.com", +} + +var prefixHelpers = map[string]string{ + "change": "https://github.com/google/gvisor/commit/%s", + "issue": "https://github.com/google/gvisor/issues/%s", + "pr": "https://github.com/google/gvisor/pull/%s", + + // Redirects to compatibility docs. + "c/linux/amd64": "/docs/user_guide/compatibility/linux/amd64/#%s", + + // Deprecated, but links continue to work. + "cl": "https://gvisor-review.googlesource.com/c/gvisor/+/%s", +} + +var ( + validID = regexp.MustCompile(`^[A-Za-z0-9-]*/?$`) + goGetHTML5 = ` + + +Go-get` +) + +// cronHandler wraps an http.Handler to check that the request is from the App +// Engine Cron service. +// See: https://cloud.google.com/appengine/docs/standard/go112/scheduling-jobs-with-cron-yaml#validating_cron_requests +func cronHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("X-Appengine-Cron") != "true" { + http.NotFound(w, r) + return + } + // Fallthrough. + h.ServeHTTP(w, r) + }) +} + +// wrappedHandler wraps an http.Handler. +// +// If the query parameters include go-get=1, then we redirect to a single +// static page that allows us to serve arbitrary Go packages. +func wrappedHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gg, ok := r.URL.Query()["go-get"] + if ok && len(gg) == 1 && gg[0] == "1" { + // Serve a trivial html page. + w.Write([]byte(goGetHTML5)) + return + } + // Fallthrough. + h.ServeHTTP(w, r) + }) +} + +// redirectWithQuery redirects to the given target url preserving query parameters. +func redirectWithQuery(w http.ResponseWriter, r *http.Request, target string) { + url := target + if qs := r.URL.RawQuery; qs != "" { + url += "?" + qs + } + http.Redirect(w, r, url, http.StatusFound) +} + +// hostRedirectHandler redirects the www. domain to the naked domain. +func hostRedirectHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.Host, "www.") { + // Redirect to the naked domain. + r.URL.Scheme = "https" // Assume https. + r.URL.Host = r.Host[4:] // Remove the 'www.' + http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently) + return + } + + if *projectID != "" && r.Host == *projectID+".appspot.com" && *customHost != "" { + // Redirect to the custom domain. + r.URL.Scheme = "https" // Assume https. + r.URL.Host = *customHost + http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently) + return + } + h.ServeHTTP(w, r) + }) +} + +// prefixRedirectHandler returns a handler that redirects to the given formated url. +func prefixRedirectHandler(prefix, baseURL string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if p := r.URL.Path; p == prefix { + // Redirect /prefix/ to /prefix. + http.Redirect(w, r, p[:len(p)-1], http.StatusFound) + return + } + id := r.URL.Path[len(prefix):] + if !validID.MatchString(id) { + http.Error(w, "Not found", http.StatusNotFound) + return + } + target := fmt.Sprintf(baseURL, id) + redirectWithQuery(w, r, target) + }) +} + +// redirectHandler returns a handler that redirects to the given url. +func redirectHandler(target string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + redirectWithQuery(w, r, target) + }) +} + +// redirectRedirects registers redirect http handlers. +func registerRedirects(mux *http.ServeMux) { + if mux == nil { + mux = http.DefaultServeMux + } + + for prefix, baseURL := range prefixHelpers { + p := "/" + prefix + "/" + mux.Handle(p, hostRedirectHandler(wrappedHandler(prefixRedirectHandler(p, baseURL)))) + } + + for path, redirect := range redirects { + mux.Handle(path, hostRedirectHandler(wrappedHandler(redirectHandler(redirect)))) + } +} + +// registerStatic registers static file handlers +func registerStatic(mux *http.ServeMux, staticDir string) { + if mux == nil { + mux = http.DefaultServeMux + } + mux.Handle("/", hostRedirectHandler(wrappedHandler(http.FileServer(http.Dir(staticDir))))) +} + +func envFlagString(name, def string) string { + if val := os.Getenv(name); val != "" { + return val + } + return def +} + +var ( + addr = flag.String("http", envFlagString("HTTP", ":"+envFlagString("PORT", "8080")), "HTTP service address") + staticDir = flag.String("static-dir", envFlagString("STATIC_DIR", "_site"), "static files directory") + + // Uses the standard GOOGLE_CLOUD_PROJECT environment variable set by App Engine. + projectID = flag.String("project-id", envFlagString("GOOGLE_CLOUD_PROJECT", ""), "The App Engine project ID.") + customHost = flag.String("custom-domain", envFlagString("CUSTOM_DOMAIN", "gvisor.dev"), "The application's custom domain.") +) + +func main() { + flag.Parse() + + registerRedirects(nil) + registerStatic(nil, *staticDir) + + log.Printf("Listening on %s...", *addr) + log.Fatal(http.ListenAndServe(*addr, nil)) +} diff --git a/website/cmd/syscalldocs/BUILD b/website/cmd/syscalldocs/BUILD new file mode 100644 index 000000000..c5a0ed7fe --- /dev/null +++ b/website/cmd/syscalldocs/BUILD @@ -0,0 +1,9 @@ +load("//tools:defs.bzl", "go_binary") + +package(licenses = ["notice"]) + +go_binary( + name = "syscalldocs", + srcs = ["main.go"], + visibility = ["//website:__pkg__"], +) diff --git a/website/cmd/syscalldocs/main.go b/website/cmd/syscalldocs/main.go new file mode 100644 index 000000000..62d293a05 --- /dev/null +++ b/website/cmd/syscalldocs/main.go @@ -0,0 +1,209 @@ +// Copyright 2019 The gVisor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Binary syscalldocs generates system call markdown. +package main + +import ( + "bufio" + "encoding/json" + "flag" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + "text/template" +) + +// CompatibilityInfo is the collection of all information. +type CompatibilityInfo map[string]map[string]ArchInfo + +// ArchInfo is compatbility doc for an architecture. +type ArchInfo struct { + // Syscalls maps syscall number for the architecture to the doc. + Syscalls map[uintptr]SyscallDoc `json:"syscalls"` +} + +// SyscallDoc represents a single item of syscall documentation. +type SyscallDoc struct { + Name string `json:"name"` + Support string `json:"support"` + Note string `json:"note,omitempty"` + URLs []string `json:"urls,omitempty"` +} + +var mdTemplate = template.Must(template.New("out").Parse(`--- +title: {{.OS}}/{{.Arch}} +description: Syscall Compatibility Reference Documentation for {{.OS}}/{{.Arch}} +layout: docs +category: Compatibility +weight: 50 +permalink: /docs/user_guide/compatibility/{{.OS}}/{{.Arch}}/ +--- + +This table is a reference of {{.OS}} syscalls for the {{.Arch}} architecture and +their compatibility status in gVisor. gVisor does not support all syscalls and +some syscalls may have a partial implementation. + +This page is automatically generated from the source code. + +Of {{.Total}} syscalls, {{.Supported}} syscalls have a full or partial +implementation. There are currently {{.Unsupported}} unsupported +syscalls. {{if .Undocumented}}{{.Undocumented}} syscalls are not yet documented.{{end}} + + + + + + + + + + + + {{range $i, $syscall := .Syscalls}} + + + + + + + {{end}} + +
#NameSupportNotes
{{.Number}}{{.Name}}{{.Support}}{{.Note}} {{range $i, $url := .URLs}}
See: {{.}}{{end}}
+`)) + +// Fatalf writes a message to stderr and exits with error code 1 +func Fatalf(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, format, a...) + os.Exit(1) +} + +func main() { + inputFlag := flag.String("in", "-", "File to input ('-' for stdin)") + outputDir := flag.String("out", ".", "Directory to output files.") + + flag.Parse() + + var input io.Reader + if *inputFlag == "-" { + input = os.Stdin + } else { + i, err := os.Open(*inputFlag) + if err != nil { + Fatalf("Error opening %q: %v", *inputFlag, err) + } + input = i + } + input = bufio.NewReader(input) + + var info CompatibilityInfo + d := json.NewDecoder(input) + if err := d.Decode(&info); err != nil { + Fatalf("Error reading json: %v", err) + } + + weight := 0 + for osName, osInfo := range info { + for archName, archInfo := range osInfo { + outDir := filepath.Join(*outputDir, osName) + outFile := filepath.Join(outDir, archName+".md") + + if err := os.MkdirAll(outDir, 0755); err != nil { + Fatalf("Error creating directory %q: %v", *outputDir, err) + } + + f, err := os.OpenFile(outFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + Fatalf("Error opening file %q: %v", outFile, err) + } + defer f.Close() + + weight += 10 + data := struct { + OS string + Arch string + Weight int + Total int + Supported int + Unsupported int + Undocumented int + Syscalls []struct { + Name string + Number uintptr + Support string + Note string + URLs []string + } + }{ + OS: strings.Title(osName), + Arch: archName, + Weight: weight, + Total: 0, + Supported: 0, + Unsupported: 0, + Undocumented: 0, + Syscalls: []struct { + Name string + Number uintptr + Support string + Note string + URLs []string + }{}, + } + + for num, s := range archInfo.Syscalls { + switch s.Support { + case "Full Support", "Partial Support": + data.Supported++ + case "Unimplemented": + data.Unsupported++ + default: + data.Undocumented++ + } + data.Total++ + + for i := range s.URLs { + if !strings.HasPrefix(s.URLs[i], "http://") && !strings.HasPrefix(s.URLs[i], "https://") { + s.URLs[i] = "https://" + s.URLs[i] + } + } + + data.Syscalls = append(data.Syscalls, struct { + Name string + Number uintptr + Support string + Note string + URLs []string + }{ + Name: s.Name, + Number: num, + Support: s.Support, + Note: s.Note, // TODO urls + URLs: s.URLs, + }) + } + + sort.Slice(data.Syscalls, func(i, j int) bool { + return data.Syscalls[i].Number < data.Syscalls[j].Number + }) + + if err := mdTemplate.Execute(f, data); err != nil { + Fatalf("Error writing file %q: %v", outFile, err) + } + } + } +} diff --git a/website/css/main.scss b/website/css/main.scss new file mode 100644 index 000000000..06106833f --- /dev/null +++ b/website/css/main.scss @@ -0,0 +1,5 @@ +@import 'style.scss'; +@import 'front.scss'; +@import 'navbar.scss'; +@import 'sidebar.scss'; +@import 'footer.scss'; diff --git a/website/defs.bzl b/website/defs.bzl new file mode 100644 index 000000000..ead6a3067 --- /dev/null +++ b/website/defs.bzl @@ -0,0 +1,176 @@ +"""Wrappers for website documentation.""" + +# DocInfo is a provider which simple adds sufficient metadata to the source +# files (and additional data files) so that a jeyll header can be constructed +# dynamically. This is done the via BUILD system so that the plain +# documentation files can be viewable without non-compliant markdown headers. +DocInfo = provider( + fields = [ + "layout", + "description", + "permalink", + "category", + "subcategory", + "weight", + "editpath", + "authors", + ], +) + +def _doc_impl(ctx): + return [ + DefaultInfo( + files = depset(ctx.files.src + ctx.files.data), + ), + DocInfo( + layout = ctx.attr.layout, + description = ctx.attr.description, + permalink = ctx.attr.permalink, + category = ctx.attr.category, + subcategory = ctx.attr.subcategory, + weight = ctx.attr.weight, + editpath = ctx.files.src[0].short_path, + authors = ctx.attr.authors, + ), + ] + +doc = rule( + implementation = _doc_impl, + doc = "Annotate a document for jekyll headers.", + attrs = { + "src": attr.label( + doc = "The markdown source file.", + mandatory = True, + allow_single_file = True, + ), + "data": attr.label_list( + doc = "Additional data files (e.g. images).", + allow_files = True, + ), + "layout": attr.string( + doc = "The document layout.", + default = "docs", + ), + "description": attr.string( + doc = "The document description.", + default = "", + ), + "permalink": attr.string( + doc = "The document permalink.", + mandatory = True, + ), + "category": attr.string( + doc = "The document category.", + default = "", + ), + "subcategory": attr.string( + doc = "The document subcategory.", + default = "", + ), + "weight": attr.string( + doc = "The document weight.", + default = "50", + ), + "authors": attr.string_list(), + }, +) + +def _docs_impl(ctx): + # Tarball is the actual output. + tarball = ctx.actions.declare_file(ctx.label.name + ".tgz") + + # But we need an intermediate builder to translate the files. + builder = ctx.actions.declare_file("%s-builder" % ctx.label.name) + builder_content = [ + "#!/bin/bash", + "set -euo pipefail", + "declare -r T=$(mktemp -d)", + "function cleanup {", + " rm -rf $T", + "}", + "trap cleanup EXIT", + ] + for dep in ctx.attr.deps: + doc = dep[DocInfo] + + # Sanity check the permalink. + if not doc.permalink.endswith("/"): + fail("permalink %s for target %s should end with /" % ( + doc.permalink, + ctx.label.name, + )) + + # Construct the header. + header = """\ +description: {description} +permalink: {permalink} +category: {category} +subcategory: {subcategory} +weight: {weight} +editpath: {editpath} +authors: {authors} +layout: {layout}""" + + for f in dep.files.to_list(): + # Is this a markdown file? If not, then we ensure that it ends up + # in the same path as the permalink for relative addressing. + if not f.basename.endswith(".md"): + builder_content.append("mkdir -p $T/%s" % doc.permalink) + builder_content.append("cp %s $T/%s" % (f.path, doc.permalink)) + continue + + # Is this a post? If yes, then we must put this in the _posts + # directory. This directory is treated specially with respect to + # pagination and page generation. + dest = f.short_path + if doc.layout == "post": + dest = "_posts/" + f.basename + builder_content.append("echo Processing %s... >&2" % f.short_path) + builder_content.append("mkdir -p $T/$(dirname %s)" % dest) + + # Construct the header dynamically. We include the title field from + # the markdown itself, as this is the g3doc format required. The + # title will be injected by the web layout however, so we don't + # want this to appear in the document. + args = dict([(k, getattr(doc, k)) for k in dir(doc)]) + builder_content.append("title=\"$(grep -E '^# ' %s | head -n 1 | cut -d'#' -f2- || true)\"" % f.path) + builder_content.append("cat >$T/%s <>$T/%s" % + (f.path, dest)) + + builder_content.append("declare -r filename=$(readlink -m %s)" % tarball.path) + builder_content.append("(cd $T && tar -zcf \"${filename}\" .)\n") + ctx.actions.write(builder, "\n".join(builder_content), is_executable = True) + + # Generate the tarball. + ctx.actions.run( + inputs = depset(ctx.files.deps), + outputs = [tarball], + progress_message = "Generating %s" % ctx.label, + executable = builder, + ) + return [DefaultInfo( + files = depset([tarball]), + )] + +docs = rule( + implementation = _docs_impl, + doc = "Construct a site tarball from doc dependencies.", + attrs = { + "deps": attr.label_list( + doc = "All document dependencies.", + ), + }, +) diff --git a/website/import.sh b/website/import.sh new file mode 100755 index 000000000..e1350e83d --- /dev/null +++ b/website/import.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Copyright 2018 The gVisor Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -xeuo pipefail + +if [[ -d $0.runfiles ]]; then + cd $0.runfiles +fi + +exec docker import \ + -c "EXPOSE 8080/tcp" \ + -c "ENTRYPOINT [\"/server\"]" \ + $(find . -name files.tgz) \ + gvisor.dev/images/website diff --git a/website/index.md b/website/index.md new file mode 100644 index 000000000..34d3ee23d --- /dev/null +++ b/website/index.md @@ -0,0 +1,50 @@ +
+
+
+
+
+

gVisor is an application kernel and container runtime providing defense-in-depth for containers anywhere.

+

+ Learn More  + GitHub  +

+
+
+
+
+
+ +
+ +
+
+

Container-native Security

+

By providing each container with its own userspace kernel, gVisor limits + the attack surface of the host. This protection does not limit + functionality: gVisor runs unmodified binaries and integrates with container + orchestration systems, such as Docker and Kubernetes, and supports features + such as volumes and sidecars.

+ Read More » +
+ +
+

Resource Efficiency

+

Containers are efficient because workloads of different shapes and sizes + can be packed together by sharing host resources. gVisor uses host-native + abstractions, such as threads and memory mappings, to co-operate with the + host and enable the same resource model as native containers.

+ Read More » +
+ +
+

Platform Portability

+

Modern infrastructure spans multiple cloud services and data centers, + often with a mix of managed services and virtualized or traditional servers. + The pluggable platform architecture of gVisor allows it to run anywhere, + enabling consistent security policies across multiple environments without + having to rearchitect your infrastructure.

+ Read More » +
+
+ +
diff --git a/website/performance/README.md b/website/performance/README.md new file mode 100644 index 000000000..0dbfd2f02 --- /dev/null +++ b/website/performance/README.md @@ -0,0 +1,9 @@ +# Performance data + +This directory holds the CSVs generated by the +[benchmark-tools][benchmark-tools] repository. + +In the future, these will be automatically posted to a cloud storage bucket and +loaded dynamically. At that point, this directory will be removed. + +[benchmark-tools]: https://github.com/google/gvisor/tree/master/benchmarks diff --git a/website/performance/applications.csv b/website/performance/applications.csv new file mode 100644 index 000000000..7b4661c60 --- /dev/null +++ b/website/performance/applications.csv @@ -0,0 +1,13 @@ +runtime,method,metric,result +runc,http.node,transfer_rate,3814.85 +runc,http.node,latency,11.0 +runc,http.node,requests_per_second,885.81 +runc,http.ruby,transfer_rate,2874.38 +runc,http.ruby,latency,18.0 +runc,http.ruby,requests_per_second,539.97 +runsc,http.node,transfer_rate,1615.54 +runsc,http.node,latency,27.0 +runsc,http.node,requests_per_second,375.13 +runsc,http.ruby,transfer_rate,1382.71 +runsc,http.ruby,latency,38.0 +runsc,http.ruby,requests_per_second,259.75 diff --git a/website/performance/density.csv b/website/performance/density.csv new file mode 100644 index 000000000..729b44941 --- /dev/null +++ b/website/performance/density.csv @@ -0,0 +1,9 @@ +runtime,method,metric,result +runc,density.empty,memory_usage,4092149.76 +runc,density.node,memory_usage,76709888.0 +runc,density.ruby,memory_usage,45737000.96 +runsc,density.empty,memory_usage,23695032.32 +runsc,density.node,memory_usage,124076605.44 +runsc,density.ruby,memory_usage,106141777.92 +runc,density.redis,memory_usage,1055323750.4 +runsc,density.redis,memory_usage,1076686028.8 diff --git a/website/performance/ffmpeg.csv b/website/performance/ffmpeg.csv new file mode 100644 index 000000000..08661c749 --- /dev/null +++ b/website/performance/ffmpeg.csv @@ -0,0 +1,3 @@ +runtime,metric,result +runc,run_time,82.000625 +runsc,run_time,88.24018 diff --git a/website/performance/fio-tmpfs.csv b/website/performance/fio-tmpfs.csv new file mode 100644 index 000000000..99777d2e4 --- /dev/null +++ b/website/performance/fio-tmpfs.csv @@ -0,0 +1,9 @@ +runtime,method,metric,result +runc,fio.read,bandwidth,4240686080 +runc,fio.write,bandwidth,3029744640 +runsc,fio.read,bandwidth,2533604352 +runsc,fio.write,bandwidth,1207536640 +runc,fio.randread,bandwidth,1221472256 +runc,fio.randwrite,bandwidth,1046094848 +runsc,fio.randread,bandwidth,68940800 +runsc,fio.randwrite,bandwidth,67286016 diff --git a/website/performance/fio.csv b/website/performance/fio.csv new file mode 100644 index 000000000..80d6ae289 --- /dev/null +++ b/website/performance/fio.csv @@ -0,0 +1,9 @@ +runtime,method,metric,result +runc,fio.read,bandwidth,252253184 +runc,fio.write,bandwidth,457767936 +runsc,fio.read,bandwidth,252323840 +runsc,fio.write,bandwidth,431845376 +runc,fio.randread,bandwidth,5284864 +runc,fio.randwrite,bandwidth,107758592 +runsc,fio.randread,bandwidth,4403200 +runsc,fio.randwrite,bandwidth,69161984 diff --git a/website/performance/httpd100k.csv b/website/performance/httpd100k.csv new file mode 100644 index 000000000..e92c7e9e0 --- /dev/null +++ b/website/performance/httpd100k.csv @@ -0,0 +1,17 @@ +connections,runtime,metric,result +1,runc,transfer_rate,565.35 +1,runc,latency,1.0 +1,runsc,transfer_rate,282.84 +1,runsc,latency,2.0 +5,runc,transfer_rate,3260.57 +5,runc,latency,1.0 +5,runsc,transfer_rate,832.69 +5,runsc,latency,3.0 +10,runc,transfer_rate,4672.01 +10,runc,latency,1.0 +10,runsc,transfer_rate,1095.47 +10,runsc,latency,4.0 +25,runc,transfer_rate,4964.14 +25,runc,latency,2.0 +25,runsc,transfer_rate,961.03 +25,runsc,latency,12.0 diff --git a/website/performance/httpd10240k.csv b/website/performance/httpd10240k.csv new file mode 100644 index 000000000..60dbe7b40 --- /dev/null +++ b/website/performance/httpd10240k.csv @@ -0,0 +1,17 @@ +connections,runtime,metric,result +1,runc,transfer_rate,674.05 +1,runc,latency,1.0 +1,runsc,transfer_rate,243.35 +1,runsc,latency,2.0 +5,runc,transfer_rate,3089.83 +5,runc,latency,1.0 +5,runsc,transfer_rate,981.91 +5,runsc,latency,2.0 +10,runc,transfer_rate,4701.2 +10,runc,latency,1.0 +10,runsc,transfer_rate,1135.08 +10,runsc,latency,4.0 +25,runc,transfer_rate,5021.36 +25,runc,latency,2.0 +25,runsc,transfer_rate,963.26 +25,runsc,latency,12.0 diff --git a/website/performance/iperf.csv b/website/performance/iperf.csv new file mode 100644 index 000000000..1f3b41aec --- /dev/null +++ b/website/performance/iperf.csv @@ -0,0 +1,5 @@ +runtime,method,metric,result +runc,network.download,bandwidth,746386000.0 +runc,network.upload,bandwidth,709808000.0 +runsc,network.download,bandwidth,640303500.0 +runsc,network.upload,bandwidth,482254000.0 diff --git a/website/performance/redis.csv b/website/performance/redis.csv new file mode 100644 index 000000000..369b16712 --- /dev/null +++ b/website/performance/redis.csv @@ -0,0 +1,35 @@ +runtime,method,metric,result +runc,PING_INLINE,requests_per_second,30525.03 +runc,PING_BULK,requests_per_second,30293.85 +runc,SET,requests_per_second,30257.19 +runc,GET,requests_per_second,30312.21 +runc,INCR,requests_per_second,30525.03 +runc,LPUSH,requests_per_second,30712.53 +runc,RPUSH,requests_per_second,30459.95 +runc,LPOP,requests_per_second,30367.45 +runc,RPOP,requests_per_second,30665.44 +runc,SADD,requests_per_second,30030.03 +runc,HSET,requests_per_second,30656.04 +runc,SPOP,requests_per_second,29940.12 +runc,LRANGE_100,requests_per_second,24224.81 +runc,LRANGE_300,requests_per_second,14302.06 +runc,LRANGE_500,requests_per_second,11728.83 +runc,LRANGE_600,requests_per_second,9900.99 +runc,MSET,requests_per_second,30120.48 +runsc,PING_INLINE,requests_per_second,14528.55 +runsc,PING_BULK,requests_per_second,15627.44 +runsc,SET,requests_per_second,15403.57 +runsc,GET,requests_per_second,15325.67 +runsc,INCR,requests_per_second,15269.51 +runsc,LPUSH,requests_per_second,15172.2 +runsc,RPUSH,requests_per_second,15117.16 +runsc,LPOP,requests_per_second,15257.86 +runsc,RPOP,requests_per_second,15188.33 +runsc,SADD,requests_per_second,15432.1 +runsc,HSET,requests_per_second,15163.0 +runsc,SPOP,requests_per_second,15561.78 +runsc,LRANGE_100,requests_per_second,13365.41 +runsc,LRANGE_300,requests_per_second,9520.18 +runsc,LRANGE_500,requests_per_second,8248.78 +runsc,LRANGE_600,requests_per_second,6544.07 +runsc,MSET,requests_per_second,14367.82 diff --git a/website/performance/startup.csv b/website/performance/startup.csv new file mode 100644 index 000000000..6bad00df6 --- /dev/null +++ b/website/performance/startup.csv @@ -0,0 +1,7 @@ +runtime,method,metric,result +runc,startup.empty,startup_time_ms,1193.10768 +runc,startup.node,startup_time_ms,2557.95336 +runc,startup.ruby,startup_time_ms,2530.12624 +runsc,startup.empty,startup_time_ms,1144.1775 +runsc,startup.node,startup_time_ms,2441.90284 +runsc,startup.ruby,startup_time_ms,2455.69882 diff --git a/website/performance/sysbench-cpu.csv b/website/performance/sysbench-cpu.csv new file mode 100644 index 000000000..f4e6b69a6 --- /dev/null +++ b/website/performance/sysbench-cpu.csv @@ -0,0 +1,3 @@ +runtime,metric,result +runc,cpu_events_per_second,103.62 +runsc,cpu_events_per_second,103.21 diff --git a/website/performance/sysbench-memory.csv b/website/performance/sysbench-memory.csv new file mode 100644 index 000000000..626ff4994 --- /dev/null +++ b/website/performance/sysbench-memory.csv @@ -0,0 +1,3 @@ +runtime,metric,result +runc,memory_ops_per_second,13098.73 +runsc,memory_ops_per_second,13107.44 diff --git a/website/performance/syscall.csv b/website/performance/syscall.csv new file mode 100644 index 000000000..40bdce49e --- /dev/null +++ b/website/performance/syscall.csv @@ -0,0 +1,4 @@ +runtime,metric,result +runc,syscall_time_ns,1939.0 +runsc,syscall_time_ns,38219.0 +runsc-kvm,syscall_time_ns,763.0 diff --git a/website/performance/tensorflow.csv b/website/performance/tensorflow.csv new file mode 100644 index 000000000..03498bef0 --- /dev/null +++ b/website/performance/tensorflow.csv @@ -0,0 +1,3 @@ +runtime,metric,result +runc,run_time,207.1118165 +runsc,run_time,244.473401