From ab601665d17cf697ef79b5e00b88d21ca4860b81 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Mon, 24 Sep 2018 09:54:25 -0700 Subject: [PATCH 1/3] Reduced cartservice Docker Image size (#46) Reduces docker image size for cartservice from ~2.36 GB to ~157 MB Fixes Issue #36 ![image-size](https://user-images.githubusercontent.com/7820716/45908973-37a31e00-bdb4-11e8-92d3-d84acfb1c10f.png) --- src/cartservice/Dockerfile | 33 +++++++++++++++++++++--------- src/cartservice/cartservice.csproj | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/cartservice/Dockerfile b/src/cartservice/Dockerfile index 738aaf8..ae28b24 100644 --- a/src/cartservice/Dockerfile +++ b/src/cartservice/Dockerfile @@ -1,7 +1,6 @@ -# cartservice_probe -FROM golang:1.10 as builder +FROM golang:1.10 as probe RUN wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ - chmod +x /go/bin/dep + chmod +x /go/bin/dep ENV PROJECT github.com/GoogleCloudPlatform/microservices-demo/src/cartservice/probe WORKDIR /go/src/$PROJECT COPY probe/Gopkg.* ./ @@ -9,14 +8,28 @@ RUN dep ensure --vendor-only -v COPY ./probe ./ RUN go build -o /cartservice_probe . -# cartservice -FROM gcr.io/google-appengine/aspnetcore:2.1.0 -COPY --from=builder /cartservice_probe /cartservice_probe -RUN apt-get update && apt-get install net-tools telnet +FROM microsoft/dotnet:2.1-sdk-alpine as builder WORKDIR /app COPY . . RUN dotnet restore && \ dotnet build && \ - dotnet publish -WORKDIR /app/bin/Debug/netcoreapp2.0 -ENTRYPOINT ["dotnet", "cartservice.dll", "start"] + dotnet publish -c release -r linux-musl-x64 -o /cartservice + +# cartservice +FROM alpine:3.8 +# Add the probe +COPY --from=probe /cartservice_probe /cartservice_probe +# Dependencies for runtime +# busybox-extras => telnet +RUN apk add --no-cache \ + busybox-extras \ + libc6-compat \ + libunwind \ + libuuid \ + libgcc \ + libstdc++ \ + libintl \ + icu +WORKDIR /app +COPY --from=builder /cartservice . +ENTRYPOINT ["./cartservice", "start"] \ No newline at end of file diff --git a/src/cartservice/cartservice.csproj b/src/cartservice/cartservice.csproj index 2df2e2c..91a1c61 100644 --- a/src/cartservice/cartservice.csproj +++ b/src/cartservice/cartservice.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp2.1 From 6460427bee57cd44b8a7bca10356ec20d940937d Mon Sep 17 00:00:00 2001 From: Yoshi Yamaguchi Date: Wed, 26 Sep 2018 08:43:17 +0900 Subject: [PATCH 2/3] Change log format to JSON and log destination to stdout (#48) * log: change log format to JSON payload for better log in Stackdriver change the log format in Go written service from text payload to JSON payload using 3rd party logging library (logrus). https://cloud.google.com/logging/docs/structured-logging https://github.com/sirupsen/logrus/blob/33a1e118e113c7d1dd24a80f80670864cd598519/json_formatter.go#L40-L49 Effected services are frontend, productcatalogservice, checkoutservice, and shippinservice. Also change target container registry and locust scenario for testing. * revert kubernetes manifests to point to the original container registry URLs * revert skaffold.yaml to point to the original registry * loadgenerator: revert locust settings --- src/checkoutservice/Gopkg.lock | 16 +++++++++ src/checkoutservice/Gopkg.toml | 4 +++ src/checkoutservice/main.go | 53 ++++++++++++++++++---------- src/frontend/main.go | 10 +++++- src/productcatalogservice/Gopkg.lock | 16 +++++++++ src/productcatalogservice/Gopkg.toml | 4 +++ src/productcatalogservice/server.go | 40 +++++++++++++-------- src/shippingservice/Gopkg.lock | 16 +++++++++ src/shippingservice/Gopkg.toml | 4 +++ src/shippingservice/main.go | 48 ++++++++++++++++--------- src/shippingservice/quote.go | 2 +- 11 files changed, 163 insertions(+), 50 deletions(-) diff --git a/src/checkoutservice/Gopkg.lock b/src/checkoutservice/Gopkg.lock index 036480d..364e527 100644 --- a/src/checkoutservice/Gopkg.lock +++ b/src/checkoutservice/Gopkg.lock @@ -56,6 +56,14 @@ revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" +[[projects]] + digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "3e01752db0189b9157070a0e1668a620f9a85da2" + version = "v1.0.6" + [[projects]] name = "go.opencensus.io" packages = [ @@ -77,6 +85,14 @@ revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" +[[projects]] + branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + [[projects]] branch = "master" name = "golang.org/x/net" diff --git a/src/checkoutservice/Gopkg.toml b/src/checkoutservice/Gopkg.toml index 0599867..8566b97 100644 --- a/src/checkoutservice/Gopkg.toml +++ b/src/checkoutservice/Gopkg.toml @@ -41,6 +41,10 @@ name = "github.com/google/uuid" version = "1.0.0" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.6" + [[constraint]] name = "go.opencensus.io" version = "0.16.0" diff --git a/src/checkoutservice/main.go b/src/checkoutservice/main.go index 116e051..cbc408f 100644 --- a/src/checkoutservice/main.go +++ b/src/checkoutservice/main.go @@ -17,7 +17,6 @@ package main import ( "context" "fmt" - "log" "net" "os" "time" @@ -25,6 +24,7 @@ import ( "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" "github.com/google/uuid" + "github.com/sirupsen/logrus" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -42,6 +42,22 @@ const ( usdCurrency = "USD" ) +var log *logrus.Logger + +func init() { + log = logrus.New() + log.Level = logrus.DebugLevel + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout +} + type checkoutService struct { productCatalogSvcAddr string cartSvcAddr string @@ -68,7 +84,7 @@ func main() { mustMapEnv(&svc.emailSvcAddr, "EMAIL_SERVICE_ADDR") mustMapEnv(&svc.paymentSvcAddr, "PAYMENT_SERVICE_ADDR") - log.Printf("service config: %+v", svc) + log.Infof("service config: %+v", svc) lis, err := net.Listen("tcp", fmt.Sprintf(":%s", port)) if err != nil { @@ -77,16 +93,17 @@ func main() { srv := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{})) pb.RegisterCheckoutServiceServer(srv, svc) healthpb.RegisterHealthServer(srv, svc) - log.Printf("starting to listen on tcp: %q", lis.Addr().String()) - log.Fatal(srv.Serve(lis)) + log.Infof("starting to listen on tcp: %q", lis.Addr().String()) + err = srv.Serve(lis) + log.Fatal(err) } func initStats(exporter *stackdriver.Exporter) { view.RegisterExporter(exporter) if err := view.Register(ocgrpc.DefaultServerViews...); err != nil { - log.Printf("Error registering default server views") + log.Warn("Error registering default server views") } else { - log.Printf("Registered default server views") + log.Info("Registered default server views") } } @@ -96,21 +113,21 @@ func initTracing() { for i := 1; i <= 3; i++ { exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { - log.Printf("info: failed to initialize stackdriver exporter: %+v", err) + log.Infof("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - log.Print("registered stackdriver tracing") + log.Info("registered stackdriver tracing") // Register the views to collect server stats. initStats(exporter) return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver exporter", d) + log.Infof("sleeping %v to retry initializing stackdriver exporter", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up") + log.Warn("could not initialize stackdriver exporter after retrying, giving up") } func initProfiling(service, version string) { @@ -123,16 +140,16 @@ func initProfiling(service, version string) { // ProjectID must be set if not running on GCP. // ProjectID: "my-project", }); err != nil { - log.Printf("warn: failed to start profiler: %+v", err) + log.Warnf("failed to start profiler: %+v", err) } else { - log.Print("started stackdriver profiler") + log.Info("started stackdriver profiler") return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver profiler", d) + log.Infof("sleeping %v to retry initializing stackdriver profiler", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up") + log.Warn("could not initialize stackdriver profiler after retrying, giving up") } func mustMapEnv(target *string, envKey string) { @@ -148,7 +165,7 @@ func (cs *checkoutService) Check(ctx context.Context, req *healthpb.HealthCheckR } func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderRequest) (*pb.PlaceOrderResponse, error) { - log.Printf("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency) + log.Infof("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency) orderID, err := uuid.NewUUID() if err != nil { @@ -172,7 +189,7 @@ func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderReq if err != nil { return nil, status.Errorf(codes.Internal, "failed to charge card: %+v", err) } - log.Printf("payment went through (transaction_id: %s)", txID) + log.Infof("payment went through (transaction_id: %s)", txID) shippingTrackingID, err := cs.shipOrder(ctx, req.Address, prep.cartItems) if err != nil { @@ -190,9 +207,9 @@ func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderReq } if err := cs.sendOrderConfirmation(ctx, req.Email, orderResult); err != nil { - log.Printf("failed to send order confirmation to %q: %+v", req.Email, err) + log.Warnf("failed to send order confirmation to %q: %+v", req.Email, err) } else { - log.Printf("order confirmation email sent to %q", req.Email) + log.Infof("order confirmation email sent to %q", req.Email) } resp := &pb.PlaceOrderResponse{Order: orderResult} return resp, nil diff --git a/src/frontend/main.go b/src/frontend/main.go index e70dac3..8939def 100644 --- a/src/frontend/main.go +++ b/src/frontend/main.go @@ -83,7 +83,15 @@ func main() { ctx := context.Background() log := logrus.New() log.Level = logrus.DebugLevel - log.Formatter = &logrus.TextFormatter{} + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout go initProfiling(log, "frontend", "1.0.0") go initTracing(log) diff --git a/src/productcatalogservice/Gopkg.lock b/src/productcatalogservice/Gopkg.lock index b9a3bbd..e1c01e0 100644 --- a/src/productcatalogservice/Gopkg.lock +++ b/src/productcatalogservice/Gopkg.lock @@ -62,6 +62,14 @@ revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" +[[projects]] + digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "3e01752db0189b9157070a0e1668a620f9a85da2" + version = "v1.0.6" + [[projects]] name = "go.opencensus.io" packages = [ @@ -83,6 +91,14 @@ revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" +[[projects]] + branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + [[projects]] branch = "master" name = "golang.org/x/net" diff --git a/src/productcatalogservice/Gopkg.toml b/src/productcatalogservice/Gopkg.toml index a9b34ec..473b4b8 100644 --- a/src/productcatalogservice/Gopkg.toml +++ b/src/productcatalogservice/Gopkg.toml @@ -41,6 +41,10 @@ name = "github.com/google/go-cmp" version = "0.2.0" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.6" + [[constraint]] name = "go.opencensus.io" version = "0.16.0" diff --git a/src/productcatalogservice/server.go b/src/productcatalogservice/server.go index 6599877..0b8efef 100644 --- a/src/productcatalogservice/server.go +++ b/src/productcatalogservice/server.go @@ -20,8 +20,8 @@ import ( "flag" "fmt" "io/ioutil" - "log" "net" + "os" "strings" "time" @@ -31,6 +31,7 @@ import ( "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" "github.com/golang/protobuf/jsonpb" + "github.com/sirupsen/logrus" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -41,6 +42,7 @@ import ( var ( catalogJSON []byte + log *logrus.Logger port = flag.Int("port", 3550, "port to listen at") ) @@ -51,7 +53,17 @@ func init() { log.Fatalf("failed to open product catalog json file: %v", err) } catalogJSON = c - log.Printf("successfully parsed product catalog json") + log = logrus.New() + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout + log.Info("successfully parsed product catalog json") } func main() { @@ -59,7 +71,7 @@ func main() { go initProfiling("productcatalogservice", "1.0.0") flag.Parse() - log.Printf("starting grpc server at :%d", *port) + log.Infof("starting grpc server at :%d", *port) run(*port) select {} } @@ -80,9 +92,9 @@ func run(port int) string { func initStats(exporter *stackdriver.Exporter) { view.RegisterExporter(exporter) if err := view.Register(ocgrpc.DefaultServerViews...); err != nil { - log.Printf("Error registering default server views") + log.Info("Error registering default server views") } else { - log.Printf("Registered default server views") + log.Info("Registered default server views") } } @@ -92,21 +104,21 @@ func initTracing() { for i := 1; i <= 3; i++ { exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { - log.Printf("info: failed to initialize stackdriver exporter: %+v", err) + log.Warnf("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - log.Print("registered stackdriver tracing") + log.Info("registered stackdriver tracing") // Register the views to collect server stats. initStats(exporter) return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver exporter", d) + log.Infof("sleeping %v to retry initializing stackdriver exporter", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up") + log.Warn("could not initialize stackdriver exporter after retrying, giving up") } func initProfiling(service, version string) { @@ -119,16 +131,16 @@ func initProfiling(service, version string) { // ProjectID must be set if not running on GCP. // ProjectID: "my-project", }); err != nil { - log.Printf("warn: failed to start profiler: %+v", err) + log.Warnf("failed to start profiler: %+v", err) } else { - log.Print("started stackdriver profiler") + log.Info("started stackdriver profiler") return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver profiler", d) + log.Infof("sleeping %v to retry initializing stackdriver profiler", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up") + log.Warn("could not initialize stackdriver profiler after retrying, giving up") } type productCatalog struct{} @@ -137,7 +149,7 @@ func parseCatalog() []*pb.Product { var cat pb.ListProductsResponse if err := jsonpb.Unmarshal(bytes.NewReader(catalogJSON), &cat); err != nil { - log.Printf("warning: failed to parse the catalog JSON: %v", err) + log.Warnf("failed to parse the catalog JSON: %v", err) return nil } return cat.Products diff --git a/src/shippingservice/Gopkg.lock b/src/shippingservice/Gopkg.lock index 998e4eb..9250ec1 100644 --- a/src/shippingservice/Gopkg.lock +++ b/src/shippingservice/Gopkg.lock @@ -50,6 +50,14 @@ revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" +[[projects]] + digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "3e01752db0189b9157070a0e1668a620f9a85da2" + version = "v1.0.6" + [[projects]] name = "go.opencensus.io" packages = [ @@ -71,6 +79,14 @@ revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" +[[projects]] + branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + [[projects]] branch = "master" name = "golang.org/x/net" diff --git a/src/shippingservice/Gopkg.toml b/src/shippingservice/Gopkg.toml index eafb618..90a3ce9 100644 --- a/src/shippingservice/Gopkg.toml +++ b/src/shippingservice/Gopkg.toml @@ -37,6 +37,10 @@ name = "github.com/golang/protobuf" version = "1.2.0" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.6" + [[constraint]] name = "go.opencensus.io" version = "0.16.0" diff --git a/src/shippingservice/main.go b/src/shippingservice/main.go index f82787a..35f7ed4 100644 --- a/src/shippingservice/main.go +++ b/src/shippingservice/main.go @@ -16,13 +16,13 @@ package main import ( "fmt" - "log" "net" "os" "time" "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" + "github.com/sirupsen/logrus" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -38,6 +38,22 @@ const ( defaultPort = "50051" ) +var log *logrus.Logger + +func init() { + log = logrus.New() + log.Level = logrus.DebugLevel + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout +} + func main() { go initTracing() go initProfiling("shippingservice", "1.0.0") @@ -56,7 +72,7 @@ func main() { svc := &server{} pb.RegisterShippingServiceServer(srv, svc) healthpb.RegisterHealthServer(srv, svc) - log.Printf("Shipping Service listening on port %s", port) + log.Infof("Shipping Service listening on port %s", port) // Register reflection service on gRPC server. reflection.Register(srv) @@ -75,8 +91,8 @@ func (s *server) Check(ctx context.Context, req *healthpb.HealthCheckRequest) (* // GetQuote produces a shipping quote (cost) in USD. func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQuoteResponse, error) { - log.Printf("[GetQuote] received request") - defer log.Printf("[GetQuote] completed request") + log.Info("[GetQuote] received request") + defer log.Info("[GetQuote] completed request") // 1. Our quote system requires the total number of items to be shipped. count := 0 @@ -100,8 +116,8 @@ func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQ // ShipOrder mocks that the requested items will be shipped. // It supplies a tracking ID for notional lookup of shipment delivery status. func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.ShipOrderResponse, error) { - log.Printf("[ShipOrder] received request") - defer log.Printf("[ShipOrder] completed request") + log.Info("[ShipOrder] received request") + defer log.Info("[ShipOrder] completed request") // 1. Create a Tracking ID baseAddress := fmt.Sprintf("%s, %s, %s", in.Address.StreetAddress, in.Address.City, in.Address.State) id := CreateTrackingId(baseAddress) @@ -115,9 +131,9 @@ func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.Sh func initStats(exporter *stackdriver.Exporter) { view.RegisterExporter(exporter) if err := view.Register(ocgrpc.DefaultServerViews...); err != nil { - log.Printf("Error registering default server views") + log.Warn("Error registering default server views") } else { - log.Printf("Registered default server views") + log.Info("Registered default server views") } } @@ -127,21 +143,21 @@ func initTracing() { for i := 1; i <= 3; i++ { exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { - log.Printf("info: failed to initialize stackdriver exporter: %+v", err) + log.Warnf("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - log.Print("registered stackdriver tracing") + log.Info("registered stackdriver tracing") // Register the views to collect server stats. initStats(exporter) return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver exporter", d) + log.Infof("sleeping %v to retry initializing stackdriver exporter", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up") + log.Warn("could not initialize stackdriver exporter after retrying, giving up") } func initProfiling(service, version string) { @@ -154,14 +170,14 @@ func initProfiling(service, version string) { // ProjectID must be set if not running on GCP. // ProjectID: "my-project", }); err != nil { - log.Printf("warn: failed to start profiler: %+v", err) + log.Warnf("failed to start profiler: %+v", err) } else { - log.Print("started stackdriver profiler") + log.Info("started stackdriver profiler") return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver profiler", d) + log.Infof("sleeping %v to retry initializing stackdriver profiler", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up") + log.Warn("could not initialize stackdriver profiler after retrying, giving up") } diff --git a/src/shippingservice/quote.go b/src/shippingservice/quote.go index 09c040a..3732098 100644 --- a/src/shippingservice/quote.go +++ b/src/shippingservice/quote.go @@ -50,6 +50,6 @@ func quoteByCountFloat(count int) float64 { return 0 } count64 := float64(count) - var p float64 = 1 + (count64 * 0.2) + var p = 1 + (count64 * 0.2) return count64 + math.Pow(3, p) } From 29242504491623edd1e6089c104c6fbce24646f7 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Tue, 25 Sep 2018 16:43:39 -0700 Subject: [PATCH 3/3] emailservice Image Optimization (#51) Reduce docker image for emailservice to ~240 MB (down from ~ 1.31 GB) Main application (`email_server.py`) now runs as python 2.7. Before we had both Python 2.7 and Python 3 installed in the image. Switched to using `python:2.7-alpine3.8` as the base image, and used multi-stage dockerfiles to keep dependencies minimal. Fixes #49 From my shell: ``` $ docker build -t emailservice:dev . && docker run -it emailservice:dev Sending build context to Docker daemon 97.28kB Step 1/17 : FROM python:2.7-alpine3.8 as base ---> b2bc7255b42c Step 2/17 : FROM base as builder ---> b2bc7255b42c Step 3/17 : RUN apk add --update --no-cache gcc linux-headers make musl-dev python-dev g++ cairo-dev cairo openssl-dev gobject-introspection-dev ---> Using cache ---> 6daf3d9fe49a Step 4/17 : ENV GRPC_PYTHON_VERSION 1.15.0 ---> Using cache ---> 3e33d97d9580 Step 5/17 : RUN python -m pip install --upgrade pip ---> Using cache ---> e8fa3879c282 Step 6/17 : RUN pip install grpcio==${GRPC_PYTHON_VERSION} grpcio-tools==${GRPC_PYTHON_VERSION} ---> Using cache ---> c6fba7743eed Step 7/17 : COPY requirements.txt . ---> Using cache ---> 1f6b0a444980 Step 8/17 : RUN pip install -r requirements.txt ---> Using cache ---> 8cc0a7af6aa8 Step 9/17 : FROM base as final ---> b2bc7255b42c Step 10/17 : RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && chmod +x /bin/grpc_health_probe ---> Using cache ---> e954a0384081 Step 11/17 : ENV PYTHONUNBUFFERED=0 ---> Using cache ---> 64ece3d72a66 Step 12/17 : WORKDIR /email_server ---> Using cache ---> 27b34dc14492 Step 13/17 : COPY --from=builder /usr/local/lib/python2.7/ /usr/local/lib/python2.7/ ---> Using cache ---> 60035ec8dfd4 Step 14/17 : RUN apk add --no-cache libstdc++ ---> Using cache ---> 920be90c126e Step 15/17 : COPY . . ---> Using cache ---> 9541bed2d7a0 Step 16/17 : EXPOSE 8080 ---> Using cache ---> 48fbeaa852b9 Step 17/17 : ENTRYPOINT [ "python", "email_server.py" ] ---> Using cache ---> ff317770992d Successfully built ff317770992d Successfully tagged emailservice:dev starting the email service in dummy mode. listening on port: 8080 ``` --- src/emailservice/Dockerfile | 46 +++++++++++++++++++++---------- src/emailservice/requirements.txt | 40 +++++++++++++++++---------- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index 8395949..5a1bb22 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -1,27 +1,45 @@ +FROM python:3-alpine as base +FROM base as builder -# Use the grpc.io provided Python image as the base image -FROM grpc/python:1.0 +# gRPC and app deps +RUN apk add --update --no-cache \ + gcc \ + linux-headers \ + make \ + musl-dev \ + python-dev \ + g++ \ + # App Deps + cairo-dev \ + cairo \ + openssl-dev \ + gobject-introspection-dev -# download the grpc health probe +# get packages +COPY requirements.txt . +RUN pip install -r requirements.txt + +FROM base as final + +# Enable unbuffered logging +ENV PYTHONUNBUFFERED=1 + +# Download the grpc health probe RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe -# show python logs as they occur -ENV PYTHONUNBUFFERED=0 - -# install pip for python3 -RUN apt-get -qqy update && \ - apt-get -qqy install python3-pip - -# get packages WORKDIR /email_server -COPY requirements.txt . -RUN pip3 install -r requirements.txt + +# Grab packages from builder +COPY --from=builder /usr/local/lib/python3.7/ /usr/local/lib/python3.7/ + +# Need libstdc++ for grpc +RUN apk add --no-cache libstdc++ # Add the application COPY . . EXPOSE 8080 -ENTRYPOINT [ "python3", "email_server.py" ] +ENTRYPOINT [ "python", "email_server.py" ] \ No newline at end of file diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index de1567e..ca3f1c3 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -1,31 +1,41 @@ +asn1crypto==0.24.0 cachetools==2.1.0 -certifi==2018.4.16 +certifi==2018.8.24 +cffi==1.11.5 chardet==3.0.4 -cryptography==1.7.1 -google-api-core==1.2.1 -google-auth==1.5.0 +configparser==3.5.0 +cryptography==2.3.1 +entrypoints==0.2.3 +enum34==1.1.6 +futures==3.1.1 +google-api-core==1.4.0 +google-auth==1.5.1 google-cloud-core==0.28.1 google-cloud-trace==0.19.0 googleapis-common-protos==1.5.3 grpc-google-iam-v1==0.11.4 grpcio==1.12.1 -grpcio-health-checking==1.14.1 +grpcio-health-checking==1.12.1 grpcio-tools==1.12.1 idna==2.7 +ipaddress==1.0.22 +jeepney==0.4 Jinja2==2.10 -keyring==10.1 -keyrings.alt==1.3 +keyring==15.1.0 +keyrings.alt==3.1 MarkupSafe==1.0 -opencensus==0.1.5 -protobuf==3.6.0 -pyasn1==0.4.3 +opencensus==0.1.7 +protobuf==3.6.1 +pyasn1==0.4.4 pyasn1-modules==0.2.2 +pycairo==1.17.1 +pycparser==2.19 pycrypto==2.6.1 -pygobject==3.22.0 +PyGObject==3.30.1 pytz==2018.5 -pyxdg==0.25 +pyxdg==0.26 requests==2.19.1 -rsa==3.4.2 -SecretStorage==2.3.1 +rsa==4.0 +SecretStorage==3.1.0 six==1.11.0 -urllib3==1.23 +urllib3==1.23 \ No newline at end of file