Skip to content

Commit 8547df3

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 8547df3

File tree

1 file changed

+293
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)