SlideShare una empresa de Scribd logo
Readying your Go webservice
Ralph Ligtenberg
September 12, 2019
https://www.pexels.com/photo/web-close-up-photography-2632059/
Ralph Ligtenberg
Tech Lead @ Travix
C#, Go, Google Cloud Platform
twitter.com/prutswonder
medium.com/@prutswonder
linkedin.com/in/ralphligtenberg
Done
❏ “Works on my machine”
❏ Merged to master
❏ Unit & Integration tests
❏ Works as expected
Ready
❏ “Works anywhere”
❏ Deployed & tested
❏ Acceptance & load tests
❏ Performs as expected
https://www.pexels.com/photo/photo-of-green-data-matrix-1089438/
● CI/CD: build & deployment automation
● Observability: logging, monitoring & tracing
● Resilience: Circuit breaker & panic recovery
● Lifecycle management: warm-up & shutdown
● Security: authentication & authorization
From “Done” to “Ready”
https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/
CI/CD: Kubernetes & Estafette
https://www.pexels.com/photo/red-and-gray-industrial-machinery-2569842/
Estafette build stage
# https://estafette.io/usage/manifest/#build-stages
stages:
test-lint-build:
image: golang:1.13.0
env:
CGO_ENABLED: 0
GOOS: linux
GO111MODULE: "on"
GOGC: off
commands:
- go get -u golang.org/x/lint/golint
- CGO_ENABLED=1 go test -race -cover ./...
- golint -set_exit_status ./...
- go build -a -installsuffix cgo -o ./publish/${ESTAFETTE_LABEL_APP} .
Estafette docker image creation
# https://estafette.io/usage/extensions/estafette-extensions/#extensions-docker
bake:
image: extensions/docker:stable
action: build
path: ./publish
push:
image: extensions/docker:stable
action: push
Estafette deployment
# https://estafette.io/usage/manifest/#releases
releases:
development:
stages:
deploy:
image: extensions/gke:stable
container:
port: 8080
env:
CORS_ORIGINS: "*"
cpu:
request: 10m
limit: 100m
memory:
request: 25Mi
limit: 100Mi
# Continued on the right -->
liveness:
path: /live
readiness:
path: /ready
sidecar:
healthcheckpath: /live
slack-notify:
image: extensions/slack-build-status:stable
workspace: travix
channels:
- '#{ESTAFETTE_LABEL_TEAM}-builds'
when:
status == 'failed'
Logging: ELK Stack & zerolog
https://www.pexels.com/photo/bark-brown-cut-daylight-296333/
Logging
import (
"os"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
// Logger is used to write log messages.
type Logger struct {
level zerolog.Level
logger zerolog.Logger
}
// NewLogger sets and returns a new global-level logger.
func NewLogger(appGroup, appName, logLevel string) Logger {
zLogLevel := ToZeroLogLevel(logLevel)
logger := log.Output(v3FormatWriter{Out: os.Stderr}).With().
Str("appgroup", appGroup).Str("appname", appName).
Logger().Level(zLogLevel)
log.Logger = logger
return Logger{level: zLogLevel, logger: logger}
}
Monitoring: Prometheus & Grafana
https://www.pexels.com/photo/black-and-white-business-chart-computer-241544/
Custom metrics
import p8s "github.com/prometheus/client_golang/prometheus"
var (
labelNames = []string{"affiliate", "status"}
responseCounter = p8s.NewCounterVec(p8s.CounterOpts{Name: "app_response_count"}, labelNames)
)
func init() {
p8s.MustRegister(responseCounter)
}
func countFailedResponse(affiliate string, reason string) {
responseCounter.WithLabelValues(affiliate, reason).Inc()
}
func countSuccessResponse(affiliate string) {
responseCounter.WithLabelValues(affiliate, "success").Inc()
}
Tracing: Jaeger
https://www.pexels.com/photo/white-airplane-728824/
Tracing middleware
// WithTracing creates a span for each request
func WithTracing(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// retrieve span context from upstream caller if available
tracingCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(r.Header))
span := opentracing.StartSpan(fmt.Sprintf("%v %v", r.Method, r.URL.Path),
ext.RPCServerOption(tracingCtx))
defer span.Finish()
ext.HTTPMethod.Set(span, r.Method)
ext.HTTPUrl.Set(span, r.URL.String())
tw := tracedResponseWriter{ResponseWriter: w}
rc := r.WithContext(opentracing.ContextWithSpan(r.Context(), span))
next.ServeHTTP(&tw, rc)
ext.HTTPStatusCode.Set(span, uint16(tw.Status()))
})
}
Tracing: Jaeger
Circuit breakers
https://www.pexels.com/photo/2-man-on-construction-site-during-daytime-159306/
Circuit breaker
// Try wraps a function with circuit breaking
func (b *Breaker) Try(cmdKey string, tryFunc func() (
interface{}, error)) (interface{}, error) {
type result struct {
response interface{}
err error
}
startTime := time.Now()
cmd := b.getOrAddCommand(cmdKey)
if !cmd.allowRequest() {
cmd.registerShortCircuited()
return nil, ErrRequestShortCircuited
}
// Continued on the right -->
ch := make(chan result, 1)
go func(ch chan result) {
defer close(ch)
response, err := tryFunc()
ch <- result{response: response, err: err}
}(ch)
timer := time.NewTimer(cmd.timeout)
defer timer.Stop()
select {
case res := <-ch:
if res.err != nil {
cmd.registerFailure(time.Since(startTime))
return nil, res.err
}
cmd.registerSuccess(time.Since(startTime))
return res.response, nil
case <-timer.C:
cmd.registerTimeout(time.Since(startTime))
return nil, &ErrRequestTimeout{commandKey: cmdKey,
timeout: cmd.timeout}
}
}
Panic recovery middleware
// WithPanicRecoveryFunc recovers any panics that occur in the next http handler.
func WithPanicRecoveryFunc(logger logging.Logger, next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
logger.Error("PanicRecovered").
Bytes("stacktrace", debug.Stack()).
LogErr(fmt.Errorf("%s", rec))
w.WriteHeader(http.StatusInternalServerError)
}
}()
next(w, r)
}
}
Application start-up
https://www.pexels.com/photo/close-up-engine-landscape-locomotive-533608/
Server & start-up
type shutdownFunc func() error
type server struct {
ctx context.Context
version versionInfo
shutdown shutdownFunc
}
func (s *server) Serve() {
// (...)
mux := http.NewServeMux()
svr := http.Server{
ReadTimeout: time.Second * 3,
ReadHeaderTimeout: time.Second * 2,
WriteTimeout: time.Second * 10,
Addr: ":8080",
Handler: mux,
}
// Continued on the right -->
mux.HandleFunc("/ready", s.ready)
mux.HandleFunc("/live", s.live)
// Put your own endpoints here
err = s.setControllers(mux)
if err != nil {
log.Error("ServerControllerError").LogErr(err)
return
}
_ = svr.ListenAndServe() // Blocks until server stops
}
func (s *server) live(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, "Alive!")
}
func (s *server) ready(w http.ResponseWriter, r *http.Request) {
//TODO: Determine readiness
_, _ = io.WriteString(w, "Ready!")
}
Graceful shutdown
https://www.pexels.com/photo/bulb-close-up-conceptual-current-207420/
Server with graceful shutdown
func (s *server) Serve() {
// (...)
s.shutdown = func() error {
cancelCtx, cancel := context.WithTimeout(s.ctx,
time.Second * 10)
defer cancel()
err := svr.Shutdown(cancelCtx)
return err
}
signalCh := make(chan os.Signal, 1)
go s.listenToShutdownSignals(signalCh)
_ = svr.ListenAndServe() // Blocks until server stops
}
func (s *server) listenToShutdownSignals(
signalCh chan os.Signal) {
signal.Notify(signalCh,
syscall.SIGINT, // kill -SIGINT XXXX or Ctrl+c
syscall.SIGTERM, // kill -SIGTERM XXXX
syscall.SIGQUIT) // kill -SIGQUIT XXXX
for {
sig := <-signalCh
switch sig {
case syscall.SIGINT:
fallthrough
case syscall.SIGTERM:
fallthrough
case syscall.SIGQUIT:
s.shutdown()
return
}
}
}
Security
https://www.pexels.com/photo/door-handle-key-keyhole-279810/
Estafette & cloud credentials
releases:
development:
stages:
deploy:
image: extensions/gke:stable
visibility: public-whitelist
container:
# (...)
sidecar:
healthcheckpath: /live
useGoogleCloudCredentials: true
Estafette secrets
production:
# https://estafette.io/usage/manifest/#release-actions
actions:
- name: deploy-canary
- name: deploy-stable
- name: rollback-canary
stages:
deploy:
image: extensions/gke:stable
visibility: public
container:
port: 8080
env:
# AES-256-encrypted value
AUTH_BASIC_TOKEN: estafette.secret(6J1RtwwpvMIhMtbE.QuRJhnTgO8FcHP-cEtJy72pTzaTw2L5-1zeT0A==)
Authorization middleware
import "net/http"
// WithAuthBasic performs a basic authorization check
func WithAuthBasic(token string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Header.Get("Authorization") {
case "Basic " + token:
next.ServeHTTP(w, r)
case "":
w.Header().Add("WWW-Authenticate", "Basic")
w.WriteHeader(http.StatusUnauthorized)
default:
w.WriteHeader(http.StatusForbidden)
}
})
}
CORS middleware
import "github.com/rs/cors"
// WithCORS wraps the handler with CORS options.
func WithCORS(handlerFunc http.HandlerFunc) http.Handler {
corsOptions := cors.Options{
AllowedOrigins: []string{os.Getenv("CORS_ORIGINS")},
AllowedMethods: []string{"HEAD", "OPTIONS", "GET", "PUT", "POST"},
AllowedHeaders: []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "X-CSRF-Token"},
ExposedHeaders: []string{
"Access-Control-Allow-Headers",
"Access-Control-Allow-Methods",
"Access-Control-Max-Age",
},
MaxAge: 0,
}
return cors.New(corsOptions).Handler(handlerFunc)
}
● Automate builds & deployments for your webservice
● Observe your webservice
● Make your webservice resilient
● Warm up your webservice
● Shut down your webservice gracefully
● Secure your webservice
Getting “Ready”
https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/
Estafette: https://estafette.io/
Zerolog: https://github.com/rs/zerolog
Prometheus: https://github.com/prometheus/client_golang
Grafana: https://grafana.com/
Jaeger: https://www.jaegertracing.io/
CORS: https://github.com/rs/cors
Circuit breaker: https://martinfowler.com/bliki/CircuitBreaker.html
References
https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/
Thank you!
Ralph Ligtenberg - @prutswonder
stock images downloaded from Pexels.com
https://www.pexels.com/photo/silhouette-of-airplanes-47044/

Más contenido relacionado

La actualidad más candente

Puppet and Openshift
Puppet and OpenshiftPuppet and Openshift
Puppet and Openshift
Gareth Rushgrove
 
Quay 3.3 installation
Quay 3.3 installationQuay 3.3 installation
Quay 3.3 installation
Jooho Lee
 
Bootstrapping multidc observability stack
Bootstrapping multidc observability stackBootstrapping multidc observability stack
Bootstrapping multidc observability stack
Bram Vogelaar
 
Roll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and LuaRoll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and Lua
Jon Moore
 
Ubic
UbicUbic
Using ngx_lua in upyun 2
Using ngx_lua in upyun 2Using ngx_lua in upyun 2
Using ngx_lua in upyun 2
OpenRestyCon
 
Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"
Fwdays
 
OpenShift4 Installation by UPI on kvm
OpenShift4 Installation by UPI on kvmOpenShift4 Installation by UPI on kvm
OpenShift4 Installation by UPI on kvm
Jooho Lee
 
Puppet and the HashiStack
Puppet and the HashiStackPuppet and the HashiStack
Puppet and the HashiStack
Bram Vogelaar
 
Puppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the ForgePuppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the Forge
Puppet
 
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet
 
OlinData Puppet Presentation for MOSC 2012
OlinData Puppet Presentation for MOSC 2012OlinData Puppet Presentation for MOSC 2012
OlinData Puppet Presentation for MOSC 2012
Walter Heck
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
tomcopeland
 
Fun with Ruby and Cocoa
Fun with Ruby and CocoaFun with Ruby and Cocoa
Fun with Ruby and Cocoa
Patrick Huesler
 
Trac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイル
Trac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイルTrac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイル
Trac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイル
Shuji Watanabe
 
Lua tech talk
Lua tech talkLua tech talk
Lua tech talk
Locaweb
 
Gevent what's the point
Gevent what's the pointGevent what's the point
Gevent what's the point
seanmcq
 
openATTIC using grafana and prometheus
openATTIC using  grafana and prometheusopenATTIC using  grafana and prometheus
openATTIC using grafana and prometheus
Alex Lau
 
Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...
Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...
Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...
addame
 
2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku
ronnywang_tw
 

La actualidad más candente (20)

Puppet and Openshift
Puppet and OpenshiftPuppet and Openshift
Puppet and Openshift
 
Quay 3.3 installation
Quay 3.3 installationQuay 3.3 installation
Quay 3.3 installation
 
Bootstrapping multidc observability stack
Bootstrapping multidc observability stackBootstrapping multidc observability stack
Bootstrapping multidc observability stack
 
Roll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and LuaRoll Your Own API Management Platform with nginx and Lua
Roll Your Own API Management Platform with nginx and Lua
 
Ubic
UbicUbic
Ubic
 
Using ngx_lua in upyun 2
Using ngx_lua in upyun 2Using ngx_lua in upyun 2
Using ngx_lua in upyun 2
 
Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"Anton Moldovan "Load testing which you always wanted"
Anton Moldovan "Load testing which you always wanted"
 
OpenShift4 Installation by UPI on kvm
OpenShift4 Installation by UPI on kvmOpenShift4 Installation by UPI on kvm
OpenShift4 Installation by UPI on kvm
 
Puppet and the HashiStack
Puppet and the HashiStackPuppet and the HashiStack
Puppet and the HashiStack
 
Puppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the ForgePuppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the Forge
 
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
 
OlinData Puppet Presentation for MOSC 2012
OlinData Puppet Presentation for MOSC 2012OlinData Puppet Presentation for MOSC 2012
OlinData Puppet Presentation for MOSC 2012
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
 
Fun with Ruby and Cocoa
Fun with Ruby and CocoaFun with Ruby and Cocoa
Fun with Ruby and Cocoa
 
Trac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイル
Trac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイルTrac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイル
Trac/Subversion/JUnit/Maven/Jenkinsで構築する開発スタイル
 
Lua tech talk
Lua tech talkLua tech talk
Lua tech talk
 
Gevent what's the point
Gevent what's the pointGevent what's the point
Gevent what's the point
 
openATTIC using grafana and prometheus
openATTIC using  grafana and prometheusopenATTIC using  grafana and prometheus
openATTIC using grafana and prometheus
 
Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...
Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...
Montreal On Rails 5 : Rails deployment using : Nginx, Mongrel, Mongrel_cluste...
 
2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku
 

Similar a Meetup talk: Readying your Go Webservice

Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
Paweł Kowalczuk
 
How to Leverage Go for Your Networking Needs
How to Leverage Go for Your Networking NeedsHow to Leverage Go for Your Networking Needs
How to Leverage Go for Your Networking Needs
DigitalOcean
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
KAI CHU CHUNG
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
Bo-Yi Wu
 
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Masahiro Nagano
 
From Node to Go
From Node to GoFrom Node to Go
From Node to Go
John Maxwell
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Web sockets in Java
Web sockets in JavaWeb sockets in Java
Web sockets in Java
Pance Cavkovski
 
如何透過 Go-kit 快速搭建微服務架構應用程式實戰
如何透過 Go-kit 快速搭建微服務架構應用程式實戰如何透過 Go-kit 快速搭建微服務架構應用程式實戰
如何透過 Go-kit 快速搭建微服務架構應用程式實戰
KAI CHU CHUNG
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
Oleg Podsechin
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
Jorge Ortiz
 
Vladimir Vorontsov - Splitting, smuggling and cache poisoning come back
Vladimir Vorontsov - Splitting, smuggling and cache poisoning come backVladimir Vorontsov - Splitting, smuggling and cache poisoning come back
Vladimir Vorontsov - Splitting, smuggling and cache poisoning come back
DefconRussia
 
Angular js security
Angular js securityAngular js security
Angular js security
Jose Manuel Ortega Candel
 
REST made simple with Java
REST made simple with JavaREST made simple with Java
REST made simple with Java
elliando dias
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHP
King Foo
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
Oleg Podsechin
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
Ian Barber
 
Building Web APIs that Scale
Building Web APIs that ScaleBuilding Web APIs that Scale
Building Web APIs that Scale
Salesforce Developers
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin Yu
 
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
DevClub_lv
 

Similar a Meetup talk: Readying your Go Webservice (20)

Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
How to Leverage Go for Your Networking Needs
How to Leverage Go for Your Networking NeedsHow to Leverage Go for Your Networking Needs
How to Leverage Go for Your Networking Needs
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015
 
From Node to Go
From Node to GoFrom Node to Go
From Node to Go
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Web sockets in Java
Web sockets in JavaWeb sockets in Java
Web sockets in Java
 
如何透過 Go-kit 快速搭建微服務架構應用程式實戰
如何透過 Go-kit 快速搭建微服務架構應用程式實戰如何透過 Go-kit 快速搭建微服務架構應用程式實戰
如何透過 Go-kit 快速搭建微服務架構應用程式實戰
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
 
Vladimir Vorontsov - Splitting, smuggling and cache poisoning come back
Vladimir Vorontsov - Splitting, smuggling and cache poisoning come backVladimir Vorontsov - Splitting, smuggling and cache poisoning come back
Vladimir Vorontsov - Splitting, smuggling and cache poisoning come back
 
Angular js security
Angular js securityAngular js security
Angular js security
 
REST made simple with Java
REST made simple with JavaREST made simple with Java
REST made simple with Java
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHP
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
Building Web APIs that Scale
Building Web APIs that ScaleBuilding Web APIs that Scale
Building Web APIs that Scale
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
 

Último

Project Management Semester Long Project - Acuity
Project Management Semester Long Project - AcuityProject Management Semester Long Project - Acuity
Project Management Semester Long Project - Acuity
jpupo2018
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
danishmna97
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
Federico Razzoli
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
shyamraj55
 
GenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizationsGenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizations
kumardaparthi1024
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
panagenda
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
Mariano Tinti
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
panagenda
 
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptxOcean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
SitimaJohn
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Jeffrey Haguewood
 
WeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation TechniquesWeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation Techniques
Postman
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
Zilliz
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
innovationoecd
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
Jakub Marek
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Wask
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
MichaelKnudsen27
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
Octavian Nadolu
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 

Último (20)

Project Management Semester Long Project - Acuity
Project Management Semester Long Project - AcuityProject Management Semester Long Project - Acuity
Project Management Semester Long Project - Acuity
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
 
GenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizationsGenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizations
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
 
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptxOcean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
 
WeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation TechniquesWeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation Techniques
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 

Meetup talk: Readying your Go Webservice

  • 1. Readying your Go webservice Ralph Ligtenberg September 12, 2019 https://www.pexels.com/photo/web-close-up-photography-2632059/
  • 2. Ralph Ligtenberg Tech Lead @ Travix C#, Go, Google Cloud Platform twitter.com/prutswonder medium.com/@prutswonder linkedin.com/in/ralphligtenberg
  • 3. Done ❏ “Works on my machine” ❏ Merged to master ❏ Unit & Integration tests ❏ Works as expected Ready ❏ “Works anywhere” ❏ Deployed & tested ❏ Acceptance & load tests ❏ Performs as expected https://www.pexels.com/photo/photo-of-green-data-matrix-1089438/
  • 4. ● CI/CD: build & deployment automation ● Observability: logging, monitoring & tracing ● Resilience: Circuit breaker & panic recovery ● Lifecycle management: warm-up & shutdown ● Security: authentication & authorization From “Done” to “Ready” https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/
  • 5. CI/CD: Kubernetes & Estafette https://www.pexels.com/photo/red-and-gray-industrial-machinery-2569842/
  • 6.
  • 7. Estafette build stage # https://estafette.io/usage/manifest/#build-stages stages: test-lint-build: image: golang:1.13.0 env: CGO_ENABLED: 0 GOOS: linux GO111MODULE: "on" GOGC: off commands: - go get -u golang.org/x/lint/golint - CGO_ENABLED=1 go test -race -cover ./... - golint -set_exit_status ./... - go build -a -installsuffix cgo -o ./publish/${ESTAFETTE_LABEL_APP} .
  • 8. Estafette docker image creation # https://estafette.io/usage/extensions/estafette-extensions/#extensions-docker bake: image: extensions/docker:stable action: build path: ./publish push: image: extensions/docker:stable action: push
  • 9. Estafette deployment # https://estafette.io/usage/manifest/#releases releases: development: stages: deploy: image: extensions/gke:stable container: port: 8080 env: CORS_ORIGINS: "*" cpu: request: 10m limit: 100m memory: request: 25Mi limit: 100Mi # Continued on the right --> liveness: path: /live readiness: path: /ready sidecar: healthcheckpath: /live slack-notify: image: extensions/slack-build-status:stable workspace: travix channels: - '#{ESTAFETTE_LABEL_TEAM}-builds' when: status == 'failed'
  • 10. Logging: ELK Stack & zerolog https://www.pexels.com/photo/bark-brown-cut-daylight-296333/
  • 11. Logging import ( "os" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) // Logger is used to write log messages. type Logger struct { level zerolog.Level logger zerolog.Logger } // NewLogger sets and returns a new global-level logger. func NewLogger(appGroup, appName, logLevel string) Logger { zLogLevel := ToZeroLogLevel(logLevel) logger := log.Output(v3FormatWriter{Out: os.Stderr}).With(). Str("appgroup", appGroup).Str("appname", appName). Logger().Level(zLogLevel) log.Logger = logger return Logger{level: zLogLevel, logger: logger} }
  • 12. Monitoring: Prometheus & Grafana https://www.pexels.com/photo/black-and-white-business-chart-computer-241544/
  • 13. Custom metrics import p8s "github.com/prometheus/client_golang/prometheus" var ( labelNames = []string{"affiliate", "status"} responseCounter = p8s.NewCounterVec(p8s.CounterOpts{Name: "app_response_count"}, labelNames) ) func init() { p8s.MustRegister(responseCounter) } func countFailedResponse(affiliate string, reason string) { responseCounter.WithLabelValues(affiliate, reason).Inc() } func countSuccessResponse(affiliate string) { responseCounter.WithLabelValues(affiliate, "success").Inc() }
  • 14.
  • 16. Tracing middleware // WithTracing creates a span for each request func WithTracing(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // retrieve span context from upstream caller if available tracingCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header)) span := opentracing.StartSpan(fmt.Sprintf("%v %v", r.Method, r.URL.Path), ext.RPCServerOption(tracingCtx)) defer span.Finish() ext.HTTPMethod.Set(span, r.Method) ext.HTTPUrl.Set(span, r.URL.String()) tw := tracedResponseWriter{ResponseWriter: w} rc := r.WithContext(opentracing.ContextWithSpan(r.Context(), span)) next.ServeHTTP(&tw, rc) ext.HTTPStatusCode.Set(span, uint16(tw.Status())) }) }
  • 19. Circuit breaker // Try wraps a function with circuit breaking func (b *Breaker) Try(cmdKey string, tryFunc func() ( interface{}, error)) (interface{}, error) { type result struct { response interface{} err error } startTime := time.Now() cmd := b.getOrAddCommand(cmdKey) if !cmd.allowRequest() { cmd.registerShortCircuited() return nil, ErrRequestShortCircuited } // Continued on the right --> ch := make(chan result, 1) go func(ch chan result) { defer close(ch) response, err := tryFunc() ch <- result{response: response, err: err} }(ch) timer := time.NewTimer(cmd.timeout) defer timer.Stop() select { case res := <-ch: if res.err != nil { cmd.registerFailure(time.Since(startTime)) return nil, res.err } cmd.registerSuccess(time.Since(startTime)) return res.response, nil case <-timer.C: cmd.registerTimeout(time.Since(startTime)) return nil, &ErrRequestTimeout{commandKey: cmdKey, timeout: cmd.timeout} } }
  • 20. Panic recovery middleware // WithPanicRecoveryFunc recovers any panics that occur in the next http handler. func WithPanicRecoveryFunc(logger logging.Logger, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { defer func() { if rec := recover(); rec != nil { logger.Error("PanicRecovered"). Bytes("stacktrace", debug.Stack()). LogErr(fmt.Errorf("%s", rec)) w.WriteHeader(http.StatusInternalServerError) } }() next(w, r) } }
  • 22. Server & start-up type shutdownFunc func() error type server struct { ctx context.Context version versionInfo shutdown shutdownFunc } func (s *server) Serve() { // (...) mux := http.NewServeMux() svr := http.Server{ ReadTimeout: time.Second * 3, ReadHeaderTimeout: time.Second * 2, WriteTimeout: time.Second * 10, Addr: ":8080", Handler: mux, } // Continued on the right --> mux.HandleFunc("/ready", s.ready) mux.HandleFunc("/live", s.live) // Put your own endpoints here err = s.setControllers(mux) if err != nil { log.Error("ServerControllerError").LogErr(err) return } _ = svr.ListenAndServe() // Blocks until server stops } func (s *server) live(w http.ResponseWriter, r *http.Request) { _, _ = io.WriteString(w, "Alive!") } func (s *server) ready(w http.ResponseWriter, r *http.Request) { //TODO: Determine readiness _, _ = io.WriteString(w, "Ready!") }
  • 24. Server with graceful shutdown func (s *server) Serve() { // (...) s.shutdown = func() error { cancelCtx, cancel := context.WithTimeout(s.ctx, time.Second * 10) defer cancel() err := svr.Shutdown(cancelCtx) return err } signalCh := make(chan os.Signal, 1) go s.listenToShutdownSignals(signalCh) _ = svr.ListenAndServe() // Blocks until server stops } func (s *server) listenToShutdownSignals( signalCh chan os.Signal) { signal.Notify(signalCh, syscall.SIGINT, // kill -SIGINT XXXX or Ctrl+c syscall.SIGTERM, // kill -SIGTERM XXXX syscall.SIGQUIT) // kill -SIGQUIT XXXX for { sig := <-signalCh switch sig { case syscall.SIGINT: fallthrough case syscall.SIGTERM: fallthrough case syscall.SIGQUIT: s.shutdown() return } } }
  • 26. Estafette & cloud credentials releases: development: stages: deploy: image: extensions/gke:stable visibility: public-whitelist container: # (...) sidecar: healthcheckpath: /live useGoogleCloudCredentials: true
  • 27. Estafette secrets production: # https://estafette.io/usage/manifest/#release-actions actions: - name: deploy-canary - name: deploy-stable - name: rollback-canary stages: deploy: image: extensions/gke:stable visibility: public container: port: 8080 env: # AES-256-encrypted value AUTH_BASIC_TOKEN: estafette.secret(6J1RtwwpvMIhMtbE.QuRJhnTgO8FcHP-cEtJy72pTzaTw2L5-1zeT0A==)
  • 28. Authorization middleware import "net/http" // WithAuthBasic performs a basic authorization check func WithAuthBasic(token string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.Header.Get("Authorization") { case "Basic " + token: next.ServeHTTP(w, r) case "": w.Header().Add("WWW-Authenticate", "Basic") w.WriteHeader(http.StatusUnauthorized) default: w.WriteHeader(http.StatusForbidden) } }) }
  • 29. CORS middleware import "github.com/rs/cors" // WithCORS wraps the handler with CORS options. func WithCORS(handlerFunc http.HandlerFunc) http.Handler { corsOptions := cors.Options{ AllowedOrigins: []string{os.Getenv("CORS_ORIGINS")}, AllowedMethods: []string{"HEAD", "OPTIONS", "GET", "PUT", "POST"}, AllowedHeaders: []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "X-CSRF-Token"}, ExposedHeaders: []string{ "Access-Control-Allow-Headers", "Access-Control-Allow-Methods", "Access-Control-Max-Age", }, MaxAge: 0, } return cors.New(corsOptions).Handler(handlerFunc) }
  • 30. ● Automate builds & deployments for your webservice ● Observe your webservice ● Make your webservice resilient ● Warm up your webservice ● Shut down your webservice gracefully ● Secure your webservice Getting “Ready” https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/
  • 31. Estafette: https://estafette.io/ Zerolog: https://github.com/rs/zerolog Prometheus: https://github.com/prometheus/client_golang Grafana: https://grafana.com/ Jaeger: https://www.jaegertracing.io/ CORS: https://github.com/rs/cors Circuit breaker: https://martinfowler.com/bliki/CircuitBreaker.html References https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/
  • 32. Thank you! Ralph Ligtenberg - @prutswonder stock images downloaded from Pexels.com https://www.pexels.com/photo/silhouette-of-airplanes-47044/