Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elena Grahovac_Best practices for cloud-native ...

Codemotion
November 12, 2019

Elena Grahovac_Best practices for cloud-native go services_Codemotion Berlin 2019

It is easy to fall in love with a new programming language, tool or architectural approach, especially as it gains in popularity. Usually, we start trying new technology by understanding a "tour" or the "quick start" guidance. However, in practice, it is not always so simple to bridge the gap between our first web server and a real production-ready application, this is especially true if this application should be prepared for cloud-native infrastructure. This talk is for those who touched Go and fell in love with it and now wonder how to achieve production readiness.

About:
Elena Grahovac: Lead TechOps Automation Engineer - N26
Elena is a Lead TechOps Automation Engineer at N26 and a co-host of the GolangShow podcast. With 11+ years of overall experience in IT, she values DevOps culture and passionate about automation, software architecture and site reliability engineering topics.

Codemotion

November 12, 2019
Tweet

More Decks by Codemotion

Other Decks in Technology

Transcript

  1. 12 factor apps 一 Revision control 一 Dependencies 一 Config

    in the environment 一 Backing services as attached resources 一 Build and run stages 一 Stateless processes 一 Port binding 一 Environments as similar as possible 一 ... 12factor.net
  2. Production readiness 一 Stability 一 Reliability 一 Scalability 一 Fault

    tolerance 一 Catastrophe-preparedness 一 Performance 一 Monitoring 一 Documentation by Susan J. Fowler
  3. How to be Cloud Native? 一 Operate managed infrastructure 一

    Develop isolated containerized services 一 Communicate through network 一 Follow microservice design principles 一 Use DevOps techniques
  4. What developers can do? 一 Structure the services properly 一

    Be quality-oriented 一 Think about observability and operability 一 Shutdown gracefully
  5. What developers can do? 一 Manage configuration wisely 一 Be

    accurate with dependencies 一 Containerize applications properly 一 Automate as much as possible
  6. Structuring 一 Structuring is important 一 There is no one

    right way to structure apps 一 For inspiration: https://github.com/golang-standards/project-layout
  7. Structuring in practice 一 cmd for small and simple entry

    points E.g. I might have cmd/myctl and cmd/myserver
  8. Structuring in practice 一 internal for packages that should be

    available for current project only If I don’t want a package being available for import by other projects, I’ll store it under internal See also: ‘Go 1.4 Internal Packages’ - https://docs.google.com/document/d/1e8kOo3r51b2BWtTs_1uADIA5djfXhPT36s6e HVRIvaU/edit
  9. Testing Testing deserves its own talk… Maybe even a few.

    一 Why there is no “assert” in the standard library: https://golang.org/doc/faq#testing_framework 一 Learn testing: https://github.com/golang/go/wiki/LearnTesting
  10. Fuzzy testing 一 My application works with a complex input

    一 I validate it 一 I want to make sure that my validation is good enough 一 https://github.com/dvyukov/go-fuzz
  11. Static code analysis: how? 一 Run the most popular linters:

    golangci-lint https://github.com/golangci/golangci-lint 一 Fast assessment for open source projects: https://goreportcard.com
  12. Static code analysis: when? 一 Local hooks (pre-commit): https://github.com/dnephin/pre-commit-golang 一

    Server hooks (push, pull request) 一 Dedicated Docker image 一 Continuous Integration stage
  13. Observability: logs 一 Log errors or strange situations! 一 Log

    “stages” of your application 一 Try multiple log levels 一 Try “tags” to classify your logs 一 Tip: if something goes wrong, check performance of your logger
  14. Observability Metrics: 一 Define, measure and report business and SLA

    metrics 一 Business metrics might be useful as well! Traces: 一 Tracing is a technique that shows how a single request goes through your services
  15. Operability: health checks 一 “Healthy/Unhealthy”: application state, business and performance

    metrics 一 “Readiness”: report if application is ready to handle requests
  16. Graceful shutdown 一 Recover panics 一 Don’t panic, return errors

    一 Handle errors 一 Listen to OS signals 一 Provide shutdown for your functional units
  17. Versioning Use linker to provide current version, commit hash or

    any other data to identify the version: go build -ldflags "-X main.version=put_version_here" package main import ( "fmt" ) var ( version = "unset" ) func main() { fmt.Printf("The version is: %s\n", version) }
  18. Configuration 一 Set configuration via env 一 Systems solution: https://github.com/kelseyhightower/envconfig

    一 Keep secrets safe 一 Prepare a systems solution if you need to deal with secrets on the application level
  19. Secrets: Solutions 一 Hashicorp Vault https://www.vaultproject.io 一 Google Cloud: KMS,

    HMS https://cloud.google.com/solutions/secrets-management/#tools 一 Other cloud solutions
  20. Dependencies: problem definition 一 Design & quality 一 Testing 一

    Activity & maintenance 一 Licenses 一 Integrity & dependencies 一 Immutability & updates
  21. Dependencies checklist 一 Description 一 Documentation 一 Go Report Card

    一 Issues & pull requests 一 Code coverage 一 Other reports 一 Repeat the same for dependencies of this dependency
  22. GOPROXY: pros 一 Availability 一 Independency 一 Immutability 一 Archives

    are faster than git repos 一 Additional opportunities
  23. GOPROXY: cons 一 Workflows around module management 一 Current implementations

    一 Transitive dependencies still might cause problems
  24. Builds 一 Compile a binary on the CI/CD node &

    copy it 一 Multi-staging builds
  25. The simplest “monostage” image FROM scratch ENV PORT 8080 COPY

    bin/myapp /myapp EXPOSE $PORT CMD ["myapp"]
  26. Multi-staging builds: GOPROXY # Initial stage: download modules FROM registry/golang:1.13

    AS modules ADD go.mod go.sum /m/ RUN cd /m && go mod download
  27. Multi-staging builds: building phase # The second stage. Build the

    binary FROM registry/golang:1.13 AS builder COPY --from=modules /go/pkg /go/pkg # add a non-privileged user RUN useradd -u 10001 myapp RUN mkdir -p /go/src/github.com/rumyantseva/myapp ADD . /go/src/github.com/rumyantseva/myapp WORKDIR /go/src/github.com/rumyantseva/myapp # Build the binary with go build RUN CGO_ENABLED=0 go build \ -o bin/myapp github.com/rumyantseva/myapp/cmd/myapp
  28. Multi-staging builds: running phase # The final stage. Run the

    binary FROM scratch ENV PORT 8080 # certificates to interact with other services COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # don't forget /etc/passwd from previous stage COPY --from=builder /etc/passwd /etc/passwd USER myapp # and finally the binary COPY --from=builder /go/src/github.com/rumyantseva/myapp/bin/myapp /myapp EXPOSE $PORT CMD ["myapp"]
  29. Base image for testing FROM registry/golang:1.13 # Change here to

    update ENV VERSION 1.18.0 ENV CHECKSUM 0ef2c502035d5f12d6d3a30a7c4469cfcae4dd3828d15fbbfb799c8331cd51c4 # Make sure we have a fixed golangci-lint script with a chekcsum check RUN echo "${CHECKSUM} golangci-lint-${VERSION}-linux-amd64.tar.gz" > CHECKSUM # Download from Github the specified release and extract into the go/bin folder RUN curl -L "https://github.com/golangci/golangci-lint/ releases/download/v${VERSION}/golangci-lint-${VERSION}-linux-amd64.tar.gz" \ -o golangci-lint-${VERSION}-linux-amd64.tar.gz \ && shasum -a 256 -c CHECKSUM \ && tar xvzf golangci-lint-${VERSION}-linux-amd64.tar.gz \ --strip-components=1 \ -C ./bin \ golangci-lint-${VERSION}-linux-amd64/golangci-lint # Clean up RUN rm -rf CHECKSUM "golangci-lint-${VERSION}-linux-amd64.tar.gz"
  30. Run linters and tests FROM registry/golang-linters RUN mkdir -p /go/src/github.com/rumyantseva/myapp

    ADD . /go/src/github.com/rumyantseva/myapp WORKDIR /go/src/github.com/rumyantseva/myapp # Run linters RUN golangci-lint run \ --no-config --issues-exit-code=1 \ --deadline=10m --exclude-use-default=false \ ./... # Run tests RUN go test -timeout=600s -v --race ./...
  31. Repeatable actions 一 Define repeatable actions and prepare a tool

    to call them fast: • The actions you call when CI/CD-ing • Checkers and tests • Application building • Dealing with container images 一 GNU Make as a classic approach 一 A fancy alternative: https://github.com/go-task/task
  32. Automate creation of new services 一 Prepare a typical “Cloud-Native

    Hello World” service 一 Define templates based on it 一 Use code generation to produce new services from the templates 一 Consider details specific for your infrastructure or project For inspiration: https://github.com/takama/caldera
  33. What’s next? 一 You don’t have to agree with all

    the practices from this talk 一 When disagree, ask yourself why 一 Discover, try and adopt new practices 一 Document what you adopted 一 Share your experience with the community