Merge pull request #2513 from amscanne:website-integrated

PiperOrigin-RevId: 311184385
This commit is contained in:
gVisor bot
2020-05-12 12:55:23 -07:00
150 changed files with 6240 additions and 16 deletions
+39
View File
@@ -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",
+2 -3
View File
@@ -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).
+2 -3
View File
@@ -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/
+113
View File
@@ -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:[email protected]): general purpose user
list.
* [gvisor-dev](mailto:[email protected]): general purpose
development list.
* [gvisor-security](mailto:[email protected]): 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:[email protected]): 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.
+33 -1
View File
@@ -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.
##
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+31
View File
@@ -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",
)
+27 -2
View File
@@ -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
+64
View File
@@ -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",
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 70 KiB

+80
View File
@@ -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?
<a name="gofer"></a> <!-- For deep linking. -->
[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
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

+274
View File
@@ -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
+86
View File
@@ -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
+143
View File
@@ -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.
+253
View File
@@ -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
+31
View File
@@ -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.
<iframe src="https://calendar.google.com/calendar/b/1/embed?showTitle=0&amp;height=600&amp;wkst=1&amp;bgcolor=%23FFFFFF&amp;src=bd6f4k210u3ukmlj9b8vl053fk%40group.calendar.google.com&amp;color=%23AB8B00&amp;ctz=America%2FLos_Angeles" style="border-width:0" width="600" height="400" frameborder="0" scrolling="no"></iframe>
[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
+1
View File
@@ -0,0 +1 @@
The gVisor logo files are licensed under CC BY-SA 4.0 (Creative Commons Attribution-ShareAlike 4.0 International).
+49
View File
@@ -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
+70
View File
@@ -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",
)
+122
View File
@@ -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/.../<containerid>/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/
+101
View File
@@ -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 <container id>
```
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=<path> <container id>
```
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=<path> --leave-running <container id>
```
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 <container id>
runsc restore --image-path=<path> <container id>
```
## 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 <image>`
```
Checkpoint a container:
```bash
docker checkpoint create <container> <checkpoint_name>`
```
Create a new container into which to restore:
```bash
docker create [options] --runtime=runsc <image>
```
Restore a container:
```bash
docker start --checkpoint --checkpoint-dir=<directory> <container>
```
### 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
+93
View File
@@ -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:
<!-- mdformat off(don't wrap the table) -->
| 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. |
<!-- mdformat on -->
[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
+131
View File
@@ -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 <PID>
# 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
+60
View File
@@ -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"
]
}
}
}
```
+160
View File
@@ -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
+85
View File
@@ -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
+119
View File
@@ -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
+33
View File
@@ -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",
)
+92
View File
@@ -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/
@@ -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/
+45
View File
@@ -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
+37
View File
@@ -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",
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

+172
View File
@@ -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}
```
+68
View File
@@ -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
<http://localhost:8080>.
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/
+134
View File
@@ -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/
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+5
View File
@@ -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"]
+12
View File
@@ -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"]
+12 -4
View File
@@ -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
+181
View File
@@ -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"],
)
+35
View File
@@ -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: [email protected]
zkoopmans:
name: Zach Koopmans
email: [email protected]
igudger:
name: Ian Gudger
email: [email protected]
+18
View File
@@ -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 %}
<a href="mailto:{{ author.email }}">{{ author.name }}</a>
{% else %}
{{ author_id }}
{% endif %}
{% if i == and_pos %}
and
{% elsif i < and_pos %}
,
{% endif %}
{% endfor %}
on <span class="text-muted">{{ include.date | date_to_long_string }}</span>
+43
View File
@@ -0,0 +1,43 @@
<div class="container">
<div class="row">
<div class="col-sm-3 col-md-2">
<p>About</p>
<ul class="list-unstyled">
<li><a href="/roadmap/">Roadmap</a></li>
<li><a href="/contributing/">Contributing</a></li>
<li><a href="/security/">Security</a></li>
<li><a href="/community/governance/">Governance</a></li>
<li><a href="https://policies.google.com/privacy">Privacy Policy</a></li>
</ul>
</div>
<div class="col-sm-3 col-md-2">
<p>Support</p>
<ul class="list-unstyled">
<li><a href="https://github.com/google/gvisor/issues">Issues</a></li>
<li><a href="/docs">Documentation</a></li>
<li><a href="/docs/user_guide/FAQ">FAQ</a></li>
</ul>
</div>
<div class="col-sm-3 col-md-2">
<p>Connect</p>
<ul class="list-unstyled">
<li><a href="https://github.com/google/gvisor">GitHub</a></li>
<li><a href="https://groups.google.com/forum/#!forum/gvisor-users">User Mailing List</a></li>
<li><a href="https://groups.google.com/forum/#!forum/gvisor-dev">Developer Mailing List</a></li>
<li><a href="https://gitter.im/gvisor/community">Gitter Chat</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</div>
<div class="col-sm-3 col-md-3"></div>
<div class="hidden-xs hidden-sm col-md-3">
<a href="https://cloud.google.com/run">
<img style="float: right;" src="/assets/logos/powered-gvisor.png" alt="Powered by gVisor"/>
</a>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<p>&copy; {{ 'now' | date: "%Y" }} The gVisor Authors</p>
</div>
</div>
</div>
+72
View File
@@ -0,0 +1,72 @@
<footer class="footer">
{% include footer-links.html %}
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.1/js/all.min.js" integrity="sha256-Z1Nvg/+y2+vRFhFgFij7Lv0r77yG3hOvWz2wI0SfTa0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js" integrity="sha256-hYXbQJK4qdJiAeDVjjQ9G0D6A0xLnDQ4eJI9dkm7Fpk=" crossorigin="anonymous"></script>
{% if site.analytics %}
<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', '{{ site.analytics }}', 'auto');
ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
{% endif %}
<script>
var shiftWindow = function() {
if (location.hash.length !== 0) {
window.scrollBy(0, -50);
}
};
window.addEventListener("hashchange", shiftWindow);
var highlightCurrentSidebarNav = function() {
var href = location.pathname;
var item = $('#sidebar-nav [href$="' + href + '"]');
if (item) {
var li = item.parent();
li.addClass("active");
if (li.parent() && li.parent().is("ul")) {
do {
var ul = li.parent();
if (ul.hasClass("collapse")) {
ul.collapse("show");
}
li = ul.parent();
} while (li && li.is("li"));
}
}
};
$(document).ready(function() {
// Scroll to anchor of location hash, adjusted for fixed navbar.
window.setTimeout(function() {
shiftWindow();
}, 1);
// Flip the caret when submenu toggles are clicked.
$(".sidebar-submenu").on("show.bs.collapse", function() {
var toggle = $('[href$="#' + $(this).attr('id') + '"]');
if (toggle) {
toggle.addClass("dropup");
}
});
$(".sidebar-submenu").on("hide.bs.collapse", function() {
var toggle = $('[href$="#' + $(this).attr('id') + '"]');
if (toggle) {
toggle.removeClass("dropup");
}
});
// Highlight the current page on the sidebar nav.
highlightCurrentSidebarNav();
});
</script>
+205
View File
@@ -0,0 +1,205 @@
{::nomarkdown}
{% assign fn = include.id | remove: " " | remove: "-" | downcase %}
<figure><a href="{{ include.url }}"><svg id="{{ include.id }}" width=500 height=200 onload="render_{{ fn }}()"><title>{{ include.title }}</title></svg></a></figure>
<script type="text/javascript">
function render_{{ fn }}() {
d3.csv("{{ include.url }}", function(d, i, columns) {
return d; // Transformed below.
}, function(error, data) {
if (error) throw(error);
// Create a new data that pivots on runtime.
//
// To start, we have:
// runtime, ..., result
// runc, ..., 1
// runsc, ..., 2
//
// In the end we want:
// ..., runsc, runc
// ..., 1, 2
// Filter by metric, if required.
if ("{{ include.metric }}" != "") {
orig_columns = data.columns;
data = data.filter(d => d.metric == "{{ include.metric }}");
data.columns = orig_columns;
}
// Filter by method, if required.
if ("{{ include.method }}" != "") {
orig_columns = data.columns;
data = data.filter(d => d.method == "{{ include.method }}");
data.columns = orig_columns.filter(key => key != "method");
}
// Enumerate runtimes.
var runtimes = Array.from(new Set(data.map(d => d.runtime)));
var metrics = Array.from(new Set(data.map(d => d.metric)));
if (metrics.length < 1) {
console.log(data);
throw("need at least one metric");
} else if (metrics.length == 1) {
metric = metrics[0];
data.columns = data.columns.filter(key => key != "metric");
} else {
metric = ""; // Used for grouping.
}
var isSubset = function(a, sup) {
var ap = Object.getOwnPropertyNames(a);
for (var i = 0; i < ap.length; i++) {
if (a[ap[i]] !== sup[ap[i]]) {
return false;
}
}
return true;
};
// Execute a pivot to include runtimes as attributes.
var new_data = data.map(function(data_item) {
// Generate a prototype data item.
var proto_item = Object.assign({}, data_item);
delete proto_item.runtime;
delete proto_item.result;
var next_item = Object.assign({}, proto_item);
// Find all matching runtime items.
data.forEach(function(d) {
if (isSubset(proto_item, d)) {
// Add the result result.
next_item[d.runtime] = d.result;
}
});
return next_item;
});
// Remove any duplication.
new_data = Array.from(new Set(new_data));
new_data.columns = data.columns;
new_data.columns = new_data.columns.filter(key => key != "runtime" && key != "result");
new_data.columns = new_data.columns.concat(runtimes);
data = new_data;
// Slice based on the first key.
if (data.columns.length != runtimes.length) {
x0_key = new_data.columns[0];
var x1_domain = data.columns.slice(1);
} else {
x0_key = "runtime";
var x1_domain = runtimes;
}
// Determine varaible margins.
var x0_domain = data.map(d => d[x0_key]);
var margin_bottom_pad = 0;
if (x0_domain.length > 8) {
margin_bottom_pad = 50;
}
// Use log scale if required.
var y_min = 0;
if ({{ include.log | default: "false" }}) {
// Need to cap lower end of the domain at 1.
y_min = 1;
}
if ({{ include.y_min | default: "false" }}) {
y_min = "{{ include.y_min }}";
}
var svg = d3.select("#{{ include.id }}"),
margin = {top: 20, right: 20, bottom: 30 + margin_bottom_pad, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x0 = d3.scaleBand()
.rangeRound([margin.left / 2, width - (4 * margin.right)])
.paddingInner(0.1);
var x1 = d3.scaleBand()
.padding(0.05);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
if ({{ include.log | default: "false" }}) {
y = d3.scaleLog()
.rangeRound([height, 0]);
}
var z = d3.scaleOrdinal()
.range(["#262362", "#FBB03B", "#286FD7", "#6b486b"]);
// Set all domains.
x0.domain(x0_domain);
x1.domain(x1_domain).rangeRound([0, x0.bandwidth()]);
y.domain([y_min, d3.max(data, d => d3.max(x1_domain, key => parseFloat(d[key])))]).nice();
// The data.
g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d[x0_key]) + ",0)"; })
.selectAll("rect")
.data(d => x1_domain.map(key => ({key, value: d[key]})))
.enter().append("rect")
.attr("x", d => x1(d.key))
.attr("y", d => y(d.value))
.attr("width", x1.bandwidth())
.attr("height", d => y(y_min) - y(d.value))
.attr("fill", d => z(d.key));
// X0 ticks and labels.
var x0_axis = g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0));
if (x0_domain.length > 8) {
x0_axis.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
}
// Y ticks and top-label.
if (metric == "default") {
metric = ""; // Don't display.
}
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, "s"))
.append("text")
.attr("x", -30.0)
.attr("y", y(y.ticks().pop()) - 10.0)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text(metric);
// The legend.
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(x1_domain.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
});
}
</script>
{:/}
+19
View File
@@ -0,0 +1,19 @@
<nav class="navbar navbar-expand-sm navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-brand">
<a href="/">
<img src="/assets/logos/logo_solo_on_dark.svg" height="25px" class="d-inline-block align-top" style="margin-right: 10px;" alt="logo"/>
gVisor
</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/docs">Documentation</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/community/">Community</a></li>
<li><a href="https://github.com/google/gvisor">GitHub</a></li>
</ul>
</div>
</div>
</nav>
+30
View File
@@ -0,0 +1,30 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% if page.title %}
<title>{{ page.title }} - gVisor</title>
{% else %}
<title>gVisor</title>
{% endif %}
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site_root }}">
<!-- Dependencies. -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.1/css/all.min.css" integrity="sha256-fdcFNFiBMrNfWL6OcAGQz6jDgNTRxnrLEd4vJYFWScE=" crossorigin="anonymous" />
<!-- Our own style sheet. -->
<link rel="stylesheet" type="text/css" href="/css/main.css">
<link rel="icon" type="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16">
{% if page.title %}
<meta name="og:title" content="{{ page.title }}">
{% else %}
<meta name="og:title" content="gVisor">
{% endif %}
{% if page.description %}
<meta name="og:description" content="{{ page.description }}">
{% endif %}
<meta name="og:image" content="{{ site.site_url }}/assets/logos/logo_solo_on_white_bordered.svg">
</head>
+10
View File
@@ -0,0 +1,10 @@
<nav aria-label="...">
<ul class="pager">
{% if paginator.previous_page %}
<li class="previous"><a href="{{ paginator.previous_page_path }}"><span aria-hidden="true">&larr;</span> Newer</a></li>
{% endif %}
{% if paginator.next_page %}
<li class="next"><a href="{{ paginator.next_page_path }}">Older <span aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>
+2
View File
@@ -0,0 +1,2 @@
> Note: gVisor supports only x86\_64 and requires Linux 4.14.77+
> ([older Linux](/docs/user_guide/networking/#gso)).
+9
View File
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en" itemscope itemtype="https://schema.org/WebPage">
{% include header.html %}
<body>
{% include header-links.html %}
{{ content }}
{% include footer.html %}
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
---
layout: base
---
<div class="container">
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<h1>{{ page.title }}</h1>
{% if page.feed %}
<a class="btn-inverse" href="/blog/index.xml">Feed&nbsp;<i class="fas fa-rss ml-2"></i></a>
{% endif %}
{{ content }}
</div>
<div class="col-lg-2"></div>
</div>
</div>
+14
View File
@@ -0,0 +1,14 @@
---
layout: base
---
{% if page.title %}
<div class="container">
<div class="page-header">
<h1>{{ page.title }}</h1>
</div>
</div>
{% endif %}
<div class="container">
{{ content }}
</div>
+57
View File
@@ -0,0 +1,57 @@
---
layout: base
categories:
- Project
- User Guide
- Architecture Guide
- Compatibility
---
<div class="container">
<div class="row">
<div class="col-md-3">
<nav class="sidebar" id="sidebar-nav">
{% for category in layout.categories %}
<h3>{{ category }}</h3>
<ul class="sidebar-nav">
{% assign sorted_pages = site.pages | where: 'layout', 'docs' | where: 'category', category | sort: 'weight' | sort: 'subcategory' %}
{% assign subcategory = nil %}
{% for p in sorted_pages %}
{% if p.subcategory != subcategory %}
{% if subcategory != nil %}
</ul>
</li>
{% endif %}
{% assign subcategory = p.subcategory %}
{% if subcategory != nil %}
{% assign ac = "aria-controls" %}
{% assign cid = p.category | remove: " " | downcase %}
{% assign sid = p.subcategory | remove: " " | downcase %}
<li>
<a class="sidebar-nav-heading" data-toggle="collapse" href="#{{ cid }}-{{ sid }}" aria-expanded="false" {{ ac }}="{{ cid }}-{{ sid }}">{{ subcategory }}<span class="caret"></span></a>
<ul class="collapse sidebar-nav sidebar-submenu" id="{{ cid }}-{{ sid }}">
{% endif %}
{% endif %}
<li><a href="{{ p.url }}">{{ p.title }}</a></li>
{% endfor %}
{% if subcategory != nil %}
</ul>
</li>
{% endif %}
</ul>
{% endfor %}
</nav>
</div>
<div class="col-md-9">
<h1>{{ page.title }}</h1>
{% if page.editpath %}
<p>
<a href="https://github.com/google/gvisor/edit/master/content/{{page.editpath}}" target="_blank"><i class="fa fa-edit fa-fw"></i> Edit this page</a>
<a href="https://github.com/google/gvisor/issues/new?title={{page.title | url_encode}}" target="_blank"><i class="fab fa-github fa-fw"></i> Create issue</a>
</p>
{% endif %}
{{ content }}
</div>
</div>
</div>
+10
View File
@@ -0,0 +1,10 @@
---
layout: blog
---
<div class="blog-meta">
{% include byline.html authors=page.authors date=page.date %}
</div>
<div class="blog-content">
{{ content }}
</div>
+3
View File
@@ -0,0 +1,3 @@
require 'webrick'
include WEBrick
WEBrick::HTTPUtils::DefaultMimeTypes.store 'svg', 'image/svg+xml'
+15
View File
@@ -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;
}
}
}
+15
View File
@@ -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;
}
}
+26
View File
@@ -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;
}
}
+61
View File
@@ -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;
}
}
}
+144
View File
@@ -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;
}
+29
View File
@@ -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-----
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+13
View File
@@ -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 $<
+10
View File
@@ -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.
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
xml:space="preserve"
width="175.35599"
height="193.20036"
viewBox="0 0 175.35599 193.20036"
sodipodi:docname="logo_solo_monochrome.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath20"><path
d="M 0,821.614 H 1366 V 0 H 0 Z"
id="path18"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview4"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.43085925"
inkscape:cx="374.99057"
inkscape:cy="88.483321"
inkscape:window-x="0"
inkscape:window-y="9"
inkscape:window-maximized="0"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="gvisor_final-logo_20190313"
transform="matrix(1.3333333,0,0,-1.3333333,-614.45037,638.9628)"><g
id="g48"
transform="translate(548.2423,363.2485)"><path
d="m 0,0 c 16.655,21.121 22.696,44.433 18.328,70.995 3.068,0 5.743,-0.023 8.417,0.007 2.222,0.025 4.443,0.102 6.664,0.175 4.79,0.154 4.818,0.165 5.88,-4.582 3.145,-14.051 2.18,-28.09 -0.179,-42.118 -0.25,-1.492 -0.7,-2.956 -0.864,-4.454 C 37.05,9.081 30.089,3.645 20.165,1.097 13.787,-0.54 7.323,-0.829 0,0"
style="fill:#262262;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path50"
inkscape:connector-curvature="0" /></g><g
id="g52"
transform="translate(544.6891,396.1763)"><path
d="M 0,0 C 0,2.594 -3.457,4.322 -3.457,4.322 -0.864,5.187 0,8.644 0,8.644 0,8.644 0.865,5.187 3.458,4.322 3.458,4.322 0,2.594 0,0 m -17.099,6.454 c 0,6.742 -8.989,11.236 -8.989,11.236 6.742,2.248 8.989,11.238 8.989,11.238 0,0 2.247,-8.99 8.99,-11.238 0,0 -8.99,-4.494 -8.99,-11.236"
style="fill:#262262;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path54"
inkscape:connector-curvature="0" /></g><g
id="g56"
transform="translate(485.0861,429.7925)"><path
d="m 0,0 c 0,0 -2.214,3.359 -9.736,2.059 0,0 5.987,28.738 36.298,38.806 C 26.562,40.865 -2.82,24.275 0,0 M 0.583,-33.208 0.58,-33.211 c -1.297,-2.026 -2.821,-3.579 -4.53,-4.616 -1.515,-0.933 -3.178,-1.425 -4.743,-1.425 -0.528,0 -1.044,0.057 -1.539,0.17 l -2.209,0.507 2.184,0.603 c 1.63,0.451 3.063,1.347 4.259,2.664 1.014,1.108 1.856,2.485 2.577,4.213 1.175,2.82 1.784,6.162 1.81,9.936 -0.049,3.718 -0.683,7.054 -1.886,9.902 -0.703,1.654 -1.585,3.056 -2.621,4.163 -1.227,1.311 -2.671,2.178 -4.294,2.576 l -2.187,0.538 2.179,0.572 c 0.48,0.126 0.998,0.196 1.539,0.209 h 0.031 l 1.688,-0.153 c 1.045,-0.206 2.104,-0.616 3.061,-1.185 1.755,-1.031 3.302,-2.567 4.598,-4.565 2.155,-3.374 3.315,-7.536 3.357,-12.042 -0.028,-4.548 -1.159,-8.717 -3.271,-12.064 m 101.949,51.176 c 0,0 -0.075,0.05 -0.226,0.136 -0.541,0.327 -1.113,0.603 -1.715,0.815 -3.044,1.241 -9.881,3.186 -21.906,2.623 -0.029,0 -0.056,0 -0.085,-0.001 C 52.916,21.123 30.022,10.922 30.022,10.922 c 0,0 1.439,1.761 3.453,3.692 10e-4,0 10e-4,10e-4 0.002,10e-4 1.052,0.974 2.355,2.076 3.912,3.227 0.046,0.031 0.088,0.063 0.124,0.093 8.708,6.384 25.34,14.163 51.625,9.541 -0.989,1.124 -2.002,2.192 -3.036,3.215 -1.112,0.883 -2.231,1.693 -3.354,2.456 0.02,-0.012 0.039,-0.023 0.059,-0.036 0,0 -17.016,19.415 -48.683,15.891 C 30.19,48.622 25.983,47.867 21.66,46.564 21.653,46.563 21.646,46.562 21.64,46.56 L 21.638,46.558 C 11.48,43.492 0.683,37.387 -8.719,25.911 -9.29,25.193 -9.841,24.479 -10.376,23.77 c -0.065,-0.099 -0.141,-0.202 -0.226,-0.307 -1.182,-1.581 -2.271,-3.14 -3.279,-4.674 -3.266,-5.427 -5.631,-11.665 -6.311,-13.545 -10.58,-32.401 2.586,-57.55 5.144,-61.967 8.93,-15.158 24.565,-32.355 50.771,-37.327 0.197,-0.047 0.382,-0.101 0.582,-0.147 1.723,-0.367 4.864,-0.929 8.908,-1.196 1.524,-0.069 3.088,-0.094 4.699,-0.067 1.548,-0.009 2.999,0.017 4.335,0.064 0.396,0.028 0.74,0.041 1.044,0.044 5.102,0.238 8.272,0.775 8.272,0.775 -26.543,1.299 -39.847,13.409 -45.691,21.142 -1.325,1.648 -2.46,3.42 -3.377,5.316 -0.361,0.71 -0.523,1.115 -0.523,1.115 8.459,-7.181 20.294,-13.362 20.294,-13.362 10.611,-4.993 21.737,-7.451 33.524,-5.837 0,0 24.645,2.263 34.464,25.09 -0.423,0.322 -0.366,0.278 -0.79,0.6 -0.652,-0.526 -1.294,-1.023 -1.926,-1.496 -0.991,-0.651 -1.964,-1.357 -2.937,-2.07 -5.265,-3.485 -9.561,-5.128 -12.12,-5.879 -19.359,-4.887 -37.273,-1.252 -52.93,12.455 -7.253,6.349 -11.754,14.352 -11.944,24.291 -0.124,6.465 -0.19,12.935 -0.136,19.4 0.085,10.181 7.246,17.921 17.394,19.284 20.561,2.759 41.234,3.71 61.947,4.193 3.174,0.073 5.981,0.037 7.458,-3.356 0.025,-0.058 0.363,0.02 0.552,0.035 1.4,4.461 -0.617,9.27 -4.29,11.624"
style="fill:#262262;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path58"
inkscape:connector-curvature="0" /></g></g></svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
xml:space="preserve"
width="175.35599"
height="193.19984"
viewBox="0 0 175.35599 193.19985"
sodipodi:docname="logo_solo_on_dark.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath20"><path
d="M 0,821.614 H 1366 V 0 H 0 Z"
id="path18"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1278"
inkscape:window-height="699"
id="namedview4"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.8617185"
inkscape:cx="257.20407"
inkscape:cy="172.193"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="gvisor_final-logo_20190313"
transform="matrix(1.3333333,0,0,-1.3333333,-614.45037,638.96254)"><g
id="g48"
transform="translate(548.2423,363.2484)"><path
d="m 0,0 c 16.655,21.121 22.696,44.434 18.328,70.995 3.068,0 5.743,-0.023 8.417,0.007 2.222,0.025 4.443,0.102 6.664,0.175 4.79,0.154 4.818,0.165 5.88,-4.582 3.145,-14.05 2.18,-28.089 -0.179,-42.118 -0.25,-1.492 -0.7,-2.956 -0.864,-4.454 C 37.05,9.081 30.089,3.645 20.165,1.097 13.787,-0.54 7.323,-0.829 0,0"
style="fill:#fbb03b;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path50"
inkscape:connector-curvature="0" /></g><g
id="g52"
transform="translate(544.6891,396.1771)"><path
d="M 0,0 C 0,2.593 -3.457,4.321 -3.457,4.321 -0.864,5.186 0,8.644 0,8.644 0,8.644 0.865,5.186 3.458,4.321 3.458,4.321 0,2.593 0,0 m -17.099,6.453 c 0,6.742 -8.989,11.237 -8.989,11.237 6.742,2.247 8.989,11.237 8.989,11.237 0,0 2.247,-8.99 8.99,-11.237 0,0 -8.99,-4.495 -8.99,-11.237"
style="fill:#fbb03b;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path54"
inkscape:connector-curvature="0" /></g><g
id="g56"
transform="translate(485.0861,429.7923)"><path
d="m 0,0 c 0,0 -2.214,3.359 -9.736,2.059 0,0 5.987,28.738 36.298,38.806 C 26.562,40.865 -2.82,24.275 0,0 M 0.583,-33.208 0.58,-33.211 c -1.297,-2.026 -2.821,-3.578 -4.53,-4.615 -1.515,-0.934 -3.178,-1.425 -4.743,-1.425 -0.528,0 -1.044,0.056 -1.539,0.169 l -2.209,0.507 2.184,0.603 c 1.63,0.451 3.063,1.347 4.259,2.664 1.014,1.108 1.856,2.485 2.577,4.214 1.175,2.819 1.784,6.161 1.81,9.935 -0.049,3.719 -0.683,7.054 -1.886,9.902 -0.703,1.655 -1.585,3.057 -2.621,4.163 -1.227,1.311 -2.671,2.178 -4.294,2.576 l -2.187,0.538 2.179,0.572 c 0.48,0.127 0.998,0.196 1.539,0.209 l 0.031,10e-4 1.688,-0.154 c 1.045,-0.206 2.104,-0.615 3.061,-1.184 1.755,-1.032 3.302,-2.568 4.598,-4.565 2.155,-3.374 3.315,-7.537 3.357,-12.043 -0.028,-4.548 -1.159,-8.717 -3.271,-12.064 m 101.949,51.176 c 0,0 -0.075,0.051 -0.226,0.137 -0.541,0.326 -1.113,0.602 -1.715,0.814 -3.044,1.241 -9.881,3.187 -21.906,2.623 -0.029,0 -0.056,0 -0.085,-0.001 C 52.916,21.123 30.022,10.923 30.022,10.923 c 0,0 1.439,1.76 3.453,3.691 10e-4,10e-4 10e-4,10e-4 0.002,0.002 1.052,0.973 2.355,2.076 3.912,3.226 0.046,0.032 0.088,0.063 0.124,0.094 8.708,6.383 25.34,14.162 51.625,9.54 -0.989,1.124 -2.002,2.193 -3.036,3.215 -1.112,0.884 -2.231,1.694 -3.354,2.456 0.02,-0.012 0.039,-0.023 0.059,-0.036 0,0 -17.016,19.415 -48.683,15.891 C 30.19,48.622 25.983,47.868 21.66,46.564 21.653,46.563 21.646,46.562 21.64,46.56 L 21.638,46.558 C 11.48,43.492 0.683,37.387 -8.719,25.911 c -0.571,-0.718 -1.122,-1.431 -1.657,-2.14 -0.065,-0.1 -0.141,-0.202 -0.226,-0.307 -1.182,-1.582 -2.271,-3.141 -3.279,-4.674 -3.266,-5.427 -5.631,-11.666 -6.311,-13.546 -10.58,-32.401 2.586,-57.549 5.144,-61.967 8.93,-15.157 24.565,-32.355 50.771,-37.327 0.197,-0.046 0.382,-0.101 0.582,-0.146 1.723,-0.367 4.864,-0.929 8.908,-1.197 1.524,-0.069 3.088,-0.094 4.699,-0.066 1.548,-0.01 2.999,0.017 4.335,0.064 0.396,0.027 0.74,0.041 1.044,0.044 5.102,0.237 8.272,0.774 8.272,0.774 -26.543,1.3 -39.847,13.41 -45.691,21.142 -1.325,1.648 -2.46,3.421 -3.377,5.316 -0.361,0.711 -0.523,1.115 -0.523,1.115 8.459,-7.18 20.294,-13.361 20.294,-13.361 10.611,-4.993 21.737,-7.452 33.524,-5.838 0,0 24.645,2.264 34.464,25.09 -0.423,0.322 -0.366,0.278 -0.79,0.6 -0.652,-0.526 -1.294,-1.022 -1.926,-1.496 -0.991,-0.65 -1.964,-1.357 -2.937,-2.07 -5.265,-3.485 -9.561,-5.127 -12.12,-5.879 -19.359,-4.887 -37.273,-1.252 -52.93,12.455 -7.253,6.349 -11.754,14.353 -11.944,24.291 -0.124,6.466 -0.19,12.935 -0.136,19.4 0.085,10.181 7.246,17.921 17.394,19.284 20.561,2.759 41.234,3.71 61.947,4.193 3.174,0.074 5.981,0.037 7.458,-3.356 0.025,-0.058 0.363,0.02 0.552,0.035 1.4,4.462 -0.617,9.27 -4.29,11.624"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path58"
inkscape:connector-curvature="0" /></g></g></svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
xml:space="preserve"
width="246.17325"
height="246.17325"
viewBox="0 0 246.17325 246.17326"
sodipodi:docname="logo_solo_on_dark_full.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath20"><path
d="M 0,821.614 H 1366 V 0 H 0 Z"
id="path18"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1278"
inkscape:window-height="699"
id="namedview4"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.8617185"
inkscape:cx="291.21659"
inkscape:cy="198.28704"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="gvisor_final-logo_20190313"
transform="matrix(1.3333333,0,0,-1.3333333,-580.43785,665.8419)"><circle
id="path83"
cx="527.64337"
cy="-407.06647"
r="92.314972"
transform="scale(1,-1)"
style="fill:#262262;fill-opacity:1;stroke-width:0.48076925" /><g
id="g48"
transform="translate(548.2423,363.2484)"><path
d="m 0,0 c 16.655,21.121 22.696,44.434 18.328,70.995 3.068,0 5.743,-0.023 8.417,0.007 2.222,0.025 4.443,0.102 6.664,0.175 4.79,0.154 4.818,0.165 5.88,-4.582 3.145,-14.05 2.18,-28.089 -0.179,-42.118 -0.25,-1.492 -0.7,-2.956 -0.864,-4.454 C 37.05,9.081 30.089,3.645 20.165,1.097 13.787,-0.54 7.323,-0.829 0,0"
style="fill:#fbb03b;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path50"
inkscape:connector-curvature="0" /></g><g
id="g52"
transform="translate(544.6891,396.1771)"><path
d="M 0,0 C 0,2.593 -3.457,4.321 -3.457,4.321 -0.864,5.186 0,8.644 0,8.644 0,8.644 0.865,5.186 3.458,4.321 3.458,4.321 0,2.593 0,0 m -17.099,6.453 c 0,6.742 -8.989,11.237 -8.989,11.237 6.742,2.247 8.989,11.237 8.989,11.237 0,0 2.247,-8.99 8.99,-11.237 0,0 -8.99,-4.495 -8.99,-11.237"
style="fill:#fbb03b;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path54"
inkscape:connector-curvature="0" /></g><g
id="g56"
transform="translate(485.0861,429.7923)"><path
d="m 0,0 c 0,0 -2.214,3.359 -9.736,2.059 0,0 5.987,28.738 36.298,38.806 C 26.562,40.865 -2.82,24.275 0,0 M 0.583,-33.208 0.58,-33.211 c -1.297,-2.026 -2.821,-3.578 -4.53,-4.615 -1.515,-0.934 -3.178,-1.425 -4.743,-1.425 -0.528,0 -1.044,0.056 -1.539,0.169 l -2.209,0.507 2.184,0.603 c 1.63,0.451 3.063,1.347 4.259,2.664 1.014,1.108 1.856,2.485 2.577,4.214 1.175,2.819 1.784,6.161 1.81,9.935 -0.049,3.719 -0.683,7.054 -1.886,9.902 -0.703,1.655 -1.585,3.057 -2.621,4.163 -1.227,1.311 -2.671,2.178 -4.294,2.576 l -2.187,0.538 2.179,0.572 c 0.48,0.127 0.998,0.196 1.539,0.209 l 0.031,10e-4 1.688,-0.154 c 1.045,-0.206 2.104,-0.615 3.061,-1.184 1.755,-1.032 3.302,-2.568 4.598,-4.565 2.155,-3.374 3.315,-7.537 3.357,-12.043 -0.028,-4.548 -1.159,-8.717 -3.271,-12.064 m 101.949,51.176 c 0,0 -0.075,0.051 -0.226,0.137 -0.541,0.326 -1.113,0.602 -1.715,0.814 -3.044,1.241 -9.881,3.187 -21.906,2.623 -0.029,0 -0.056,0 -0.085,-0.001 C 52.916,21.123 30.022,10.923 30.022,10.923 c 0,0 1.439,1.76 3.453,3.691 10e-4,10e-4 10e-4,10e-4 0.002,0.002 1.052,0.973 2.355,2.076 3.912,3.226 0.046,0.032 0.088,0.063 0.124,0.094 8.708,6.383 25.34,14.162 51.625,9.54 -0.989,1.124 -2.002,2.193 -3.036,3.215 -1.112,0.884 -2.231,1.694 -3.354,2.456 0.02,-0.012 0.039,-0.023 0.059,-0.036 0,0 -17.016,19.415 -48.683,15.891 C 30.19,48.622 25.983,47.868 21.66,46.564 21.653,46.563 21.646,46.562 21.64,46.56 L 21.638,46.558 C 11.48,43.492 0.683,37.387 -8.719,25.911 c -0.571,-0.718 -1.122,-1.431 -1.657,-2.14 -0.065,-0.1 -0.141,-0.202 -0.226,-0.307 -1.182,-1.582 -2.271,-3.141 -3.279,-4.674 -3.266,-5.427 -5.631,-11.666 -6.311,-13.546 -10.58,-32.401 2.586,-57.549 5.144,-61.967 8.93,-15.157 24.565,-32.355 50.771,-37.327 0.197,-0.046 0.382,-0.101 0.582,-0.146 1.723,-0.367 4.864,-0.929 8.908,-1.197 1.524,-0.069 3.088,-0.094 4.699,-0.066 1.548,-0.01 2.999,0.017 4.335,0.064 0.396,0.027 0.74,0.041 1.044,0.044 5.102,0.237 8.272,0.774 8.272,0.774 -26.543,1.3 -39.847,13.41 -45.691,21.142 -1.325,1.648 -2.46,3.421 -3.377,5.316 -0.361,0.711 -0.523,1.115 -0.523,1.115 8.459,-7.18 20.294,-13.361 20.294,-13.361 10.611,-4.993 21.737,-7.452 33.524,-5.838 0,0 24.645,2.264 34.464,25.09 -0.423,0.322 -0.366,0.278 -0.79,0.6 -0.652,-0.526 -1.294,-1.022 -1.926,-1.496 -0.991,-0.65 -1.964,-1.357 -2.937,-2.07 -5.265,-3.485 -9.561,-5.127 -12.12,-5.879 -19.359,-4.887 -37.273,-1.252 -52.93,12.455 -7.253,6.349 -11.754,14.353 -11.944,24.291 -0.124,6.466 -0.19,12.935 -0.136,19.4 0.085,10.181 7.246,17.921 17.394,19.284 20.561,2.759 41.234,3.71 61.947,4.193 3.174,0.074 5.981,0.037 7.458,-3.356 0.025,-0.058 0.363,0.02 0.552,0.035 1.4,4.462 -0.617,9.27 -4.29,11.624"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path58"
inkscape:connector-curvature="0" /></g></g></svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Some files were not shown because too many files have changed in this diff Show More