Real-World Lessons from DevOps: Dockerizing Applications

DevOps

YOUR COSMETIC CARE STARTS HERE

Find the Best Cosmetic Hospitals

Trusted • Curated • Easy

Looking for the right place for a cosmetic procedure? Explore top cosmetic hospitals in one place and choose with confidence.

“Small steps lead to big changes — today is a perfect day to begin.”

Explore Cosmetic Hospitals Compare hospitals, services & options quickly.

✓ Shortlist providers • ✓ Review options • ✓ Take the next step with confidence

This article is based on a case study originally published on containerjournal.com, written by the site reliability team at Instana.

Background: Why Dockerize at All?

One advantage of working for an application management vendor is broad visibility into how development and operations teams architect, build, and deploy software. After absorbing those patterns across many customers, the site reliability team at Instana decided to share their own experience dockerizing the one remaining application in their portfolio that was still running outside of Docker.

Instana operated two distinct delivery models: a SaaS platform and a self-hosted, on-premises version of its back-end management servers. The SaaS side was already containerized; the on-premises version was packaged as RPM and DEB binaries stitched together by a Chef cookbook that had grown organically to cover every edge case discovered over time. The goal was to close that gap and give on-premises customers the same quality, cadence, and ease of operation enjoyed by SaaS customers.

Should You Dockerize? Three Questions to Answer First

Before committing to a containerization effort, the team framed the decision around three specific questions:

  1. Should you re-architect your application to use containers? — Containers are not the right answer for every workload. Evaluate whether your application’s operational pain points — inconsistent environments, slow releases, complex dependency management — are problems containers actually solve.
  2. Is Docker the right container technology? — Docker has broad enterprise adoption, and the Open Container Initiative (OCI) standard means images built today remain compatible with emerging runtimes such as CRI-O. That longevity matters when you are making a multi-year infrastructure commitment.
  3. Is now the right time? — Timing a migration requires honest assessment of team bandwidth, release schedule risk, and customer impact. Instana’s trigger was that the lag between SaaS and on-premises releases was actively growing, customer interviews confirmed frustration, and the SaaS artifacts were already containerized — meaning the raw material for the migration already existed.

The Architecture Before Dockerization

The legacy delivery pipeline packaged SaaS binaries into RPM/DEB packages to support multiple Linux distributions. A Chef cookbook wired the components together and handled configuration. Over time, the cookbook accumulated logic to handle:

  • Multiple Linux distribution variants
  • Multi-host deployment topologies (beyond the original single-host model)
  • Multiple cloud environments: AWS, Google Cloud Platform, Microsoft Azure, and private data centers

This complexity created unpredictable release cycles, slowed QA qualification, and meant on-premises customers always lagged behind SaaS customers in getting new capabilities.

Choosing and Implementing Docker

Because the SaaS platform already used Docker images (orchestrated by Nomad and Kubernetes), the core application containers were ready. The main work involved creating containers for third-party infrastructure components — including ClickHouse, Cassandra, and other databases — and integrating them into the release pipeline.

The team’s key architectural insight: creating a database container is not the hard part — managing its configuration in a repeatable, trackable way is.

Their solution was to use a host-mounted volume (mount point) for all configuration files. This approach:

  • Keeps configuration changes outside the container, on the host file system
  • Makes every change auditable and version-controllable
  • Allows debug bundles to be collected from the host without exec-ing into a running container
  • Simplifies the docker run directive because the container itself does not encode environment-specific state

Originally adopted out of necessity for database containers, this mount-point pattern turned out to be repeatable across all containers in the stack, creating an unexpected but valuable layer of standardization.

Lessons Learned: Practical Gotchas When Dockerizing

Despite a largely smooth migration, three specific issues surfaced that are worth knowing before you start your own containerization project.

1. ulimits on CentOS Are Lower Than You Expect

During the first CentOS rollout, ClickHouse failed to write to disk as expected. The initial assumption was a database misconfiguration, but the root cause was the system’s default ulimits — specifically the open-file-descriptor limit, which is set surprisingly low in some CentOS configurations.

The team considered modifying the ulimit on the host but recognized that each customer environment could configure ulimits differently, making that approach fragile. The better solution: use Docker’s --ulimit flag when launching the container.

docker run --ulimit nofile=65536:65536 my-clickhouse-image

The --ulimit flag sits at the top of Docker’s override hierarchy, so it reliably enforces the required limit regardless of what the host OS or customer configuration specifies.

2. Eliminate Docker Network Overhead with Host Networking

Network overhead introduced by Docker’s default bridge networking was a legitimate concern, especially for latency-sensitive inter-component communication. Because the deployment model is single-host (all components on one machine), the team used Docker’s host network mode:

docker run --network host my-service-image

This removes the virtual network interface layer entirely, giving containers direct access to the host network stack and eliminating potential throughput or latency bottlenecks from the Docker networking layer. Note that this trade-off is appropriate for a single-host model; multi-host or multi-tenant deployments require a different approach.

3. Bind Systemd Services to docker.service

Once customers saw the reliability of the new platform, their automated maintenance tools began issuing system updates — reboots, patch cycles — without Docker-aware sequencing. Docker’s own restart policy (--restart always or --restart unless-stopped) is not sufficient to guarantee that containers start in the correct order after a host reboot or a forced service restart triggered by an external automation tool.

The fix was to define explicit systemd unit files for each container service and bind them to docker.service using After= and Requires= directives. This ensures that no application container attempts to start before the Docker daemon is fully up, and that startup ordering between dependent services is enforced by the init system rather than left to timing luck.

[Unit]
Description=My Application Container
After=docker.service
Requires=docker.service

[Service]
Restart=always
ExecStart=/usr/bin/docker run --name my-app my-app-image
ExecStop=/usr/bin/docker stop my-app

[Install]
WantedBy=multi-user.targetCode language: JavaScript (javascript)

Results After Six Months in Production

According to the team, the outcomes exceeded their original goals:

  • SaaS and self-hosted releases now ship simultaneously — a goal that was not even stated at the start of the project.
  • QA qualification cycles are shorter, particularly for operating system compatibility testing, because a validated container image behaves consistently across distributions.
  • Release cycles are more predictable — the variability introduced by the Chef cookbook’s edge-case logic is gone.
  • Support complexity dropped significantly — because the team no longer needs to reason about version skew between SaaS and on-premises deployments.
  • All customers receive new capabilities at release time, not weeks or months later.

What Comes Next: Kubernetes for Self-Hosted

With Docker packaging standardized across the product, the team’s stated next step is scalability: extending the self-hosted platform to support Kubernetes-based deployment, bringing it into full alignment with the SaaS architecture already running on Nomad and Kubernetes.

Key Takeaways

  • If your SaaS artifacts are already containers, you have most of the raw material needed for an on-premises containerization project.
  • Use host-mounted configuration volumes to keep container images environment-agnostic and configuration changes auditable.
  • Do not rely on Docker’s restart policy alone for production startup ordering — use systemd unit bindings.
  • Check ulimits early, especially on CentOS and RHEL-family hosts; use Docker’s --ulimit flag to enforce the values your workload actually needs.
  • For single-host deployments, --network host eliminates an entire category of networking overhead concerns.
  • Even organizations without containerized workloads in production often permit vendor-supplied Dockerized installations — OCI adoption has made Docker a broadly acceptable delivery format.
0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x