Ansible Playbook development for infrastructure automation

Manual server configuration keeps the team hostage: one change outside the process—and environments drift apart. We develop turnkey Ansible playbooks: we describe configuration as code so deployment takes minutes and repeats without errors.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Ansible playbook development: where manual configuration breaks

Manual server configuration starts innocently: a couple of SSH commands, a custom package installation order, a config tweaked somewhere. The knowledge of "how it should be done" lives in the engineer's head and terminal history — not in the repository or documentation.

While there is one server, this works; by the third and fifth environment, drift begins that no one tracks.

Discrepancies between environments show up as "it works on my machine". The test environment is assembled in one order, production in another, and the difference surfaces not during testing but at release time.

Debugging moves into production, where there is no room for error, and the cause of the discrepancy is still unknown.

Configuration drift accumulates unnoticed: a "temporary" limit fix, a workaround route, a manual service restart.

These changes make it into neither version control nor the environment description — a month later, no one can say how the production server differs from the reference one. The next engineer inherits not infrastructure but a set of guesses about it.

Recovery after a failure becomes the most expensive stage. The server is brought up from memory, in a hurry, reproducing steps in the wrong order — and unplanned downtime stretches into hours instead of minutes. Rollback is not guaranteed either: no one saved the previous state as an artifact.

Next, we look at how Ansible playbook development closes this gap: describing state declaratively, applying it repeatably on any environment, and recovering predictably from the repository.

What managed configuration provides instead of manual edits

While changes are made on servers by hand, configuration lives in people's heads and in chat history. Two environments brought up "according to the same instructions" diverge in details: a forgotten limit, an extra open port, a different library version.

Ansible playbook development moves these decisions into the repository — the description becomes a single source of truth against which state is compared, rather than checked from memory.

Environment reproducibility no longer depends on who exactly deployed it. The test environment, acceptance, and production are assembled by one playbook with different parameters, so discrepancies are visible during a run, not at release time.

Environment deployment time drops to tens of minutes: the environment appears in full — with service settings, permissions, and certificates.

A run is idempotent: re-running brings the system to the described state and does not break what is already configured.

This removes an entire class of failures — edits "only on one node", configs that diverged after manual intervention, changes that cannot be reproduced. Rollback is also described: returning to the previous revision of roles is one run instead of log analysis.

Reduced downtime duration comes from the same place: a node is restored not by manual assembly but by running the role on a clean machine. Checks are performed before applying, so some problems are caught in the test environment, not in production.

Infrastructure becomes something that can be described, verified, and repeated, rather than maintained by constant manual attention.

Ways to describe infrastructure: comparison of approaches

Ways to describe infrastructure differ not in syntax but in how the code behaves by the third or fourth edit, when new environments and node types are added to the configuration.

We have gone through each of the four options on real projects — below is a comparison by criteria that matter when handing over to support.

Description approach When it fits Limitations
Declarative state description A homogeneous fleet of machines, need to reproducibly bring up new nodes from scratch Poor fit for branching logic and one-off manual operations
Roles and playbooks by purpose Different node types — web, DBMS, queues; reuse across projects Become overgrown with cross-dependencies if role boundaries and application order are not maintained
Custom modules Non-standard hardware and internal APIs for which no ready-made solutions exist In-house maintenance and dependency compatibility, each module requires tests
Hybrid approach The main part declaratively, non-standard steps as separate playbooks Harder to read, requires formatting discipline and a unified style for the whole team

The main limitation of the approach is its predictability on re-run: a playbook that passes cleanly on an empty machine and breaks on a running one costs more than manual configuration.

That is why before handover we run the configuration twice in the test environment and verify that the second run does not change node state.

If analysis of your task shows that ready-made roles cover 80% of requirements, the hybrid option will be cheaper to maintain than fully custom development.

Implementation stages: from audit to handover of policies

Automation is justified when the same state is reproduced in any environment without manual edits — this is the acceptance criterion.

The stages proceed sequentially: each next one relies on the artifacts of the previous one, so the first run in production becomes a test of the agreed model, not an experiment.

Sequence of stages

  1. Infrastructure audit. We collect the actual state: server inventory, node roles, installed services, and manual edits that are not in repositories. The output is a map of discrepancies between the current configuration and the target one.

  2. Environment scheme. We record the composition of environments and their differences: addresses, accounts, set of services. We describe inventory and host groups so that a new node can be added without changing the logic.

  3. Role design. We break the configuration down into Ansible roles with re-runnable tasks: re-running does not change the already target state. We move variables outside and secrets into a secure vault.

  4. Configuration verification. We run syntax parsing and linting before launch, verify variable values and node availability. Most errors are filtered out here, not in production.

  5. Test run. First, a check-mode run without changes, then a full run on a copy of the production environment. We compare node state before and after and separately verify the re-run.

  6. Handover and team training. We hand over repositories, policies, rollback procedure, and walk through typical changes using a live example.

After that, edits are made through the same roles, and environment state is confirmed by a re-run, not by the administrator's memory.

Output artifacts: roles, schemes, policies

Ansible playbook development ends not with a successful run but with a set of artifacts that remain in your repository and work without us. Below is what exactly we hand over and how each element is used in daily operations.

  • Role structure — a roles/ tree split by service: common roles for basic host configuration, separate ones for application components. Variables are moved into group and host files, so the same description applies to the whole environment rather than being copied per task.
  • Environment scheme — the composition of environments, their inventory, and host groups with a description of which roles apply where and which parameters differ between environments. It is immediately clear where you can experiment and where changes go to production.
  • Access policies — separation of run permissions: who can apply changes in the test environment, who can in production, under which accounts and keys this is done. Secrets are stored in a separate secure vault, not in the repository.
  • Operations documentation — a description of each role, a complete list of variables with purpose and default values, run order, and typical operations: connecting a new host, updating a service version, returning to a previous state.
  • Change policy — how an edit proceeds: separate branch, syntax check and linter, run in the test environment, review, apply. It also records who approves changes and by what criterion a rollback decision is made.
  • Pipeline checks — automated scenarios for syntax and repeatability: running a role twice in a row must not change the configuration, otherwise the task is written incorrectly and will produce an unexpected result in production.
  • Dependency map — which roles depend on others, in what order they are applied, what happens if one step is missing. It helps avoid breaking the environment when adding a new component.

Each item is not a report for the shelf but a working tool: an engineer who has never seen the project before deploys the environment from scratch using the documentation and policy, without asking us questions.

Case study: how we eliminated discrepancies between environments

The customer is a business services integrator with four environments: development, test, pre-production, and production.

The environments were assembled manually according to an internal policy, and configurations matched only partially: discrepancies in service parameters, dependency versions, and limits surfaced in production during release. A typical deployment took 40–60 manual operations and 2–4 hours of an engineer's time.

Recovering a failed node took up to five hours: the procedure was held in the heads of two engineers and in an instruction that lagged behind reality.

An error in one step was carried over to all environments — discrepancies accumulated and were discovered only when they cost downtime.

What we changed

We described the infrastructure as code on Ansible: idempotent roles by service, separate inventory for each environment, variable values consolidated into environment files, secrets moved out of the repository.

A re-run does not change state if the system is already in the target form — this is the basis for discrepancy checking. Before applying, playbooks are run in check mode, and drift is visible before it reaches production.

Outcome

Manual operations per release dropped from 40–60 to zero: the engineer runs the same set of roles in all environments.

Deployment takes 12–15 minutes instead of 2–4 hours, bringing up an environment from scratch takes about half an hour, and node recovery takes 8 minutes versus five hours. Environment consistency is now verified by code, not by an incident.

Deployment repeatability no longer depends on who exactly performs the work: a new engineer is onboarded into the environment in one working day. This is the result of the infrastructure automation case study — the same result regardless of environment and executor.

How roles differ from playbooks in Ansible

A playbook is an entry point: it describes what to apply to a group of hosts and in what order. Inside are a task list or role calls, inventory binding, conditions, and handlers.

It answers the question "what to do with these servers now", but by its nature it transfers poorly to another project: the logic is tied to specific host names and run order.

A role is a reusable module. Tasks, default values, variables, file templates, and handlers live in predictable subdirectories and work in their own namespace, while parameters are set externally.

That is why the same code configures a development environment, test environment, and production without copying code branches.

The practical difference becomes visible on the second or third change of requirements.

If the logic is spread across playbooks, an edit in one place requires a synchronous edit in all the others — this is how configuration drift appears, when environments diverge from each other.

A role is edited once, and the version is pinned in dependencies, so an update rolls out in a controlled way and rolls back by changing the version.

The automation project structure is built around this separation: inventory and variables by host groups, a roles directory, separate playbooks for typical operations — deployment, update, scheduled maintenance.

An engineer opening the repository for the first time finds the needed file by role name rather than reading thousands of lines in sequence.

Supporting someone else's code rests on the same rules: idempotent tasks, documented default values, tags for partial runs, and check-mode verification.

The less hardcoding for a specific host in a playbook, the cheaper it is to change and the faster verification before rollout goes.

Technical concerns: common automation questions

Task analysis almost always comes down to the same questions: what happens when the set of services changes, where passwords are stored, whether it is safe to re-run the playbook, and how to verify changes without breaking anything. Below are working answers that we give before work starts, not after delivery.

Playbooks are designed as maintainable code: roles divide responsibility, variables are moved out by environment, inventory describes host groups. Adding a new service means writing a role and connecting it to the common playbook without rewriting the rest of the logic.

How do you maintain configuration when services and environments grow?

Roles and environment-specific variables allow the same logic to be reused in a test environment and in production, differing only in values.

Config templates are stored in the repository with edit history — you can see who changed a parameter and why, and the change can be rolled back.

Where are passwords and access keys stored?

In an encrypted vault next to the playbooks: decryption happens only at execution time, and the access key is stored outside the code. Secrets are not present in plaintext in the playbooks, task output, or run logs.

Is it safe to re-run the playbook?

Yes. Tasks are described so that a re-run brings the system to the same state and does not touch what is already configured correctly. Before applying, we run in check mode without changes — it shows which hosts and parameters will be affected but changes nothing.

What remains with your engineers after handover?

A description of the playbook structure, instructions for typical operations — add a host, create an environment, rotate a secret — and a walkthrough with the team. After that, your specialists maintain the configuration independently, without our support.

Let's discuss the task: what is needed for a correct start

To estimate the scope of work and implementation plan, we need not a retelling of the task but the actual state of the fleet. The more accurate the infrastructure inputs, the fewer assumptions in the estimate and the more predictable the timeline.

  • List of nodes and their groups: how many servers, what roles they perform, one environment or several sites.
  • Access and connection method, accounts with privilege escalation, presence of a closed environment without external network — the delivery and launch scheme depends on this.
  • Current state: how it is configured now, what manual instructions and scripts exist, what we reuse and what we rewrite.
  • Target environments and differences between them: test, pre-production, production — which parameters differ and where they are stored.
  • Requirements for re-runs: must the playbook pass safely on an already configured node and not overwrite data.
  • Rollout procedure and change windows: can services be restarted, are there time and on-call restrictions.
  • Acceptance criteria: how you will verify that the role works — checks in the test environment, configuration comparison, run report.

Ansible Playbook development rarely happens in one go: first inventory and role skeleton, then trial runs in the test environment, then staged rollout with stage approval at each step.

Describe the task and attach what you already have — we will come back with an estimate and a plan that fixes scope, work order, and control points.