Shrink controller Docker image from 315MB to 38MB (#3378)

The controller Docker image included 7 Go binaries (destination,
heartbeat, identity, proxy-injector, public-api, sp-validator, tap),
each roughly 35MB, with similar dependencies.

Change each controller binary into subcommands of a single `controller`
binary, decreasing the controller Docker image size from 315MB to 38MB.

Signed-off-by: Andrew Seigner <siggy@buoyant.io>
This commit is contained in:
Andrew Seigner 2019-09-05 11:44:03 -07:00 committed by GitHub
parent 89deacd8d6
commit d773a47dd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 150 additions and 74 deletions

View File

@ -1,4 +1,4 @@
## compile controller services
## compile controller service
FROM gcr.io/linkerd-io/go-deps:c921a98b as golang
WORKDIR /linkerd-build
COPY controller/gen controller/gen
@ -11,17 +11,17 @@ COPY charts/partials charts/partials
# TODO: `go generate` does not honor -mod=readonly
RUN go generate -mod=readonly ./pkg/charts/static
# use `install` so that we produce multiple binaries
RUN CGO_ENABLED=0 GOOS=linux go install -tags prod -mod=readonly ./pkg/...
RUN CGO_ENABLED=0 GOOS=linux go install -tags prod -mod=readonly ./controller/cmd/...
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/controller -tags prod -mod=readonly -ldflags "-s -w" ./controller/cmd
## package runtime
FROM scratch
ENV PATH=$PATH:/go/bin
COPY LICENSE /linkerd/LICENSE
COPY --from=golang /go/bin /go/bin
COPY --from=golang /out/controller /go/bin/controller
# for heartbeat (https://versioncheck.linkerd.io/version.json)
COPY --from=golang /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ARG LINKERD_VERSION
ENV LINKERD_CONTAINER_VERSION_OVERRIDE=${LINKERD_VERSION}
ENTRYPOINT ["/go/bin/controller"]

View File

@ -1,4 +1,4 @@
package main
package destination
import (
"flag"
@ -16,14 +16,18 @@ import (
log "github.com/sirupsen/logrus"
)
func main() {
addr := flag.String("addr", ":8086", "address to serve on")
metricsAddr := flag.String("metrics-addr", ":9996", "address to serve scrapable metrics on")
kubeConfigPath := flag.String("kubeconfig", "", "path to kube config")
enableH2Upgrade := flag.Bool("enable-h2-upgrade", true, "Enable transparently upgraded HTTP2 connections among pods in the service mesh")
disableIdentity := flag.Bool("disable-identity", false, "Disable identity configuration")
controllerNamespace := flag.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
flags.ConfigureAndParse()
// Main executes the destination subcommand
func Main(args []string) {
cmd := flag.NewFlagSet("destination", flag.ExitOnError)
addr := cmd.String("addr", ":8086", "address to serve on")
metricsAddr := cmd.String("metrics-addr", ":9996", "address to serve scrapable metrics on")
kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
enableH2Upgrade := cmd.Bool("enable-h2-upgrade", true, "Enable transparently upgraded HTTP2 connections among pods in the service mesh")
disableIdentity := cmd.Bool("disable-identity", false, "Disable identity configuration")
controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
flags.ConfigureAndParse(cmd, args)
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)

View File

@ -1,4 +1,4 @@
package main
package heartbeat
import (
"flag"
@ -13,11 +13,15 @@ import (
log "github.com/sirupsen/logrus"
)
func main() {
kubeConfigPath := flag.String("kubeconfig", "", "path to kube config")
prometheusURL := flag.String("prometheus-url", "http://127.0.0.1:9090", "prometheus url")
controllerNamespace := flag.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
flags.ConfigureAndParse()
// Main executes the heartbeat subcommand
func Main(args []string) {
cmd := flag.NewFlagSet("heartbeat", flag.ExitOnError)
kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
prometheusURL := cmd.String("prometheus-url", "http://127.0.0.1:9090", "prometheus url")
controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
flags.ConfigureAndParse(cmd, args)
// Gather the following fields:
// - version

View File

@ -1,4 +1,4 @@
package main
package identity
import (
"flag"
@ -25,14 +25,19 @@ import (
// TODO watch trustAnchorsPath for changes
// TODO watch issuerPath for changes
// TODO restrict servicetoken audiences (and lifetimes)
func main() {
addr := flag.String("addr", ":8080", "address to serve on")
adminAddr := flag.String("admin-addr", ":9990", "address of HTTP admin server")
kubeConfigPath := flag.String("kubeconfig", "", "path to kube config")
issuerPath := flag.String("issuer",
// Main executes the identity subcommand
func Main(args []string) {
cmd := flag.NewFlagSet("identity", flag.ExitOnError)
addr := cmd.String("addr", ":8080", "address to serve on")
adminAddr := cmd.String("admin-addr", ":9990", "address of HTTP admin server")
kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
issuerPath := cmd.String("issuer",
"/var/run/linkerd/identity/issuer",
"path to directory containing issuer credentials")
flags.ConfigureAndParse()
flags.ConfigureAndParse(cmd, args)
cfg, err := config.Global(consts.MountPathGlobalConfig)
if err != nil {

41
controller/cmd/main.go Normal file
View File

@ -0,0 +1,41 @@
package main
import (
"fmt"
"os"
"github.com/linkerd/linkerd2/controller/cmd/destination"
"github.com/linkerd/linkerd2/controller/cmd/heartbeat"
"github.com/linkerd/linkerd2/controller/cmd/identity"
proxyinjector "github.com/linkerd/linkerd2/controller/cmd/proxy-injector"
publicapi "github.com/linkerd/linkerd2/controller/cmd/public-api"
spvalidator "github.com/linkerd/linkerd2/controller/cmd/sp-validator"
"github.com/linkerd/linkerd2/controller/cmd/tap"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("expected a subcommand")
os.Exit(1)
}
switch os.Args[1] {
case "destination":
destination.Main(os.Args[2:])
case "heartbeat":
heartbeat.Main(os.Args[2:])
case "identity":
identity.Main(os.Args[2:])
case "proxy-injector":
proxyinjector.Main(os.Args[2:])
case "public-api":
publicapi.Main(os.Args[2:])
case "sp-validator":
spvalidator.Main(os.Args[2:])
case "tap":
tap.Main(os.Args[2:])
default:
fmt.Printf("unknown subcommand: %s", os.Args[1])
os.Exit(1)
}
}

View File

@ -1,4 +1,4 @@
package main
package proxyinjector
import (
"github.com/linkerd/linkerd2/controller/k8s"
@ -6,11 +6,14 @@ import (
"github.com/linkerd/linkerd2/controller/webhook"
)
func main() {
// Main executes the proxy-injector subcommand
func Main(args []string) {
webhook.Launch(
[]k8s.APIResource{k8s.NS, k8s.Deploy, k8s.RC, k8s.RS, k8s.Job, k8s.DS, k8s.SS, k8s.Pod},
9995,
injector.Inject,
"linkerd-proxy-injector",
"proxy-injector",
args,
)
}

View File

@ -1,4 +1,4 @@
package main
package publicapi
import (
"context"
@ -20,15 +20,19 @@ import (
log "github.com/sirupsen/logrus"
)
func main() {
addr := flag.String("addr", ":8085", "address to serve on")
kubeConfigPath := flag.String("kubeconfig", "", "path to kube config")
prometheusURL := flag.String("prometheus-url", "http://127.0.0.1:9090", "prometheus url")
metricsAddr := flag.String("metrics-addr", ":9995", "address to serve scrapable metrics on")
destinationAPIAddr := flag.String("destination-addr", "127.0.0.1:8086", "address of destination service")
controllerNamespace := flag.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
ignoredNamespaces := flag.String("ignore-namespaces", "kube-system", "comma separated list of namespaces to not list pods from")
flags.ConfigureAndParse()
// Main executes the public-api subcommand
func Main(args []string) {
cmd := flag.NewFlagSet("public-api", flag.ExitOnError)
addr := cmd.String("addr", ":8085", "address to serve on")
kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
prometheusURL := cmd.String("prometheus-url", "http://127.0.0.1:9090", "prometheus url")
metricsAddr := cmd.String("metrics-addr", ":9995", "address to serve scrapable metrics on")
destinationAPIAddr := cmd.String("destination-addr", "127.0.0.1:8086", "address of destination service")
controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
ignoredNamespaces := cmd.String("ignore-namespaces", "kube-system", "comma separated list of namespaces to not list pods from")
flags.ConfigureAndParse(cmd, args)
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)

View File

@ -1,15 +1,18 @@
package main
package spvalidator
import (
validator "github.com/linkerd/linkerd2/controller/sp-validator"
"github.com/linkerd/linkerd2/controller/webhook"
)
func main() {
// Main executes the sp-validator subcommand
func Main(args []string) {
webhook.Launch(
nil,
9997,
validator.AdmitSP,
"linkerd-sp-validator",
"sp-validator",
args,
)
}

View File

@ -1,4 +1,4 @@
package main
package tap
import (
"context"
@ -17,17 +17,20 @@ import (
log "github.com/sirupsen/logrus"
)
func main() {
apiServerAddr := flag.String("apiserver-addr", ":8089", "address to serve the apiserver on")
metricsAddr := flag.String("metrics-addr", ":9998", "address to serve scrapable metrics on")
kubeConfigPath := flag.String("kubeconfig", "", "path to kube config")
controllerNamespace := flag.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
tapPort := flag.Uint("tap-port", 4190, "proxy tap port to connect to")
tlsCertPath := flag.String("tls-cert", pkgK8s.MountPathTLSCrtPEM, "path to TLS Cert PEM")
tlsKeyPath := flag.String("tls-key", pkgK8s.MountPathTLSKeyPEM, "path to TLS Key PEM")
disableCommonNames := flag.Bool("disable-common-names", false, "disable checks for Common Names (for development)")
// Main executes the tap subcommand
func Main(args []string) {
cmd := flag.NewFlagSet("tap", flag.ExitOnError)
flags.ConfigureAndParse()
apiServerAddr := cmd.String("apiserver-addr", ":8089", "address to serve the apiserver on")
metricsAddr := cmd.String("metrics-addr", ":9998", "address to serve scrapable metrics on")
kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
tapPort := cmd.Uint("tap-port", 4190, "proxy tap port to connect to")
tlsCertPath := cmd.String("tls-cert", pkgK8s.MountPathTLSCrtPEM, "path to TLS Cert PEM")
tlsKeyPath := cmd.String("tls-key", pkgK8s.MountPathTLSKeyPEM, "path to TLS Key PEM")
disableCommonNames := cmd.Bool("disable-common-names", false, "disable checks for Common Names (for development)")
flags.ConfigureAndParse(cmd, args)
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)

View File

@ -18,11 +18,14 @@ import (
)
// Launch sets up and starts the webhook and metrics servers
func Launch(APIResources []k8s.APIResource, metricsPort uint32, handler handlerFunc, component string) {
metricsAddr := flag.String("metrics-addr", fmt.Sprintf(":%d", metricsPort), "address to serve scrapable metrics on")
addr := flag.String("addr", ":8443", "address to serve on")
kubeconfig := flag.String("kubeconfig", "", "path to kubeconfig")
flags.ConfigureAndParse()
func Launch(APIResources []k8s.APIResource, metricsPort uint32, handler handlerFunc, component, subcommand string, args []string) {
cmd := flag.NewFlagSet(subcommand, flag.ExitOnError)
metricsAddr := cmd.String("metrics-addr", fmt.Sprintf(":%d", metricsPort), "address to serve scrapable metrics on")
addr := cmd.String("addr", ":8443", "address to serve on")
kubeconfig := cmd.String("kubeconfig", "", "path to kubeconfig")
flags.ConfigureAndParse(cmd, args)
stop := make(chan os.Signal, 1)
defer close(stop)

View File

@ -13,17 +13,17 @@ import (
// ConfigureAndParse adds flags that are common to all go processes. This
// func calls flag.Parse(), so it should be called after all other flags have
// been configured.
func ConfigureAndParse() {
func ConfigureAndParse(cmd *flag.FlagSet, args []string) {
klog.InitFlags(nil)
flag.Set("stderrthreshold", "FATAL")
flag.Set("logtostderr", "false")
flag.Set("log_file", "/dev/null")
flag.Set("v", "0")
logLevel := flag.String("log-level", log.InfoLevel.String(),
logLevel := cmd.String("log-level", log.InfoLevel.String(),
"log level, must be one of: panic, fatal, error, warn, info, debug")
printVersion := flag.Bool("version", false, "print version and exit")
printVersion := cmd.Bool("version", false, "print version and exit")
flag.Parse()
cmd.Parse(args)
// set log timestamps
formatter := &log.TextFormatter{FullTimestamp: true}

View File

@ -23,9 +23,12 @@ const (
)
func main() {
name := flag.String("name", "", "identity name")
dir := flag.String("dir", "", "directory under which credentials are written")
flags.ConfigureAndParse()
cmd := flag.NewFlagSet("public-api", flag.ExitOnError)
name := cmd.String("name", "", "identity name")
dir := cmd.String("dir", "", "directory under which credentials are written")
flags.ConfigureAndParse(cmd, os.Args[1:])
if os.Getenv(envDisabled) != "" {
log.Debug("Identity disabled.")

View File

@ -20,16 +20,19 @@ import (
)
func main() {
addr := flag.String("addr", ":8084", "address to serve on")
metricsAddr := flag.String("metrics-addr", ":9994", "address to serve scrapable metrics on")
apiAddr := flag.String("api-addr", "127.0.0.1:8085", "address of the linkerd-controller-api service")
grafanaAddr := flag.String("grafana-addr", "127.0.0.1:3000", "address of the linkerd-grafana service")
templateDir := flag.String("template-dir", "templates", "directory to search for template files")
staticDir := flag.String("static-dir", "app/dist", "directory to search for static files")
reload := flag.Bool("reload", true, "reloading set to true or false")
controllerNamespace := flag.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
kubeConfigPath := flag.String("kubeconfig", "", "path to kube config")
flags.ConfigureAndParse()
cmd := flag.NewFlagSet("public-api", flag.ExitOnError)
addr := cmd.String("addr", ":8084", "address to serve on")
metricsAddr := cmd.String("metrics-addr", ":9994", "address to serve scrapable metrics on")
apiAddr := cmd.String("api-addr", "127.0.0.1:8085", "address of the linkerd-controller-api service")
grafanaAddr := cmd.String("grafana-addr", "127.0.0.1:3000", "address of the linkerd-grafana service")
templateDir := cmd.String("template-dir", "templates", "directory to search for template files")
staticDir := cmd.String("static-dir", "app/dist", "directory to search for static files")
reload := cmd.Bool("reload", true, "reloading set to true or false")
controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
flags.ConfigureAndParse(cmd, os.Args[1:])
_, _, err := net.SplitHostPort(*apiAddr) // Verify apiAddr is of the form host:port.
if err != nil {