github.com/uber/kraken@v0.1.4/proxy/cmd/cmd.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package cmd 15 16 import ( 17 "flag" 18 19 "fmt" 20 "net/http" 21 22 "github.com/uber/kraken/build-index/tagclient" 23 "github.com/uber/kraken/lib/dockerregistry/transfer" 24 "github.com/uber/kraken/lib/healthcheck" 25 "github.com/uber/kraken/lib/store" 26 "github.com/uber/kraken/lib/upstream" 27 "github.com/uber/kraken/metrics" 28 "github.com/uber/kraken/nginx" 29 "github.com/uber/kraken/origin/blobclient" 30 "github.com/uber/kraken/proxy/proxyserver" 31 "github.com/uber/kraken/proxy/registryoverride" 32 "github.com/uber/kraken/utils/configutil" 33 "github.com/uber/kraken/utils/flagutil" 34 "github.com/uber/kraken/utils/log" 35 36 "github.com/uber-go/tally" 37 "go.uber.org/zap" 38 ) 39 40 // Flags defines proxy CLI flags. 41 type Flags struct { 42 Ports flagutil.Ints 43 ServerPort int 44 ConfigFile string 45 KrakenCluster string 46 SecretsFile string 47 } 48 49 // ParseFlags parses proxy CLI flags. 50 func ParseFlags() *Flags { 51 var flags Flags 52 flag.Var( 53 &flags.Ports, "port", "port to listen on (may specify multiple)") 54 flag.IntVar( 55 &flags.ServerPort, "server-port", 0, "http server port to listen on") 56 flag.StringVar( 57 &flags.ConfigFile, "config", "", "configuration file path") 58 flag.StringVar( 59 &flags.KrakenCluster, "cluster", "", "cluster name (e.g. prod01-zone1)") 60 flag.StringVar( 61 &flags.SecretsFile, "secrets", "", "path to a secrets YAML file to load into configuration") 62 flag.Parse() 63 return &flags 64 } 65 66 type options struct { 67 config *Config 68 metrics tally.Scope 69 logger *zap.Logger 70 } 71 72 // Option defines an optional Run parameter. 73 type Option func(*options) 74 75 // WithConfig ignores config/secrets flags and directly uses the provided config 76 // struct. 77 func WithConfig(c Config) Option { 78 return func(o *options) { o.config = &c } 79 } 80 81 // WithMetrics ignores metrics config and directly uses the provided tally scope. 82 func WithMetrics(s tally.Scope) Option { 83 return func(o *options) { o.metrics = s } 84 } 85 86 // WithLogger ignores logging config and directly uses the provided logger. 87 func WithLogger(l *zap.Logger) Option { 88 return func(o *options) { o.logger = l } 89 } 90 91 // Run runs the proxy. 92 func Run(flags *Flags, opts ...Option) { 93 if len(flags.Ports) == 0 { 94 panic("must specify a port") 95 } 96 97 var overrides options 98 for _, o := range opts { 99 o(&overrides) 100 } 101 102 var config Config 103 if overrides.config != nil { 104 config = *overrides.config 105 } else { 106 if err := configutil.Load(flags.ConfigFile, &config); err != nil { 107 panic(err) 108 } 109 if flags.SecretsFile != "" { 110 if err := configutil.Load(flags.SecretsFile, &config); err != nil { 111 panic(err) 112 } 113 } 114 } 115 116 if overrides.logger != nil { 117 log.SetGlobalLogger(overrides.logger.Sugar()) 118 } else { 119 zlog := log.ConfigureLogger(config.ZapLogging) 120 defer zlog.Sync() 121 } 122 123 stats := overrides.metrics 124 if stats == nil { 125 s, closer, err := metrics.New(config.Metrics, flags.KrakenCluster) 126 if err != nil { 127 log.Fatalf("Failed to init metrics: %s", err) 128 } 129 stats = s 130 defer closer.Close() 131 } 132 133 go metrics.EmitVersion(stats) 134 135 cas, err := store.NewCAStore(config.CAStore, stats) 136 if err != nil { 137 log.Fatalf("Failed to create store: %s", err) 138 } 139 140 tls, err := config.TLS.BuildClient() 141 if err != nil { 142 log.Fatalf("Error building client tls config: %s", err) 143 } 144 145 origins, err := config.Origin.Build(upstream.WithHealthCheck(healthcheck.Default(tls))) 146 if err != nil { 147 log.Fatalf("Error building origin host list: %s", err) 148 } 149 150 r := blobclient.NewClientResolver(blobclient.NewProvider(blobclient.WithTLS(tls)), origins) 151 originCluster := blobclient.NewClusterClient(r) 152 153 buildIndexes, err := config.BuildIndex.Build(upstream.WithHealthCheck(healthcheck.Default(tls))) 154 if err != nil { 155 log.Fatalf("Error building build-index host list: %s", err) 156 } 157 158 tagClient := tagclient.NewClusterClient(buildIndexes, tls) 159 160 transferer := transfer.NewReadWriteTransferer(stats, tagClient, originCluster, cas) 161 162 // Open preheat function only if server-port was defined. 163 if flags.ServerPort != 0 { 164 server := proxyserver.New(stats, originCluster) 165 addr := fmt.Sprintf(":%d", flags.ServerPort) 166 log.Infof("Starting http server on %s", addr) 167 go func() { 168 log.Fatal(http.ListenAndServe(addr, server.Handler())) 169 }() 170 } 171 172 registry, err := config.Registry.Build(config.Registry.ReadWriteParameters(transferer, cas, stats)) 173 if err != nil { 174 log.Fatalf("Error creating registry: %s", err) 175 } 176 go func() { 177 log.Info("Starting registry...") 178 log.Fatal(registry.ListenAndServe()) 179 }() 180 181 ros := registryoverride.NewServer(config.RegistryOverride, tagClient) 182 go func() { 183 log.Fatal(ros.ListenAndServe()) 184 }() 185 186 log.Info("Starting nginx...") 187 log.Fatal(nginx.Run(config.Nginx, map[string]interface{}{ 188 "ports": flags.Ports, 189 "registry_server": nginx.GetServer( 190 config.Registry.Docker.HTTP.Net, config.Registry.Docker.HTTP.Addr), 191 "registry_override_server": nginx.GetServer( 192 config.RegistryOverride.Listener.Net, config.RegistryOverride.Listener.Addr)}, 193 nginx.WithTLS(config.TLS))) 194 }