Skip to content

Commit 60b59a5

Browse files
Build Kubelet without Docker
A KEP proposing supporting building a Kubelet without docker, via the use of build tags.
1 parent 8f238f5 commit 60b59a5

File tree

1 file changed

+294
-0
lines changed

1 file changed

+294
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
---
2+
title: Building a Dockerless Kubelet
3+
authors:
4+
- "@mattjmcnaughton"
5+
owning-sig: sig-node
6+
participating-sigs:
7+
- sig-testing
8+
- sig-release
9+
- sig-cluster-lifecycle
10+
reviewers:
11+
- "@dims"
12+
- "@BenTheElder"
13+
- TBD
14+
approvers:
15+
- "@derekwaynecarr"
16+
- "@dchen1107"
17+
editor: TBD
18+
creation-date: 2020-02-05
19+
last-updated: 2020-02-09
20+
status: provisional
21+
see-also:
22+
- "/keps/sig-cloud-provider/20190729-building-without-in-tree-providers.md"
23+
---
24+
25+
# Building a Dockerless Kubelet
26+
27+
## Table of Contents
28+
29+
<!-- toc -->
30+
- [Release Signoff Checklist](#release-signoff-checklist)
31+
- [Summary](#summary)
32+
- [Motivation](#motivation)
33+
- [History](#history)
34+
- [Returning to Motivation](#returning-to-motivation)
35+
- [Goals](#goals)
36+
- [Non-Goals](#non-goals)
37+
- [Proposal](#proposal)
38+
- [User Stories](#user-stories)
39+
- [Story 1](#story-1)
40+
- [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints)
41+
- [Risks and Mitigations](#risks-and-mitigations)
42+
- [Design Details](#design-details)
43+
- [Test Plan](#test-plan)
44+
- [Graduation Criteria](#graduation-criteria)
45+
- [Upgrade / Downgrade Strategy](#upgrade--downgrade-strategy)
46+
- [Version Skew Strategy](#version-skew-strategy)
47+
- [Implementation History](#implementation-history)
48+
- [Drawbacks](#drawbacks)
49+
- [Alternatives](#alternatives)
50+
<!-- /toc -->
51+
52+
## Release Signoff Checklist
53+
54+
- [ ] kubernetes/enhancements issue in release milestone, which links to KEP (this should be a link to the KEP location in kubernetes/enhancements, not the initial KEP PR)
55+
- [ ] KEP approvers have set the KEP status to `implementable`
56+
- [ ] Design details are appropriately documented
57+
- [ ] Test plan is in place, giving consideration to SIG Architecture and SIG Testing input
58+
- [ ] Graduation criteria is in place
59+
- [ ] "Implementation History" section is up-to-date for milestone
60+
- [ ] User-facing documentation has been created in [kubernetes/website], for publication to [kubernetes.io]
61+
- [ ] Supporting documentation e.g., additional design documents, links to mailing list discussions/SIG meetings, relevant PRs/issues, release notes
62+
63+
## Summary
64+
65+
This proposal outlines a plan to enable building a dockerless Kubelet. We
66+
define a dockerless Kubelet as a Kubelet with no "Docker-specific" code and
67+
no dependency on the `docker/docker` Golang package. We define "Docker-specific"
68+
code as code which only serves a purpose when Docker is the container runtime.
69+
"Docker-specific" code is never executed when the Kubelet uses a remote
70+
container runtime (i.e. containerd or CRI-O).
71+
72+
Supporting building a dockerless Kubelet is a precursor to moving all
73+
"Docker-specific" Kubelet code out-of-tree, in the name of treating Docker like
74+
any other container runtime.
75+
76+
At a high level, this undertaking is similar to the efforts of
77+
sig-cloud-provider to support [Building Kubernetes Without In-Tree Cloud Providers](/keps/sig-cloud-provider/20190729-building-without-in-tree-providers.md).
78+
A big thanks to them for their leadership; much of this KEP is based off their great work :)
79+
80+
## Motivation
81+
82+
For this KEP to be worthwhile, we must believe the following two statements.
83+
84+
First, we must see a benefit to a dockerless Kubelet.
85+
Second, we must believe supporting the ability to compile a dockerless Kubelet is
86+
a useful first step towards a truly dockerless Kubelet.
87+
88+
A quick review of recent Kubernetes history provides context when considering
89+
whether we agree with the statements in question.
90+
91+
### History
92+
93+
With 1.5, Kubernetes introduced the [Container Runtime Interface](https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/)
94+
(CRI). The CRI defines a standard interface for the Kubelet to communicate with container
95+
runtimes. At the time of the CRI's release, Kubernetes supported only the Docker
96+
and rkt container runtimes. Kubernetes introduced the CRI to avoid needing
97+
provider specific code for each new container runtime.
98+
99+
Since the CRI's release, the Kubelet only interacts with container runtimes via
100+
the CRI. For increasingly popular CRI implementations like containerd or CRI-O,
101+
the singular focus on the CRI poses no obstacles, as these container runtimes
102+
supported the CRI from the start. However, the Kubelet still needed a solution for
103+
Docker and rkt, in-tree runtimes which did not support the CRI. In-tree support
104+
for Rkt was deprecated, leaving only Docker as an issue.
105+
106+
Ultimately, the Kubelet introduced the `dockershim` to address Docker's lack of
107+
CRI support. When a cluster operator chooses to use Docker as the container
108+
runtime, the Kubelet starts running the `dockershim` in a separate go
109+
routine within the main `kubelet` process; it is not currently possible to run
110+
the `dockershim` as a standalone binary/process. The `dockershim` supports the
111+
CRI, so the Kubelet communicates with `dockershim` as if it was any other remote
112+
container runtime implementing the CRI. The `dockershim` makes the appropriate
113+
calls to the Docker daemon via a heavy dependence on the `docker/docker` client library.
114+
115+
The `docker/docker` client library is a particularly painful dependency because
116+
its pulls in code from many different open source libraries. For those managing
117+
k8s dependencies, it can be extremely difficult to keep up with the changes to
118+
all these dependencies. Additionally, all the open source libraries required by
119+
`docker/docker` bloat the Kubelet binary.
120+
121+
## Returning to Motivation
122+
123+
We can anticipate the following benefits from the Kubelet having no in-tree
124+
"Docker-specific" code and no dependency on the `docker/docker` Golang package.
125+
126+
First, a dockerless Kubelet would truly treat all container runtimes the same.
127+
Second, the Kubelet's scope of responsibility would decrease: it would no longer
128+
be responsible for making Docker conform to the CRI. Finally, the painful
129+
`docker/docker` dependency would be gone.
130+
131+
While the aforementioned benefits are desirable, they do not outweigh the cons
132+
of completely dropping support for Docker as a container runtime, as
133+
Docker remains popular. In order for Kubernetes
134+
to both support Docker as a container runtime, and for the Kubelet do have no
135+
in-tree "Docker-specific" code and no dependency on `docker/docker`, one of two
136+
following paths must be followed: either Docker must begin implementing the CRI natively
137+
or the `dockershim` must be moved out-of-tree into a standalone component.
138+
139+
Clearly, both of these paths forward require significant work. Either effort would
140+
require finding an owner, making non-trivial code changes, and updating patterns
141+
of cluster management/operation.
142+
143+
Faced with a hefty chunk of work, we naturally try to break it up into smaller
144+
components. This desire leads us to our second question: is supporting
145+
compiling a dockerless Kubelet an appropriate first step?
146+
147+
We argue yes. First, the work to support compiling a dockerless Kubelet will
148+
be useful regardless of which path forward we chose. First, to compile a dockerless
149+
Kubelet we must consolidate all "Docker-specific" Kubelet code into specific
150+
locations, which are easier to move out-of-tree or delete entirely when the time comes. Furthermore,
151+
after this initial consolidation, we can create tooling to impose limitations on
152+
where "Docker-specific" code can/cannot live. Second, allowing developers to
153+
compile a dockerless Kubelet assists in testing either proposed solution.
154+
Finally, allowing compiling a dockerless Kubelet allows projects/cluster
155+
operators which already do not depend on Docker to obtain the dockerless
156+
Kubelet's benefits (i.e. smaller binaries) without waiting for the
157+
completion of the longer term projects to make Docker support the CRI or
158+
move `dockershim` out-of-tree.
159+
160+
### Goals
161+
162+
Our goals follow from our motivation:
163+
164+
1. Support building Kubelet, from the `master` branch, without any "Docker-specific" code and without any
165+
dependency on `docker/docker`. As mentioned
166+
previously, we imagine the resulting binaries to be used to test the
167+
different paths for deleting/moving out-of-tree all "Docker-specific" code.
168+
2. Draw clear delineations, with CI support, for what code in Kubelet can and
169+
cannot be "Docker-specific" and depend on `docker/docker`.
170+
171+
### Non-Goals
172+
173+
Our non-goals also follow from our motivation:
174+
175+
1. Either making Docker support the CRI or moving `dockershim` out-of-tree.
176+
2. Removing uses of the `docker/docker` Golang library outside of the Kubelet.
177+
3. Changing the official Kubernetes release builds.
178+
179+
## Proposal
180+
181+
We will undertake the following steps to obtain our goals. First, we will ensure
182+
that all "Docker-specific" code in the Kubelet lives in `dockershim`. Then, we
183+
will add a [build constraint](https://golang.org/pkg/go/build/#hdr-Build_Constraints)
184+
to the Kubelet for a pseudo "build tag" specifying not to include
185+
any in-tree "Docker-specific" code. If builds do not specify this build tag, the Go
186+
compiler will compile the Kubelet as normal. If we do, the Go compiler will
187+
compile the Kubelet without the "Docker-specific" code, and as a result, without
188+
the dependency on `docker/docker`. In other words, it will simulate the aforementioned
189+
code/dependency's removal.
190+
191+
A prototype is available in [kubernetes/kubernetes#87746](https://github.com/kubernetes/kubernetes/pull/87746).
192+
193+
To ensure that this dockerless Kubelet continues to function we will add CI building in this mode,
194+
and CI running end to end tests against it (to be elaborated on in the test plan). Additionally, to
195+
ensure the Kubelet doesn't introduce new dependencies on the `docker/docker`
196+
Golang library, we will add automated tooling enforcing that only the
197+
`dockershim` can depend on `docker/docker`.
198+
199+
One quick additional note - currently `cadvisor` also depends on the
200+
`docker/docker` client library. Since `kubelet` depends on `cadvisor`, the
201+
`kubelet` can not truly be rid of the `docker/docker` client library until `cadvisor` no
202+
longer depends on `docker/docker`. Work to remove the `docker/docker` dependency
203+
from `cadvisor` is being dealt with in separate workstreams.
204+
205+
This proposal follows the previous patterns for similar work, namely the efforts
206+
of sig-cloud-provider to support [Building Without In-Tree Cloud Providers](/keps/sig-cloud-provider/20190729-building-without-in-tree-providers.md).
207+
208+
### User Stories
209+
210+
#### Story 1
211+
212+
As a developer working to make Docker function like any other remote container
213+
runtime, I am attempting to validate that my proposed solution
214+
functions correctly. Using this dockerless build ensures the Kubelet contains no
215+
"Docker-specific" code, and any success/failures can be attributed to my
216+
implementation.
217+
218+
### Implementation Details/Notes/Constraints
219+
220+
A couple high level notes (to be extended over time):
221+
222+
- We implement this functionality using a synthetic `dockerless` tag in go build
223+
constraints on relevant sources. If `GOFLAGS=-tags=dockerless` during build,
224+
then "Docker-specific" code will be excluded from the Kubelet build. With no
225+
"Docker-specific" code, we should also be excluding the dependency on
226+
`docker/docker`.
227+
228+
### Risks and Mitigations
229+
230+
This feature is only developer facing, which removes a large class of risks.
231+
232+
The largest remaining risk is that the build tags fall out of date, or are
233+
burdensome to continue updating, which leads to the dockerless Kubelet build
234+
breaking and/or being costly to maintain. This risk grows the longer the
235+
dockerless Kubelet exists (i.e. the longer it takes to move `dockershim` out of
236+
tree/have Docker support the CRI). Fortunately, these risks can be mitigated via
237+
the CI tooling discussed earlier.
238+
239+
## Design Details
240+
241+
### Test Plan
242+
243+
**Note:** *Section not required until targeted at a release.*
244+
245+
We envision the following testing:
246+
247+
1. A verification, run during pre-submit, which ensures the Kubelet builds when the `dockerless` tag is
248+
enabled.
249+
2. A verification, run during pre-submit, which ensures that only the imports of
250+
`github.com/docker/docker` occur within `pkg/kubelet/dockershim`.
251+
3. Unit tests, run during pre-submit, which execute the standard `pkg/kubelet/...`
252+
unit tests with the `dockerless` tag enabled.
253+
4. A e2e test, run during pre-submit, which executes a simple node e2e test w/ a
254+
Kubelet compiled with the `dockerless` tag enabled.
255+
256+
### Graduation Criteria
257+
258+
**Note:** *Section not required until targeted at a release.*
259+
260+
TBD
261+
262+
### Upgrade / Downgrade Strategy
263+
264+
N/A
265+
266+
### Version Skew Strategy
267+
268+
N/A
269+
270+
## Implementation History
271+
272+
- original prototype [kubernetes/kubernetes#87746](https://github.com/kubernetes/kubernetes/pull/87746)
273+
- original KEP PR [TBD]
274+
275+
## Drawbacks
276+
277+
One drawback is the opportunity cost of pursuing this workstream as opposed to
278+
other possible workstreams.
279+
280+
Another drawback is the slight additional cost of the CI tooling we propose
281+
adding.
282+
283+
## Alternatives
284+
285+
One alternative would be to do nothing.
286+
287+
Another alternative could be waiting to address "Docker-specific" code in the
288+
Kubelet until we have more momentum around one of the longer-term solutions
289+
discussed above. If we waited, we could delete "Docker-specific" code entirely,
290+
instead of just compiling without it.
291+
292+
Finally, we could attempt to have a long-running branch in which all
293+
"Docker-specific" code has been deleted, instead of attempting to support
294+
compiling a dockerless Kubelet from master.

0 commit comments

Comments
 (0)