Week 3 | Lesson 12

Production

Deployment
Configuration and Secrets
Observability
Monitoring

Application Lifecycle

Application Lifecycle

Develop → Build → Package → Deploy → Run → Maintain → (back to Develop)
  1. Development
    • Code is written and tested locally, focussing on features, correctness, and unit testing.
    • This phase involves development tools such as IDEs (like IntelliJ), local databases, and mocks.
  2. Build, Test, Integration
    • Code is built (compiled) and tests are run (often automated) to ensure the changes don't break existing behavior
    • This usually happens on an integration environment or CI.
  3. Packaging
    • Application is packaged for deployment.
    • Deployment artifacts are created, such as JAR files or Docker images.
    • Configuration is externalized (env vars, files).
    • The app must be self-contained, portable, and environment-aware.
  4. Deployment
    • Application is pushed to an environment (dev/staging/prod).
    • This may be manual or automated (CI/CD) and may involve some orchestration (e.g., Kubernetes, Docker Compose).

Application Lifecycle

Develop → Build → Package → Deploy → Run → Maintain → (back to Develop)
  1. Runtime & Operation
    • App is now serving users in production.
    • Needs to be observable (logs, metrics, traces).
    • Must handle failures gracefully.
  2. Maintenance & Evolution
    • Bugs are fixed, features are added.
    • Technical debt may be addressed.
    • App may be refactored or deprecated.
The lifecycle is cyclical — each change goes through the same phases.

Development, Build, and Packaging

Development

Kotlin development typically uses Gradle for builds and IntelliJ for local development.

Tools & Practices:

  • Use IntelliJ IDEA with Kotlin support.
  • Build system: Gradle (Kotlin DSL preferred).
  • Unit testing with JUnit 5 or Kotest.
  • Mocking with MockK.
  • Code formatted with ktlint or detekt for linting.

All logic should be testable independently from infrastructure (e.g., DB, HTTP).

Build

The build process compiles source code and runs tests.

Gradle Tasks:

  • ./gradlew build — compiles code and runs tests
  • ./gradlew test — runs unit tests
  • ./gradlew check — includes linting/formatting

Dependencies: Declared in build.gradle.kts


dependencies {
    implementation("io.ktor:ktor-server-core:2.3.0")
    testImplementation("io.kotest:kotest-runner-junit5:5.5.5")
}
		

Builds should be automated in CI (e.g. GitHub Actions).

Packaging

Once built and tested, applications are packaged for deployment.

Common Kotlin packaging targets:

  • .jar: Java archive – run with java -jar
  • .war: Web archive – for servlet containers (less common now)
  • Docker image: preferred for modern deployments

Example: Dockerfile for a Ktor app


FROM openjdk:17-jdk-slim
COPY build/libs/app.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
					

Include configs via ENV or mounted files; secrets should not be baked into the image.

Application Deployment

and Infrastructure

Deployment

Deployment is the process of making an application available for use on a specific environment.

Deployment can include various tasks such as:

  • Building an application package (jar, Docker image, binary).
  • Configuring the target environment.
  • Copying files to the target environment.
  • Configuring the application for the target environment.
  • Running database migrations.
  • Starting or restarting services, setting up logging, monitoring, and alerting.

Environments

Environments are used at distinct stages in the software development lifecycle, each serving a specific purpose.

Each environment has its own configuration, data, and access controls to ensure that changes can be tested safely before going live.

However, it is beneficial to keep the environments as similar to production as possible to avoid issues when deploying to production.

Typical environments include:

  • Local
  • Development / Integration
  • Staging
  • Production

Environments

Environments are used at distinct stages in the software development lifecycle.

Local

  • Usually the developer's machine, where they can run and test the application locally.
  • Often uses containerization tools like Docker to ensure consistency across different developer machines.
  • If running everything locally is not possible, and developers may use dedicated cloud resources for development.


Development

  • A shared environment where developers can deploy their changes for testing and integration.
  • It is often used for collaborative development, allowing multiple developers to work on the same codebase.
  • May include automated tests to ensure that changes do not break existing functionality.


Staging

  • A pre-production environment that closely mirrors the production environment.
  • It is used for final testing and validation of the application before it goes live.
  • Staging environments often use production-like data and configurations to ensure that the application behaves as expected in production.


Production

  • The live environment where the application is accessible to end users.
  • It is critical to ensure that the application is stable, secure, and performs well in this environment.

Infrastructure

Infrastructure refers to the underlying hardware and software components that support the deployment and operation of applications.

Infrastructure can be categorized into different types based on how applications are deployed and run.

  • Physical machines are dedicated hardware servers that run the application directly on the operating system.
  • Virtual machines (VMs) are software emulations of physical machines that run on a hypervisor, allowing multiple VMs to run on a single physical server.
  • Containers are lightweight, portable, and isolated environments that package an application and its dependencies together. They run on a shared operating system kernel, making them more efficient than VMs.

You can also distinguish between self-managed infrastructure and managed services.

  • Self-managed infrastructure requires you to set up and maintain the servers, networking, and storage.
  • Managed services provide a fully managed environment where the provider takes care of the infrastructure.
Different strategies come with a different cost and maintenance overhead.

Platform as Service (PaaS)

PaaS delivers a platform that allows developers to build, run, and manage applications without dealing with infrastructure management.

It includes the operating system, programming language runtime, databases, and web servers.

Key Features:

  • Users manage: applications and data.
  • Provider manages: runtime, OS, infrastructure.
  • Speeds up development and deployment with built-in tools and integrations.

Examples:

Heroku, Google App Engine, Microsoft Azure App Services.

Infrastructure as Service

Infrastructure as a Service (IaaS) is a cloud computing model that provides virtualized computing resources over the internet.

It delivers fundamental IT infrastructure—like virtual machines, storage, networks, and operating systems—on a pay-as-you-go basis.

Key Features:

  • Users manage: OS, applications, runtime, and data.
  • Provider manages: physical hardware, networking, virtualization.
  • Offers flexibility and control over infrastructure.

Examples:

Amazon EC2, Microsoft Azure VMs, Google Compute Engine.

Infrastructure as Code

Infrastructure as Code (IaC) is a practice of managing and provisioning infrastructure using code and automation tools.

It utilizes machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.

Key Features:

  • Infrastructure is version-controlled, testable, and reproducible.
  • Reduces human error and enables automation and consistency.
  • Often used with tools like Terraform, Ansible, or AWS CloudFormation.

Example Use:

Defining and deploying cloud infrastructure (like networks, VMs, and services) with code, rather than clicking through a UI or configuring everything manually on servers.

Deployment Strategies

Blue-Green Deployment

The Blue-Green strategy involves maintaining two identical production environments, referred to as "blue" and "green".

The goal of this strategy is to reduce downtime and risk by running two identical production environments.

  • One environment (blue) is live production,
  • while the other (green) is idle or used for staging.

When a new version of the application is ready, it is deployed to the idle environment (green).

After testing and validation, traffic is switched from the live environment (blue) to the new environment (green).

This allows for quick rollback if issues arise, as the previous version is still running in the blue environment.

It also allows for (near) zero-downtime deployments, as the switch can be done instantly without affecting users.

Canary Releases

Canary releases involve deploying a new version of an application to a small subset of users before rolling it out to the entire user base.

This approach allows you to test new features or changes in production with reduced risk.

  • A small portion of traffic is routed to the new version (the "canary").
  • The rest of the traffic continues to use the stable version.
  • If metrics and error rates are acceptable, the new version is gradually rolled out to more users.
  • If issues are detected, the canary can be rolled back quickly without impacting most users.

Used in: systems with real user traffic analysis, automated monitoring and rollback capabilities.

Rolling Updates

Rolling updates involve gradually updating instances of an application in a production environment.

Instead of stopping and replacing all instances at once, rolling updates upgrade one or a few instances at a time.

  • Minimizes downtime and avoids a full system restart.
  • Each instance is updated and verified before moving to the next.
  • Common in container orchestrators (e.g., Kubernetes), which handle update strategies automatically.
  • Risk is distributed over time; partial rollback may be possible if issues are detected.

Trade-off: More complex monitoring needed to detect errors mid-rollout.

Feature Toggles

Feature toggles (or feature flags) are a technique that allows developers to enable or disable features in an application without deploying new code.

Features can be turned on/off at runtime via configuration, targeting specific users or segments.

  • Enables safe testing of features in production (with limited exposure).
  • Facilitates A/B testing and gradual feature rollouts.
  • Allows quick disabling of problematic features without rollback.
  • Useful for separating deploy from release (deployment happens first, feature is turned on later).

Tools: LaunchDarkly, Unleash, Flipt, or custom flag systems.

"Deploy != Release" — feature toggles help decouple the two.

Deployment Tools

Deployment Tools

Deployment tools help automate the process of delivering applications to various environments.

They allow consistent, repeatable, and automated deployment workflows, reducing human error and enabling rapid iteration.

Common Categories:

  • Scripted Deployments: Bash, Gradle, or Kotlin scripts for custom tasks.
  • Container Orchestration: Kubernetes, Docker Compose.
  • CI/CD Systems: GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Travis CI.
  • Cloud Deployment Tools: AWS CodeDeploy, Google Cloud Deploy, Azure DevOps.

Choosing the right tool depends on your infrastructure, team size, complexity, and need for automation.

CI / CD

CI/CD stands for Continuous Integration and Continuous Delivery or Deployment.

CI (Continuous Integration):

  • Automatically integrates code changes into a shared repository several times a day.
  • Each change triggers a build and a suite of automated tests.
  • Ensures code quality, catches bugs early, and supports team collaboration.

CD (Continuous Delivery/Deployment):

  • Continuous Delivery: Automatically prepares every change for release but requires manual approval to deploy to production.
  • Continuous Deployment: Automatically releases every passing change to production without manual intervention.

CI/CD encourages small, incremental, and reliable updates, leading to faster feedback and lower risk.

CI/CD Pipelines

CI/CD pipelines define a series of steps to build, test, and deploy software in an automated fashion.

Typical stages of a CI/CD pipeline:

  1. Source: Code is pushed to the version control system (e.g., GitHub).
  2. Build: Application is compiled and packaged (e.g., Kotlin app → JAR or Docker image).
  3. Test: Unit, integration, and end-to-end tests are executed.
  4. Deploy: Code is deployed to dev/staging/production environments.
  5. Notify: Developers are informed of failures/success via email, Slack, etc.

Example (GitHub Actions):


jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: ./gradlew build
  

Pipelines allow versioned, reproducible automation — making CI/CD predictable and reliable.

GitHub Workflow Example


# .github/workflows/ci.yml
name: Kotlin CI

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Set up JDK
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'

    - name: Build with Gradle
      run: ./gradlew build
					

Configuration and Secrets

Configuration and Secrets

Managing configuration and secrets is one of the 12-Factor App principles.

The configuration may contain settings that can change between different environments, but also sensitive information and application secrets.

Environment specific configuration:

  • Application port
  • Database connection strings
  • Application specific settings

Application secrets:

  • Database credentials
  • API keys for third-party services
  • JWT secrets for signing tokens
Any sensitive information should not be hard-coded in the application code or shipped with the application.

Managing Configurations

Application configuration should be externalized and environment-specific.

Configurations include settings like database URLs, API endpoints, log levels, and feature toggles.

Best Practices:

  • Do not hardcode configurations in code.
  • Use environment variables, config files, or config servers.
  • Use profiles (e.g., dev, staging, prod) to switch configurations easily.
  • Track configuration versions for auditability and rollback.

Tools: Spring Cloud Config, Consul, Kubernetes ConfigMaps, dotenv libraries.

Managing Secrets

Secrets like passwords, tokens, and API keys must be stored securely and never hardcoded.

Common Secrets:

  • Database passwords
  • Third-party API keys
  • Encryption keys, JWT signing secrets

Secure Practices:

  • Use secret management tools instead of config files.
  • Set secrets through environment variables or secret volumes.
  • Rotate secrets periodically and avoid printing them in logs.

Tools: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Kubernetes Secrets.

If someone gets access to your secrets, they get access to your systems.

Observability

Observability

Observability is the ability to understand what's happening inside your system from the outside.

It enables engineers to ask new questions about their system’s behavior without deploying new code.

Three Pillars of Observability:

  • Logs: Time-stamped, text-based records of events.
  • Metrics: Numerical measurements over time (e.g. CPU usage, request latency).
  • Traces: Records of a request's journey through distributed services.

Observability is critical for debugging, understanding performance bottlenecks, and ensuring reliability.

Common Tools: Grafana, Prometheus, ELK Stack (Elasticsearch, Logstash, Kibana), Jaeger, OpenTelemetry.

Health Checks & Monitoring

Health Checks & Monitoring

Health checks and monitoring help you detect and respond to problems in production.

Health Checks:

  • Liveness check: Is the app still running?
  • Readiness check: Can the app handle traffic?
  • Common in Kubernetes and other orchestrators to manage service lifecycles.

Monitoring:

  • Continuously collects data on application health and performance.
  • Monitors SLIs (e.g. latency, error rate, uptime) and triggers alerts if thresholds are crossed.
  • Helps operators respond quickly to failures or degradation.

Alerting Tools: Prometheus + Alertmanager, Datadog, Sentry, Grafana, PagerDuty.

Release

Release

Deployment vs. Release: Deployment is about making code available; release is about making features available.

Deployment: The process of getting code into an environment (e.g. staging, production).

Release: The moment when a feature becomes visible or usable to users.

  • Feature may be deployed but disabled via feature toggle.
  • Release can be a business decision — decoupled from technical delivery.

This separation allows for safer deployments, better testing in production, and flexibility in rollout strategies.

You can deploy often and release cautiously.

Production-First Mindset

Production-First Mindset

Designing with production in mind leads to more resilient and maintainable systems.

Instead of treating production as an afterthought, a production-first approach builds with real-world usage in mind.

  • Plan for observability, deployment, scalability, and failure handling from the start.
  • Use production-like environments during development.
  • Automate everything: testing, builds, deployments, monitoring.
  • Prioritize user impact, uptime, and recovery strategies.
  • Include operational concerns (logging, alerting, maintenance) early in the development process.
“If it doesn’t work in production, it doesn’t work.”

Thank You

Thank You for Attention

Thank You for attention!

I hope you learned something.

I wish you all the best in your journey!

If you have any questions, feel free to reach out.