Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(344)

Side by Side Diff: deploytool/README.md

Issue 2182213002: deploytool: Add README.md, migrate docs to it. (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Rename to "luci_deploy" Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « README.md ('k') | deploytool/api/deploy/checkout.proto » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 The LUCI cloud services deployment tool
2 =======================================
3
4 The LUCI project hosts code on Google AppEngine, Google Container Engine (via
5 [Kubernetes](http://kubernetes.io/)), and several other locations. The code
6 layout is complex and modular, which is oftentimes at odds with the layout
7 requirements of supported deployment tools such as `gcloud` and `docker`. The
8 `luci_deploy` attempts to smooth that over by providing:
9
10 * A common declarative deployment configuration language.
11 * Hermetic, pinned source checkouts.
12 * A single tool capable of organizing and executing deployment programs.
13 * A utility that facilitates deployment management given its understanding of
14 the deployment parameters.
15
16 While much of the underlying code in the deployment tool is cross-platform, it
17 is specifically targeting Linux support. Any deployment from other platforms is,
18 at this time, unsupported.
19
20 The deployment tool doesn't reimplement all of the functionality of existing
21 tools; instead, it manages configurations and layouts and employs existing
22 tooling to perform the actual deployment operations. Some tools that it uses
23 are:
24 * [gcloud](https://cloud.google.com/sdk/gcloud/), the Google Cloud SDK tool.
25 * [kubectl](http://kubernetes.io/docs/user-guide/kubectl-overview/), the
26 Kubernetes control tool.
27 * [aedeploy](https://godoc.org/google.golang.org/appengine/cmd/aedeploy),
28 a tool which collects `GOPATH` packages for Docker deployment.
29 * [docker](https://www.docker.com/), a container management system used by
30 Kubernetes.
31
32 Deployment configuration for a given deployable component is stored in two
33 places:
34
35 1. Generic component configuration and requirements are stored alongside the
36 component in its source repository.
37 1. Deployment-specific parameters are stored in a separate repository, and
38 project the generic component layout into a product space.
39
40 The component-specific configuration details which resources the component
41 needs, which services it employs, and its relationship with other components.
42 The deployment projection then takes that generic configuration and applies it
43 to a set of specific deployment parameters. For example:
44
45 * One deployment may project a component into a production environment,
46 allocating expensive CPU resources.
47 * A development deployment may project the same component into a development
48 environment.
49 * A staging deployment may project the same component into a staging
50 enviornment alongside other components from other projects.
51
52
53 ## Overview and Terminology
54
55 Deployment configuration uses the following concepts:
56
57 * A **source** is a specific named repository checked out at a specific
58 revision.
59 * A **source group** is a collection of **source** repositories.
60 * A **component** is a single buildable and deployable entity. Its configuration
61 resides in a specific **source**.
62 * An **application** is a collection of deployable **component** pointers. Each
63 pointer is a subpath to the **component** configuration within its **source**.
64 * A **resource** is a global cloud resource (e.g., cloud project, Kubernetes
65 cluster, etc.).
66 * A **deployment** binds an **application** to a **source group** (and,
67 consequently, a specific set of **sources**) and a set of **resources**.
68
69 During deployment, several operations are performed:
70
71 * The **working directory** is used to contain files generated and managed by
72 the `luci_deploy`.
73 * The **checkout** is a read-only directory containing all of the **sources**
74 checked out at their specific revisions and initialized.
75 * The **staging** directory is a constructed environment containing deployment
76 and component sources and generated files organized such that deployment tools
77 can operate on them. See [Staging](#staging) for more information.
78
79 A user will first perform a `checkout`, which loads all of the configured
80 **sources** at their specified revisions into the working directory. Afterwards,
81 the user performs operations on the checkout:
82 * `deploy`, which deploy the configured **deployments** and their
83 composite **components**.
84 * `manage`, which offers component management utilities based on the
85 deployment configuration.
86
87
88 ## Deployment Layout
89
90 The deployment layout is a filesystem-based configuration structure that
91 defines the parameters of the configured deployments. Unless stated otherwise,
92 all layout component names may only contain:
93 - Alphanumeric characters (`[0-9a-zA-Z]`)
94 - A hyphen (`-`).
95
96 Configuration files are text-encoded protobufs. All protobufs used by the
97 `luci_deploy` are defined in its [api directory](api/deploy). Text protobuf
98 configuration files have the ".cfg" suffix. The protobuf messages used in the
99 layout are defined in [config.proto](api/deploy/config.proto).
100
101 The default deployment layout consists of a root `layout.cfg` file and several
102 subdirectories defining **source groups**, **applications**, and
103 **deployments**. Note that the layout depicted below is the *default* layout;
104 the specific config directory paths may be overridden in `layout.cfg`.
105
106 ```
107 /layout.cfg
108 /sources/
109 <source-group-name>/ (Defines a source group).
110 <source-name>.cfg (Defines a source within the source group).
111
112 /applications/
113 <application-name>.cfg (Defines a application).
114
115 /deployments/
116 <deployment-name>.cfg (Defines a deployment).
117 ```
118
119 All configuration files
120 * `layout.cfg`, a text protobuf file containing a `Layout` message.
121 * `<source-group-name>`, which defines a source group.
122 * `<source-name>.cfg`, which defines a `Source` message within its
123 **source group** parent directory.
124 * `<application-name>.cfg`, which defines an `Application` message.
125 * `<deployment-name>.cfg`, which defines a `Deployment` message.
126
127 ## Sources
128
129 **Sources** define a fully-specified repository in which **component**
130 configuration and data are stored. `luci_deploy` will manage the source
131 checkouts configured in the deployment layout.
132
133 A **source** is a file located within a source group directory named
134 `<source-name>.cfg`. The source is specified using the `Source` text protobuf,
135 defined in [config.proto](api/deploy/config.proto). Each **source** name is
136 unique within its **source group**, but **source** names can (and likely will)
137 be re-used across other **source groups** to enable deployment tracks (see
138 [Source Group Versioning](#source-group-versioning)).
139
140 Each **source** checkout is read-only, meaning that after the `checkout`
141 operation is complete, no other deployment operations will modify its contents.
142
143 ### Source Initialization
144
145 **Sources** may require additional post-checkout steps to render them usable.
146 Such sources can offer initialization scripts that will be run by `luci_deploy`
147 during the `checkout` phase after the source has been checked out.
148
149 Initialization scripts are specified by adding a `SourceLayout` text protobuf
150 file called `luci-deploy.cfg`, to the root of the **source**. If present,
151 this file will be interpreted, and any initialization options present will be
152 included as part of the **source**'s checkout operation.
153
154 The `SourceLayout` protobuf is defined in
155 [checkout.proto](api/deploy/checkout.proto).
156
157 Note that the **source**'s definition *must* have `run_scripts` set to true in
158 order for initialization scripts to be executed. This is a security precaution
159 to prevent untrusted **source** repositories from adding and executing
160 `luci_deploy` commands without the user's permission.
161
162 ### Source Group Versioning
163
164 **Applications** bind components to source *name*. Deployments then bind those
165 **applications** to **source groups**. Therefore, the specific **source** that
166 is used in a deployment is determined by the **deployment**'s
167 choice of **source group**.
168
169 An example is a directory layout with two source groups, one named `canary` and
170 one named `production`.
171
172 ```
173 sources/canary/base.cfg
174 sources/production/base.cfg
175 ```
176
177 The source named `base` is defined in both **source groups** is then used in
178 an **application**. At this point, the **application's** specific **source**
179 is not known, since the choice of *which* `base` to use requires a **source
180 group** to be selected. In other words, the **application** is bound to
181 `sources/*/base.cfg`, and the choice of which `*` to use is left to a specific
182 **deployment**.
183
184 A *canary* deployment can bind the **application** to the `canary` **source
185 group**, causing its **components** to be loaded from the version of `base`
186 defined in `sources/canary/base.cfg`. A *production* deployment can bind the
187 same **application** to the `production` **source group**, causing its
188 **components** to be loaded from `sources/production/base.cfg`.
189
190 ### Source-Relative Paths
191
192 Paths referenced within a source are referenced using "source-relative paths".
193 These paths are:
194 * Operating system independent, as they all use "/" as their delimiter.
195 * Either **absolute** (starting with a "/") or **relative** (not starting with
196 a "/"). Relative paths are relative to the configuration file in which they
197 are specified.
198
199 ## Checkout
200
201 Prior to deployment, a user must sync the checked out sources with the
202 configured sources using the `checkout` sub-command. This checks out *all*
203 sources defined in the deployment layout and runs any configured initialization
204 scripts to initialize them.
205
206 A `checkout` is a manual operation. If the configured **sources** change, a new
207 `checkout` operation must be performed to sync the on-disk checkout with the
208 configured sources.
209
210 Performing a checkout is simple:
211
212 ```shell
213 $ luci_deploy checkout
214 ```
215
216 ### Local Checkout
217
218 It is oftentimes useful for a user to stage (for testing) or deploy (for triage)
219 code from their local checkout. Rather than editing the **source** files to use
220 `file:///` URLs, the user may define a set of repository overrides in their
221 [User Configuration](#user-configuration). Running the `checkout` sub-command
222 with the `--local` flag will cause the checkout to prefer the user configuration
223 repositroies to those configured in the **sources**.
224
225 ```shell
226 $ luci_deploy checkout --local
227 ```
228
229 **NOTE**: The checkout will continue to use the local overrides until the
230 `checkout` sub-command is re-run without the `--local` flag. However, also note
231 that a checkout containing a local override is considered *tainted*.
232
233 ## Deployment
234
235 Deployment is accessed using the `deploy` sub-command. A user may deploy a
236 single component or a full deployment. All deployment operations are run in
237 stages, and, within each stage, in parallel.
238
239 ```shell
240 # Deploy all Components within a Deployment.
241 $ luci_deploy deploy mydeployment
242
243 # Deploy a specific set of Components.
244 $ luci_deploy deploy mydeployment/component-a mydeployment/component-b
245 ```
246
247 The `deploy` operation consists of several sub-stages:
248 1. `stage`, where deployable **components** are generated from their sources and
249 configurations. See [Staging](#staging) for more information.
250 1. `localbuild`, where any local build operations are performed on the staged
251 **components**. For some component types, this doubles as a sanity check prior
252 to engaging remote services.
253 1. `push`, where **components** are uploaded to their remote platforms.
254 1. `commit`, where the uploaded **components** are activated and become live.
255
256 For testing and debugging purposes, a deployment can be stopped prior to a full
257 commit by using the `--stage` parameter. For example, to assert that all
258 **components** in a deployment can be successfully staged and locally built, a
259 user may run:
260
261 ```shell
262 $ luci_deploy deploy --stage=localbuild mydeployment
263 ```
264
265 ## Component Configuration
266
267 A **component** is a single buildable/deployable unit. **Components** are
268 defined in **application** configuration files, and are specified as paths to
269 `Component` messages within a **source**. `Component` messages are defined in
270 [component.proto](api/deploy/component.proto).
271
272 **Components** are intentionally defined within a **source**, as opposed to the
273 deployment layout, because their specific composition and resource requirements
274 will be versioned alongside their deployable code. For example, different
275 versions of a Google AppEngine app may define different datastore indexes based
276 on the underlying functionality of their code.
277
278 ## User Configuration
279
280 The user may include a configuration file in their home directory at
281 `~/.luci_deploy.cfg`. If present, this file will be loaded alongside the
282 layout configuration and incorporated into `luci_deploy` behavior.
283
284 The user configuration file is a `UserConfig` text protobuf defined in
285 [userconfig.proto](api/deploy/userconfig.proto).
286
287 ## Staging
288
289 A staging space is created for each deployable Component. Staging offers
290 `luci_deploy` an isolated canvas with which it can the filesystem layouts for
291 that Component's actual deployment tooling to operate. All file operations,
292 generation, and structuring are performed in the staging state such that the
293 resulting staging directory is available for tooling or humans to use.
294
295 The staging space for a given Component depends on that Component's type.
296 A staging layout is intended to be human-navigatable while conforming to any
297 layout requirements imposed by that Component's deployment tooling.
298
299 One goal that is enforced is that the actual checkout directories used by
300 any given Component are considered read-only. This means that staging for
301 Components which require generated files to exist alongside source must
302 copy or mirror that source elsewhere. Some of the more convoluted aspects of
303 staging layouts are the result of this requirement.
304
305 ### AppEngine
306
307 AppEngine deployments are composed of two sets of information:
308 * Individual AppEngine modules, including the default module.
309 * AppEngine Project-wide globals such as Index, Cron, Dispatch, and Queue
310 settings.
311
312 The individual Components are staged and deployed independently. The globals
313 are composed of their respective settings in each individual Component
314 associated with the AppEngine project regardless of whether that Component is
315 actually being deployed. The aggregate globals are re-asserted once per
316 cloud project at the end of module deployment.
317
318 References to static content are flattened into static directories within the
319 staging area. The generated YAML files are configured to point to this
320 flattened space regardless of the original static content's location within
321 the source.
322
323 #### dev_appserver
324
325 Moving Component configuration into protobufs and constructing composite
326 GOPATH and generated configuration files prevents AppEngine tooling from
327 working out of the box in the source repository.
328
329 The offered solution is to manually stage the Components under test, then
330 run tooling against the staged Component directories. The user may optionally
331 install the staged paths (GOPATH, etc.) or use their default environment's
332 paths.
333
334 One downside to this solution is that staging operates on a snapshot of the
335 repository, meaning that changes to the repository won't be reflected in the
336 staged environment. The user can address this by either manually re-staging
337 the Deployment when a file changes. The user may also structure their
338 application such that the staged content doesn't change frequently (e.g.,
339 for Go, have a simple entry point that immediately imports the main app
340 logic). Specific structures depend on the type of Component and how it is
341 staged (see below).
342
343 In the future, a command to bootstrap "dev_appserver" through the staged
344 environment would be useful.
345
346 #### Go on Classic AppEngine
347
348 Go Classic AppEngine Components are deployed using the `appcfg.py` tool,
349 which is the fastest available method to deploy such applications.
350
351 Because the "app.yaml" file must exist alongside the deployed source, a
352 stub entry point is generated in the staging area. This stub simply imports
353 the actual entry point package.
354
355 The Component's Sources which declare GOPATH presence are combined in a
356 virutal GOPATH within the Component's staging area. This GOPATH is then
357 installed and `appcfg.py`'s "update" method is invoked to upload the
358 Component.
359
360 #### Go on Managed VM
361
362 Go AppEngine Managed VMs use a set of tools for deployment:
363 * `aedeploy`, an AppEngine project tool which copies the various referenced
364 sources across GOPATH entries into a single GOPATH hierarchy for Docker
365 isolation.
366 * `gcloud`, which engages the remote AppEngine service and offers deployment
367 utility.
368 * Behind the scenes, `gcloud` uses `docker` to build the actual deployed
369 image from the source (`aedeploy` target) and assembled GOPATH.
370
371 Because the "app.yaml" file must exist alongside the entry point code, the
372 contents of the entry package are copied (via symlink) into a generated
373 entry point package in the staging area.
374
375 The Component's Sources which declare GOPATH presence are combined in a
376 virutal GOPATH within the Component's staging area. This GOPATH is then
377 collapsed by `aedeploy` when the Managed VM image is built.
378
379 NOTE: because the entry point is actually a clone of the entry point
380 package, "internal/" imports will not work. This can be easily worked around
381 by having the entry point import another non-internal package within the
382 project, and having that package act as the actual entry point.
383
384 #### Static Content Module
385
386 The `luci_deploy` supports the concept of a static content module. This is an
387 AppEngine module whose sole purpose is to, via AppEngine handler definitions,
388 map to uploaded static content. The utility of a static module is that it can
389 be effortlessly updated without impacting actual AppEngine runtime processes.
390 Static modules can be used in conjunction with module-referencing handlers in
391 the default AppEngine module to create the effect of the default module
392 actually hosting the static content.
393
394 Static content modules are staged like other AppEngine modules, only with
395 no running code.
396
397 ### Container Engine / Kubernetes
398
399 The `luci_deploy` supports depoying services to Google Container Engine, which
400 is backed by Kubernetes. A project's Container Engine configuration consists
401 of a series of Container Engine clusters, each of which hosts a series of
402 homogenous machines. Kubernetes Pods, each of which are composed of one or
403 more Kubernetes Components (i.e., Docker images), are deployed to one or more
404 Google Container Engine Clusters.
405
406 The Deployment Component defines a series of Container Engine Pods, an
407 amalgam of a Kubernetes Pod definition and Container Engine requirements of
408 that Kubernetes Pod. Each Kubernetes Pod's Component is built in its own
409 staging area and deployed as part of that Pod to one or more Container Engine
410 clusters.
411
412 The Build phase of Container Engine deployment constructs a local Docker
413 image of each Kubernetes Component. The Push phase pushes those images to
414 the remote Docker image service. The Commit phase enacts the generated
415 Kubernetes/ configuration which references those images on the Container
416 Engine configuration.
417
418 Container Engine management is done in two layers: firstly, the Container
419 Engine configuration is managed with `gcloud` commands. This configures:
420
421 * Which managed Clusters exist on Google Container Engine.
422 * What scopes, system specs, and node count each Cluster has.
423
424 Within a Cluster, several managed Kubernetes pods are deployed. The
425 deployment is done using the `kubectl` tool, selecting the cluster using
426 the "--context" flag to select the `gcloud`-generated Kubernetes context.
427
428 Each `luci_deploy` Component (Kubernetes Pod, at this level) is managed as a
429 Kubernetes Deployment (http://kubernetes.io/docs/user-guide/deployments/). A
430 `luci_deploy`-managed Deployment will have the following metadata annotations:
431
432 * "luci.managedBy", set to "luci-deploytool"
433 * "luci.deploytool/version" set to the `deploytool` Deployment's version
434 string.
435 * "luci.deploytool/sourceVersion" set to the revision of the Deployment
436 Component's source.
437
438 The Kubernetes Deployment for a Component will be named
439 "<project>--<component>".
440
441 `luci_deploy`-driven Kubernetes depoyment is fairly straightforward:
442 * Use "kubectl get deployments/<name>" to get the current Deployment state.
443 * If there is a current Deployment,
444 * If its "luci.managedBy" annotation doesn't equal "luci-deploytool",
445 fail. The user must manually correct this situation.
446 * Check if the "luci.deploytool/version" matches the container version.
447 If it does, succeed.
448 * Create/update the Deployment's configuration using "kubectl apply".
449
450 #### Go Container Engine Pod Components
451
452 Go Container Engine Pods use a set of tools for deployment:
453 * `aedeploy`, an AppEngine project tool which copies the various referenced
454 sources across GOPATH entries into a single GOPATH hierarchy for Docker
455 isolation.
456 * `gcloud`, which engages the remote AppEngine service and offers deployment
457 utility.
458 * `docker`, which is used to build and manage the Docker images.
459
460 The Component's Sources which declare GOPATH presence are combined in a
461 virutal GOPATH within the Component's staging area. This GOPATH is then
462 collapsed by `aedeploy` when the Docker image is built.
463
464 The actual Component is built directly from the Source using `aedeploy` and
465 `docker build`. This is acceptable, since this is a read-only operation and
466 will not modify the Source.
467
468 ## To Do
469
470 Following are some ideas of "planned" features that would be useful to add
471 to `luci_deploy`:
472 * Add a "manage" command to manage a specific Deployment and/or Component.
473 Each invocation would load special set of subcommands based on that
474 resource:
475 * If the resource is a Deployment, query status?
476 * Other common automatable management macros.
477 * Offer a `dev_appserver` fallthrough to create a staging area and
478 bootstrap `dev_appserver` for the named staged AppEngine Components.
OLDNEW
« no previous file with comments | « README.md ('k') | deploytool/api/deploy/checkout.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698