# Deploying Haskell Services * Michael Snoyman * VP Engineering, FP Complete<br><img alt="FP Complete logo" src="https://tech.fpcomplete.com/images/fp-complete-logo-small.png" style="border:0"> * Amsterdam Haskell meetup * Thursday, September 19, 2019 --- ## Haskell network services * Use lots of Haskell * Mostly network services * Build/deploy/monitor * First question... why Haskell? --- ## Why Haskell (in general)? * Reliable code * Highly productive * Easy to scale to a large team * Avoid large classes of bugs --- ## Why Haskell (network services)? * Green threads * Efficient runtime/servers like Warp * Immutability, purity, and STM * Low memory footprint * Low CPU overhead * Compiled executable --- ## Simplified Haskell deployment * Compile executable locally * Spin up VPS * `scp` executable to VPS * `ssh` in, run `screen`, run executable * Done! --- ## Problems * System libraries, `libc` and `gmp` version mismatch * Associated assets * Unreliable testing story * Downtime during deployment * Non-resilient to machine failure * Non-resilient to cloud provider failure --- ## Solving these problems * Lots of approaches * Not a Haskell-specific problem * At FP Complete: we use general purpose solutions * Docker, Kubernetes, AWS * Let's step through standard deployment * Conserve the novelty budget! --- ## CI * We like Gitlab CI * Keep the configuration in the repo * Build with a Docker image too * `stack.yaml` guarantees identical build plan * Just last week: rebuilt a web app with a minor tweak still using GHC 7.8 * Artifact: a Docker image for runtime --- ## Testing * Types are great, but you still need to test! * Especially integration/system tests * Test the exact Docker image you're about to deploy to production --- ## Staging * Separate CI and production Kubernetes cluster * Gitlab review apps * Able to deploy branches to staging cluster and see difference * Great for interacting with product owners and customers --- ## Production * Use Kubernetes `deployment` system * Tests each pod * Zero downtime for deployment * Concern: share mutable resources like databases * Moral of the story: mutability always sucks --- ## High availability * Multi-node * Multi-AZ * Load balancer * Auto-scaling group --- ## Configuration * YAML config files (`Data.Yaml.Config`) * Allows environment variable overrides * Secret credentials (e.g. database passwords) use Kube secrets * Currently moving over to Vault * Can run different configurations in staging and prod --- ## Logging * Apps dump to `stdout`/`stderr` * We use `rio` and its logging capabilities * Sometimes use structured logging (with or without `rio`) * Control log level with environment variables * Use standard log aggregation tools --- ## Monitoring * Prometheus * Monitor standard node and cluster level stats by default * Memory, CPU, etc * Monitor ingress and egress (network traffic, status codes) * Some apps: add custom monitoring info as desired --- ## Summary * Very little is Haskell specific * Use common DevOps tools, providers, services * Easy to integrate with existing infrastructure * Haskell + DevOps = reliable services --- ## Questions * Thanks everyone!