...

Text file src/github.com/linkerd/linkerd2/BUILD.md

Documentation: github.com/linkerd/linkerd2

     1<!-- markdownlint-disable-file code-block-style -->
     2# Linkerd2 Development Guide
     3
     4:balloon: Welcome to the Linkerd2 development guide! :wave:
     5
     6This document will help you build and run Linkerd2 from source. More information
     7about testing from source can be found in the [TEST.md](TEST.md) guide.
     8
     9## Table of contents
    10
    11- [Repo Layout](#repo-layout)
    12  - [Control Plane (Go/React)](#control-plane-goreact)
    13  - [Data Plane (Rust)](#data-plane-rust)
    14- [Components](#components)
    15- [Development configurations](#development-configurations)
    16  - [Comprehensive](#comprehensive)
    17    - [Deploying Control Plane components with Tracing](#deploying-control-plane-components-with-tracing)
    18  - [Publishing Images](#publishing-images)
    19  - [Go](#go)
    20    - [A note about Go run](#a-note-about-go-run)
    21    - [Lint](#lint)
    22    - [Formatting](#formatting)
    23    - [Building the CLI for development](#building-the-cli-for-development)
    24    - [Running the control plane for development](#running-the-control-plane-for-development)
    25    - [Running the Tap APIService for development](#debugging-the-tap-apiservice-for-development)
    26    - [Generating CLI docs](#generating-cli-docs)
    27  - [Web](#web)
    28    - [First time setup](#first-time-setup)
    29    - [Run web standalone](#run-web-standalone)
    30    - [Webpack dev server](#webpack-dev-server)
    31    - [JavaScript dependencies](#javascript-dependencies)
    32    - [Translations](#translations)
    33  - [Rust](#rust)
    34    - [Docker](#docker)
    35- [Dependencies](#dependencies)
    36  - [Updating protobuf dependencies](#updating-protobuf-dependencies)
    37  - [Updating ServiceProfile generated
    38    code](#updating-serviceprofile-generated-code)
    39- [Linkerd Helm Chart](#linkerd-helm-chart)
    40  - [Extensions Helm charts](#extensions-helm-charts)
    41  - [Making changes to the chart templates](#making-changes-to-the-chart-templates)
    42  - [Generating Helm charts docs](#generating-helm-charts-docs)
    43  - [Using helm-docs](#using-helm-docs)
    44  - [Annotating values.yaml](#annotating-valuesyaml)
    45  - [Markdown templates](#markdown-templates)
    46
    47## Repo layout
    48
    49Linkerd2 is primarily written in Rust, Go, and React. At its core is a
    50high-performance data plane written in Rust. The control plane components and
    51its extensions are written in Go. The dashboard UI is a React application.
    52
    53### Control Plane (Go/React)
    54
    55- [`cli`](cli): Command-line `linkerd` utility, view and drive the control
    56  plane.
    57- [`controller`](controller)
    58  - [`destination`](controller/api/destination): Accepts requests from `proxy`
    59    instances and serves service discovery information.
    60  - [`proxy-injector`](controller/proxy-injector): Mutating webhook triggered by
    61    pods creation, that injects the proxy container as a sidecar.
    62  - [`identity`](controller/identity): Provides a CA to distribute certificates
    63    to proxies for them to establish mTLS connections between them.
    64- [`viz extension`](viz)
    65  - [`metrics-api`](viz/metrics-api): Accepts requests from API clients such as
    66    cli and web, serving metrics from the proxies in the cluster through
    67    Prometheus queries.
    68  - [`tap`](viz/tap/api): Provides a live pipeline of requests.
    69  - [`tap-injector`](viz/tap/injector): Mutating webhook triggered by pods
    70    creation, that injects metadata into the proxy container in order to enable
    71    tap.
    72  - [`web`](web): Provides a UI dashboard to view and drive the control plane.
    73- [`multicluster extension`](multicluster)
    74  - [`linkerd-gateway`]: Accepts requests from other clusters and forwards them
    75    to the appropriate destination in the local cluster.
    76  - [`linkerd-service-mirror-xxx`](multicluster/service-mirror): Controller
    77    observing the labeling of exported services in the target cluster, each one
    78    for which it will create a mirrored service in the local cluster.
    79- [`jaeger extension`](jaeger)
    80  - [`jaeger-injector`](jaeger/injector): Mutating webhook triggered by pods
    81    creation, that expands the proxy container for it to produce tracing spans.
    82
    83### Data Plane (Rust)
    84
    85- [`linkerd2-proxy`](https://github.com/linkerd/linkerd2-proxy): Rust source
    86  code for the proxy lives in the linkerd2-proxy repo.
    87- [`linkerd2-proxy-api`](https://github.com/linkerd/linkerd2-proxy-api):
    88  Protobuf definitions for the data plane APIs live in the linkerd2-proxy-api
    89  repo.
    90
    91## Components
    92
    93![Linkerd2 Components](https://g.gravizo.com/source/svg/linkerd2_components?https%3A%2F%2Fraw.githubusercontent.com%2Flinkerd%2Flinkerd2%2Fmain%2FBUILD.md)
    94
    95<!-- markdownlint-disable no-inline-html -->
    96<details>
    97<summary></summary>
    98linkerd2_components
    99  digraph G {
   100    rankdir=LR;
   101
   102    node [style=filled, shape=rect];
   103
   104    "cli" [color=lightblue];
   105    "destination" [color=lightblue];
   106    "identity" [color=lightblue];
   107    "metrics-api" [color=lightblue];
   108    "tap" [color=lightblue];
   109    "web" [color=lightblue];
   110
   111    "proxy" [color=orange];
   112
   113    "cli" -> "metrics-api";
   114    "cli" -> "tap";
   115
   116    "web" -> "metrics-api";
   117    "web" -> "tap";
   118    "web" -> "grafana";
   119
   120    "metrics-api" -> "prometheus";
   121
   122    "tap" -> "proxy";
   123
   124    "proxy" -> "destination";
   125    "proxy" -> "identity";
   126
   127    "identity" -> "kubernetes api"
   128
   129    "destination" -> "kubernetes api";
   130
   131    "grafana" -> "prometheus";
   132    "prometheus" -> "proxy";
   133  }
   134linkerd2_components
   135</details>
   136<!-- markdownlint-enable no-inline-html -->
   137
   138## Development configurations
   139
   140Depending on use case, there are several configurations with which to develop
   141and run Linkerd2:
   142
   143- [Comprehensive](#comprehensive): Integrated configuration using k3d, most
   144  closely matches release.
   145- [Web](#web): Development of the Linkerd2 Dashboard.
   146
   147### Comprehensive
   148
   149This configuration builds all Linkerd2 components in Docker images, and deploys
   150them onto a k3d cluster. This setup most closely parallels our recommended
   151production installation, documented in [Getting
   152Started](https://linkerd.io/2/getting-started/).
   153
   154Note that you need to have first installed docker buildx, as explained
   155[here](https://github.com/docker/buildx).
   156
   157```bash
   158# create the k3d cluster
   159bin/k3d cluster create
   160
   161# build all docker images
   162bin/docker-build
   163
   164# load all the images into k3d
   165bin/image-load --k3d
   166
   167# install linkerd
   168bin/linkerd install --crds | kubectl apply -f -
   169bin/linkerd install | kubectl apply -f -
   170
   171# wait for the core components to be ready, then install linkerd-viz
   172bin/linkerd viz install | kubectl apply -f -
   173
   174# in order to use `linkerd viz tap` against control plane components, you need
   175# to restart them (so that the tap-injector enables tap on their proxies)
   176kubectl -n linkerd rollout restart deploy
   177
   178# verify cli and server versions
   179bin/linkerd version
   180
   181# validate installation
   182bin/linkerd check --expected-version $(bin/root-tag)
   183
   184# view linkerd dashboard
   185bin/linkerd viz dashboard
   186
   187# install the demo app
   188curl https://run.linkerd.io/emojivoto.yml | bin/linkerd inject - | kubectl apply -f -
   189
   190# port-forward the demo app's frontend to see it at http://localhost:8080
   191kubectl -n emojivoto port-forward svc/web-svc 8080:80
   192
   193# view details per deployment
   194bin/linkerd viz -n emojivoto stat deployments
   195
   196# view a live pipeline of requests
   197bin/linkerd viz -n emojivoto tap deploy voting
   198```
   199
   200#### Deploying Control Plane components with Tracing
   201
   202Control Plane components have the `trace-collector` flag used to enable
   203[Distributed Tracing](https://opentracing.io/docs/overview/what-is-tracing/) for
   204development purposes. It can be enabled globally i.e Control plane components
   205and their proxies by using the `--set controlPlaneTracing=true` installation
   206flag.
   207
   208This will configure all the components to send the traces at
   209`collector.{{.Values.controlPlaneTracingNamespace}}.svc.{{.Values.ClusterDomain}}:55678`
   210
   211```bash
   212
   213# install Linkerd with tracing
   214linkerd install --set controlPlaneTracing=true | kubectl apply -f -
   215
   216# install the Jaeger extension
   217linkerd jaeger install | kubectl apply -f -
   218
   219# restart the control plane components so that the jaeger-injector enables
   220# tracing in their proxies
   221kubectl -n linkerd rollout restart deploy
   222```
   223
   224### Publishing images
   225
   226The example above builds and loads the docker images into k3d. For testing your
   227built images outside your local environment, you need to publish your images so
   228they become accessible in those external environments.
   229
   230To signal `bin/docker-build` or any of the more specific scripts
   231`bin/docker-build-*` what registry to use, just set the environment variable
   232`DOCKER_REGISTRY` (which defaults to the official registry `cr.l5d.io/linkerd`).
   233After having pushed those images through the usual means (`docker push`) you'll
   234have to pass the `--registry` flag to `linkerd install` with a value  matching
   235your registry. Extensions don't have that flag and instead you need to use the
   236equivalent Helm value; e.g. for Viz `linkerd viz install --set
   237defaultRegistry=...`.
   238
   239### Go
   240
   241#### A note about Go run
   242
   243Our instructions use a [`bin/go-run`](bin/go-run) script in lieu `go run`. This
   244is a convenience script that leverages caching via `go build` to make your
   245build/run/debug loop faster.
   246
   247In general, replace commands like this:
   248
   249```bash
   250go run cli/main.go check
   251```
   252
   253with this:
   254
   255```bash
   256bin/go-run cli check
   257```
   258
   259That is equivalent to running `linkerd check` using the code on your branch.
   260
   261#### Lint
   262
   263To analyze and lint the Go code using golangci-lint, run:
   264
   265```bash
   266golangci-lint run
   267```
   268
   269#### Formatting
   270
   271All Go source code is formatted with `goimports`. The version of `goimports`
   272used by this project is specified in `go.mod`. To ensure you have the same
   273version installed, run `go install -mod=readonly
   274golang.org/x/tools/cmd/goimports`. It's recommended that you set your IDE or
   275other development tools to use `goimports`. Formatting is checked during CI by
   276the `bin/fmt` script.
   277
   278#### Building the CLI for development
   279
   280The script for building the CLI binaries using docker is
   281`bin/docker-build-cli-bin`. This will also be called indirectly when calling
   282`bin/docker-build`. By default it creates binaries for your current host's
   283OS/arch.
   284
   285To cross-build targeting a different OS or architecture, set the environment
   286variable `DOCKER_TARGET` according to any of the final stages available in
   287[cli/Dockerfile](cli/Dockerfile).
   288
   289For local development and a faster edit-build-test cycle you can build directly
   290without going through a docker container by calling `bin/build-cli-bin`.
   291
   292If you set the environment variable `LINKERD_LOCAL_BUILD_CLI=1` then
   293`bin/docker-build` will use this last method for the step that builds the CLI.
   294
   295#### Running the control plane for development
   296
   297Linkerd2's control plane is composed of several Go microservices. You can run
   298these components in a Kubernetes cluster, or even locally.
   299
   300To run an individual component locally, you can use the `go-run` command, and
   301pass in valid Kubernetes credentials via the `-kubeconfig` flag. For instance,
   302to run the destination service locally, run:
   303
   304```bash
   305bin/go-run controller/cmd destination -kubeconfig ~/.kube/config -log-level debug
   306```
   307
   308You can send test requests to the destination service using the
   309`destination-client` in the `controller/script` directory. For instance:
   310
   311```bash
   312bin/go-run controller/script/destination-client -path hello.default.svc.cluster.local:80
   313```
   314
   315##### Debugging the Tap APIService for development
   316
   317The Tap APIService is a Kubernetes extension API server, so it can be
   318challenging to run outside the cluster. The most straightforward workflow is to
   319simply test changes by building and loading the container image as explained in
   320the [comprehensive configuration](#comprehensive) section above (in order to
   321just build this component use `bin/docker-build-tap`).
   322
   323#### Generating CLI docs
   324
   325The [documentation](https://linkerd.io/2/cli/) for the CLI tool is partially
   326generated from YAML. This can be generated by running the `linkerd doc` command.
   327
   328### Web
   329
   330This is a React app fronting a Go process. It uses webpack to bundle assets, and
   331postcss to transform css.
   332
   333These commands assume working [Go](https://golang.org) and
   334[Yarn](https://yarnpkg.com) environments.
   335
   336#### First time setup
   337
   3381. Install [Yarn](https://yarnpkg.com) and use it to install JS dependencies:
   339
   340    ```bash
   341    brew install yarn
   342    bin/web setup
   343    ```
   344
   3452. Install Linkerd on a Kubernetes cluster.
   346
   347#### Run web standalone
   348
   349```bash
   350bin/web run
   351```
   352
   353The web server will be running on `localhost:7777`.
   354
   355#### Webpack dev server
   356
   357To develop with a webpack dev server:
   358
   3591. Start the development server.
   360
   361    ```bash
   362    bin/web dev
   363    ```
   364
   365    Note: this will start up:
   366
   367    - `web` on :7777. This is the golang process that serves the dashboard.
   368    - `webpack-dev-server` on :8080 to manage rebuilding/reloading of the
   369      javascript.
   370    - `metrics-api` is port-forwarded from the Kubernetes cluster via `kubectl`
   371      on :8085
   372
   3732. Go to [http://localhost:7777](http://localhost:7777) to see everything
   374   running.
   375
   376#### JavaScript dependencies
   377
   378To add a JS dependency:
   379
   380```bash
   381cd web/app
   382yarn add [dep]
   383```
   384
   385#### Translations
   386
   387To add a locale:
   388
   389```bash
   390cd web/app
   391yarn lingui add-locale [locales...] # will create a messages.json file for new locale(s)
   392```
   393
   394To extract message keys from existing components:
   395
   396```bash
   397cd web/app
   398yarn lingui extract
   399...
   400yarn lingui compile # done automatically in bin/web run
   401```
   402
   403Finally, make sure the new locale is also referred in the following places:
   404
   405- Under the `lingui` section in `package.json`
   406- In the `make-plural/plurals` import in `index.js`
   407- In the `langOptions` object in `index.js`
   408
   409### Rust
   410
   411All Rust development happens in the
   412[`linkerd2-proxy`](https://github.com/linkerd/linkerd2-proxy) repo.
   413
   414#### Docker
   415
   416The `bin/docker-build-proxy` script builds the proxy by pulling a pre-published
   417proxy binary:
   418
   419```bash
   420bin/docker-build-proxy
   421```
   422
   423#### Locally built proxy
   424
   425If you want to deploy a locally built proxy, you can build it in the
   426[`linkerd2-proxy`](https://github.com/linkerd/linkerd2-proxy) repo by running:
   427
   428```bash
   429DOCKER_TAG=cr.l5d.io/linkerd/proxy:dev make docker
   430```
   431
   432Then, in this repo, run:
   433
   434```bash
   435./bin/k3d image import cr.l5d.io/linkerd/proxy:dev
   436```
   437
   438Now, to make a pod use your image, add the following annotations to it:
   439
   440```yaml
   441config.linkerd.io/proxy-version: dev
   442```
   443
   444## Dependencies
   445
   446### Updating protobuf dependencies
   447
   448 If you make Protobuf changes, run:
   449
   450 ```bash
   451bin/protoc-go.sh
   452```
   453
   454### Updating ServiceProfile generated code
   455
   456The [ServiceProfile client code](./controller/gen/client) is generated by
   457[`bin/update-codegen.sh`](bin/update-codegen.sh), which depends on [K8s
   458code-generator](https://github.com/kubernetes/code-generator), which does not
   459yet support Go Modules. To re-generate this code, check out this repo into your
   460`GOPATH`:
   461
   462```bash
   463go get -u github.com/linkerd/linkerd2
   464cd $GOPATH/src/github.com/linkerd/linkerd2
   465bin/update-codegen.sh
   466```
   467
   468## Linkerd Helm chart
   469
   470The Linkerd control plane chart is located in the
   471[`charts/linkerd2`](charts/linkerd2) folder. The [`charts/patch`](charts/patch)
   472chart consists of the Linkerd proxy specification, which is used by the proxy
   473injector to inject the proxy container. Both charts depend on the partials
   474subchart which can be found in the [`charts/partials`](charts/partials) folder.
   475
   476Note that the `charts/linkerd2/values.yaml` file contains a placeholder
   477`linkerdVersionValue` that you need to replace with an appropriate string (like
   478`edge-20.2.2`) before proceeding.
   479
   480During development, please use the [`bin/helm`](bin/helm) wrapper script to
   481invoke the Helm commands. For example,
   482
   483```bash
   484bin/helm install linkerd2 charts/linkerd2
   485```
   486
   487This ensures that you use the same Helm version as that of the Linkerd CI
   488system.
   489
   490For general instructions on how to install the charts check out the
   491[docs](https://linkerd.io/2/tasks/install-helm/). You also need to supply or
   492generate your own certificates to use the chart, as explained
   493[here](https://linkerd.io/2/tasks/generate-certificates/).
   494
   495### Extensions Helm charts
   496
   497Extensions provide each their own chart:
   498
   499- Viz: [`viz/charts/linkerd-viz`](viz/charts/linkerd-viz)
   500- Multicluster:
   501  [`multicluster/charts/linkerd-multicluster`](multicluster/charts/linkerd-multicluster)
   502- Jaeger: [`jaeger/charts/linkerd-jaeger`](jaeger/charts/linkerd-jaeger)
   503
   504### Making changes to the chart templates
   505
   506Whenever you make changes to the files under
   507[`charts/linkerd2/templates`](charts/linkerd2/templates) or its dependency
   508[`charts/partials`](charts/partials), make sure to run
   509[`bin/helm-build`](bin/helm-build) which will refresh the dependencies and lint
   510the templates.
   511
   512### Generating Helm charts docs
   513
   514Whenever a new chart is created or updated a README should be generated from
   515the chart's `values.yaml`. This can be done by utilizing the bundled
   516[helm-docs](https://github.com/norwoodj/helm-docs) binary. For adding additional
   517information, such as specific installation instructions a README template is
   518required to be created. Check existing charts for examples.
   519
   520#### Using helm-docs
   521
   522Example usage:
   523
   524```sh
   525bin/helm-docs
   526bin/helm-docs --dry-run #Prints to cli instead
   527bin/helm-docs --chart-search-root=./charts #Sets search root for charts
   528bin/helm-docs --template-files=README.md.gotmpl #Sets the template file used
   529```
   530
   531Note:
   532The tool searches through the current directory and sub-directories by default.
   533For additional information checkout their repo above.
   534
   535#### Annotating values.yaml
   536
   537To allow helm-docs to properly document the values in `values.yaml` a descriptive
   538comment is required. This can be done in two ways.
   539Either comment the value directly above with
   540`# -- This is a really nice value` where the double dashes automatically
   541annotates the value. Another explicit usage is to type out the value name.
   542`# global.MyNiceValue -- I really like this value`
   543
   544#### Markdown templates
   545
   546In order to accommodate for extra data that might not have a proper place in the
   547´values.yaml´ file the corresponding ´README.md.gotmpl´ can be modified for each
   548chart. This template allows the standard markdown syntax as well as the go
   549templating functions. Checkout
   550[helm-docs](https://github.com/norwoodj/helm-docs) for more info.

View as plain text