Most Ansible work is editing YAML, running playbooks, and sharing changes with a team. Git tracks what changed; Visual Studio Code gives you syntax-aware editing and a terminal in the same window. Together they form a workflow that scales beyond exam labs—clone a repo, edit playbooks safely, commit configuration, and run ansible-playbook without leaving the editor.
This guide walks through that workflow on Rocky Linux 10: project layout, git clone, VS Code setup, .gitignore rules for Ansible artifacts, vault password file hygiene, ansible-lint, and a short Ansible Navigator example. It does not replace a full Git branching tutorial, a complete Vault guide, or deep execution environment configuration—those have dedicated pages.
Tested on: Rocky Linux 10.2 (Red Quartz); kernel 6.12.0-211.16.1.el10_2.0.1.x86_64; ansible-core 2.16.16; ansible-lint 26.6.0; ansible-navigator 26.6.0.
~/ansible-project, inventory group lab, and playbooks in playbooks/. Use your own host names and paths if yours differ.
What This Article Covers
| Topic | In scope |
|---|---|
| Recommended project layout | ansible.cfg, inventory/, playbooks/, roles/, requirements.yml |
| Git basics for Ansible repos | clone, status, diff, add, commit |
| VS Code on Rocky Linux | Install, open folder, extensions |
| Safe YAML editing | Spaces, schema hints, FQCN habits |
.gitignore for Ansible |
.retry, .cache/, vault password files |
| Run from integrated terminal | ansible-playbook, --syntax-check |
| Quality checks | ansible-lint from project root |
| Optional Navigator | ansible-navigator run --mode stdout |
Why Use Git and VS Code for Ansible Projects?
Ansible projects are folders of text files. Without version control, you cannot see who changed inventory/hosts, roll back a broken playbook, or onboard a teammate with one git clone.
VS Code complements Git on the control node:
- Ansible extension (Red Hat) — playbook intelligence via ansible-language-server: module documentation, validation, and run helpers.
- YAML extension — indentation and schema-aware editing for playbooks and vars files; pair with YAML syntax habits.
- Integrated terminal — same working directory as the open folder, so ansible.cfg resolves correctly when you run playbooks.
- Source Control view — stage and commit without memorizing every Git flag (still learn
git statusandgit diff).
Ansible Navigator is separate: it is built to run and review Ansible content, including execution-environment workflows, not to replace the editor. Use Navigator when you want its TUI or stdout wrapper around ansible-playbook—details in run Ansible playbooks with navigator.
Prerequisites on Rocky Linux
On the control node you need:
| Requirement | Notes |
|---|---|
| Rocky Linux 10 (or RHEL-family) with GUI or VS Code on your laptop + SSH | Desktop: install code on the VM. Laptop: Remote - SSH to the control node. |
| Ansible installed | ansible-core 2.16+ tested |
| Git | dnf install git -y |
ansible user with project directory |
~/ansible-project in this course |
| Optional | ansible-lint, ansible-navigator via pip or dnf |
Confirm Ansible from any directory first:
ansible --versionSample output:
ansible [core 2.16.16]
config file = /etc/ansible/ansible.cfg
...After you cd ~/ansible-project, the config file line should show your project ansible.cfg instead of /etc/ansible/ansible.cfg.
Recommended Ansible Project Layout
Open the repo root in VS Code—the directory that contains ansible.cfg. A practical tree matches the project directory structure guide:
~/ansible-project/
├── ansible.cfg
├── ansible-navigator.yml # optional
├── inventory/
│ ├── hosts
│ ├── group_vars/
│ └── host_vars/
├── playbooks/
├── roles/
├── requirements.yml
├── README.md
└── .gitignoreCreate missing folders once:
mkdir -p ~/ansible-project/{inventory/group_vars,inventory/host_vars,playbooks,roles}List the tree:
find ~/ansible-project -print | sortSample output:
/home/ansible/ansible-project
/home/ansible/ansible-project/ansible.cfg
/home/ansible/ansible-project/inventory
/home/ansible/ansible-project/inventory/group_vars
/home/ansible/ansible-project/inventory/host_vars
/home/ansible/ansible-project/inventory/hosts
/home/ansible/ansible-project/playbooks
/home/ansible/ansible-project/roles
/home/ansible/ansible-project/requirements.ymlGit does not track empty directories. If you want to keep empty folders such as roles/, inventory/group_vars/, or inventory/host_vars/ in the repo before adding files, create a placeholder such as .gitkeep:
touch roles/.gitkeep inventory/group_vars/.gitkeep inventory/host_vars/.gitkeepStage the placeholders with your first commit:
git add roles/.gitkeep inventory/group_vars/.gitkeep inventory/host_vars/.gitkeepClone an Ansible Project Repository
If the project already lives in Git (GitHub, GitLab, internal Gitea), clone it to the control node:
cd ~
git clone https://example.com/team/ansible-project.git
cd ansible-projectReplace the URL with your remote. For a local bare repo on the same host (lab simulation):
git clone /path/to/ansible-project.git ~/ansible-projectList cloned files:
lsSample output:
ansible.cfg inventory playbooks requirements.ymlInstall collections after clone so playbooks match the repo:
ansible-galaxy collection install -r requirements.ymlOpen the Project in VS Code
Install VS Code on Rocky Linux (desktop session)
From the official VS Code Linux documentation, import the Microsoft signing key:
sudo rpm --import https://packages.microsoft.com/keys/microsoft.ascCreate /etc/yum.repos.d/vscode.repo:
sudo tee /etc/yum.repos.d/vscode.repo << 'EOF'
[code]
name=Visual Studio Code
baseurl=https://packages.microsoft.com/yumrepos/vscode
enabled=1
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
EOFInstall:
sudo dnf install code -yOn Ubuntu laptops, use install VS Code on Ubuntu instead.
Open the folder
Log in as the ansible user, then:
cd ~/ansible-project
code .In VS Code, confirm the Explorer shows ansible.cfg, inventory/, and playbooks/ at the top level. If you only opened a single file, File → Open Folder and choose the repo root—otherwise the integrated terminal may start in the wrong directory and Ansible will not load your project config.
Install Useful VS Code Extensions
Open the Extensions view (Ctrl+Shift+X) and install:
| Extension | ID | Purpose |
|---|---|---|
| Ansible | redhat.ansible |
Language support via ansible-language-server, module docs, playbook run integration |
| YAML | redhat.vscode-yaml |
Indentation, document structure, optional schema validation |
| GitLens (optional) | eamodio.gitlens |
Blame and history inline—helpful on shared playbooks |
After install, reload the window if prompted. Point the Ansible extension at your project when it asks for ansible.cfg, or set ansible.python.interpreter and validation paths in workspace settings if binaries are non-standard.
You do not need deep language-server tuning for daily EX294 work—defaults plus a correct project root are enough.
You can ignore local .vscode/settings.json in .gitignore (per-user paths and interpreter choices), but optionally commit .vscode/extensions.json so teammates get extension recommendations when they open the repo:
{
"recommendations": [
"redhat.ansible",
"redhat.vscode-yaml"
]
}VS Code prompts to install recommended extensions from that file—handy for onboarding without dictating personal editor settings.
Edit YAML Playbooks Safely in VS Code
Ansible playbooks are YAML. Common editor mistakes become runtime failures:
- Use spaces, not tabs — YAML treats tabs as syntax errors.
- Indent consistently — two spaces per level is the usual convention.
- Prefer FQCN —
ansible.builtin.debuginstead of baredebug(see modules and ansible-doc). - Save before run — the terminal executes the file on disk, not unsaved buffer content.
Create playbooks/hello-vscode.yml:
---
- name: VS Code workflow demo
hosts: lab
gather_facts: false
tasks:
- name: Greet from playbook edited in VS Code
ansible.builtin.debug:
msg: "Hello from ansible-project"Validate syntax from the terminal before your first real run:
ansible-playbook playbooks/hello-vscode.yml --syntax-checkSample output:
playbook: playbooks/hello-vscode.ymlUse the Integrated Terminal
Open Terminal → New Terminal (Ctrl+``). The prompt should show your project path, for example ~/ansible-project`.
If the path is wrong, click the + dropdown → Select Default Profile, then open a new terminal, or run:
cd ~/ansible-projectEvery ansible, ansible-playbook, ansible-lint, and ansible-navigator command in this guide assumes that working directory. ansible.cfg is discovered from the current directory—not from whichever file tab is active in the editor.
Run Basic Ansible Commands from VS Code
Ping inventory hosts:
ansible lab -m ansible.builtin.pingRun the demo playbook:
ansible-playbook playbooks/hello-vscode.ymlSample output:
PLAY [VS Code workflow demo] ***************************************************
TASK [Greet from playbook edited in VS Code] ***********************************
ok: [rocky2] => {
"msg": "Hello from ansible-project"
}
PLAY RECAP *********************************************************************
rocky2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Use the same flags as on a plain SSH session: --check, --limit rocky2, -v for verbosity. The playbook runner guide covers check mode, diff, and tags.
Optional: Ctrl+Shift+P → Ansible: Run Ansible Playbook and pick a file. The integrated terminal method is the one to know for exams and scripts.
Track Changes with Git
Initialize a new repo when you built the tree locally and there is no remote yet:
cd ~/ansible-project
git init -b mainCheck what Git sees:
git statusSample output (before first commit):
On branch main
Untracked files:
(use "git add <file>..." to include in what will be committed)
ansible.cfg
inventory/
playbooks/
requirements.ymlAdd, Commit and View Changes
Stage project files:
git add ansible.cfg inventory/hosts playbooks/ requirements.yml .gitignore
git commit -m "Initial ansible project layout"Add a second playbook and inspect the diff:
git add playbooks/site.yml
git diff --cached --statSample output:
playbooks/site.yml | 2 ++
1 file changed, 2 insertions(+)Commit:
git commit -m "Add site.yml wrapper playbook"View history:
git log --oneline -3Sample output:
997ad4d Add site.yml wrapper playbook
fd53780 Initial ansible project layoutUse VS Code's Source Control panel for the same operations when you prefer clicks—but run git status and git diff from the terminal regularly so you are not lost without the UI.
Create a Useful .gitignore for Ansible
Add .gitignore at the repo root before the first push. Suggested starter (aligned with ansible-lint caching guidance):
# Ansible generated files
*.retry
.cache/
# Python/cache
__pycache__/
*.pyc
# Vault password files and local secrets
.vault-pass
vault.pass
*.vault-password
.env
# Local editor/OS files
.vscode/settings.json
.DS_Storeansible-lint documentation recommends ignoring .cache/ because the directory is recreated automatically.
Adding a path to .gitignore does not untrack a file Git already committed. If a secret was pushed by mistake, remove it from the index with git rm --cached <file>, add the path to .gitignore, commit that change, and rotate the secret—it may still exist in Git history.
Verify ignored paths:
grep -E 'retry|cache|vault' .gitignoreSample output:
*.retry
.cache/
.vault-pass
vault.pass
*.vault-passwordExclude Vault Password Files and Secrets
Ansible Vault encrypts sensitive content, but the password that decrypts it must never land in Git. Official Vault documentation stresses supplying vault secrets carefully—password files need restrictive permissions and must not be added to source control.
Create an empty password file with mode 600 (no password on the command line—echo would leave the secret in shell history):
install -m 600 /dev/null .vault-passType the password in an editor:
vi .vault-passOr prompt without echoing to the terminal (still avoid logging the password in shell history on shared systems):
read -s -p "Vault password: " VAULT_PASSPress Enter, then write the file and clear the variable:
printf '\n'
printf '%s\n' "$VAULT_PASS" > .vault-pass
chmod 600 .vault-pass
unset VAULT_PASSCheck Git status:
git status --shortSample output:
An empty status means .vault-pass is ignored—good. If Git lists .vault-pass as untracked, add the filename to .gitignore immediately and never commit it.
Point Ansible at the file for ad hoc runs (do not commit this path into shared ansible.cfg if it exposes a teammate-specific location—use per-user config or environment variables instead):
ansible-playbook playbooks/site.yml --vault-password-file .vault-passStore Encrypted Vault Files Safely
Encrypted variable files—$ANSIBLE_VAULT;1.1;AES256 headers—are usually safe to commit because they are ciphertext. Reviewers still see that secrets exist, so use descriptive names (vault_db_password) and the vault_ prefix pattern from the Vault with group_vars guide.
| Item | Commit? |
|---|---|
group_vars/lab/vault.yml (encrypted) |
Usually yes |
Plain-text group_vars/lab/secrets.yml |
No—encrypt first |
.vault-pass / vault.pass |
Never |
Full encrypt, edit, and rekey workflows live in the Ansible Vault tutorial—this page only covers Git hygiene around vault passwords.
Run ansible-lint from the Project Directory
ansible-lint catches risky YAML, deprecated syntax, and policy violations before CI or peers see your commit. From the project root:
ansible-lint playbooks/hello-vscode.ymlSample output:
Passed: 0 failure(s), 0 warning(s) in 1 files processed of 1 encountered. Last profile that met the validation criteria was 'production'.Lint the whole playbooks tree before a commit when you touch multiple files:
ansible-lint playbooks/Enable the Ansible extension's lint integration in settings if you want inline squiggles—CLI lint from the terminal matches what many pipelines run.
Use Ansible Navigator for Project Runs
Ansible Navigator wraps playbook execution with a TUI or plain stdout mode and optional execution environments. It does not replace VS Code for editing; use it when you want Navigator's run UI or EE workflow from the same project directory.
Stdout mode (script- and SSH-friendly):
ansible-navigator run playbooks/hello-vscode.yml --mode stdout --ee falseSample output:
PLAY [VS Code workflow demo] ***************************************************
TASK [Greet from playbook edited in VS Code] ***********************************
ok: [localhost] => {
"msg": "Hello from ansible-project"
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0On small lab VMs without container tooling, --ee false skips execution-environment images and uses local ansible-core—same idea as execution-environment.enabled: false in ansible-navigator.yml. Interactive TUI mode needs a real terminal: ansible-navigator run playbooks/hello-vscode.yml.
Common Examples
Clone a project and open it in VS Code
cd ~
git clone https://example.com/team/ansible-project.git
cd ansible-project
code .Create a playbook and commit it
cd ~/ansible-project
cat > playbooks/hello-vscode.yml << 'EOF'
---
- name: VS Code workflow demo
hosts: lab
gather_facts: false
tasks:
- name: Greet from playbook edited in VS Code
ansible.builtin.debug:
msg: "Hello from ansible-project"
EOF
git add playbooks/hello-vscode.yml
git commit -m "Add hello-vscode demo playbook"Add ansible.cfg, inventory and playbooks to Git
git add ansible.cfg inventory/ playbooks/ requirements.yml .gitignore README.md
git status --short
git commit -m "Track Ansible project configuration and playbooks"Ignore retry files, cache and vault password files
Ensure .gitignore contains *.retry, .cache/, and vault password patterns (see section above), then create empty test artifacts:
touch playbooks/site.retry
install -m 600 /dev/null .vault-passCheck Git status:
git status --shortSample output:
Only ignored artifacts should disappear from the untracked list.
Run ansible-playbook from the VS Code terminal
cd ~/ansible-project
ansible-playbook playbooks/hello-vscode.yml --syntax-check
ansible-playbook playbooks/hello-vscode.ymlRun ansible-navigator from the project directory
cd ~/ansible-project
ansible-navigator run playbooks/hello-vscode.yml --mode stdout --ee falseFiles to Commit vs Ignore
| File / directory | Commit? | Reason |
|---|---|---|
ansible.cfg |
Yes | Project configuration |
inventory/ |
Usually yes | Lab or team inventory |
playbooks/ |
Yes | Main automation code |
roles/ (custom) |
Yes | Your authored role logic |
requirements.yml |
Yes | Reproducible roles and collections |
| Vault-encrypted vars | Usually yes | Safe when encrypted and reviewed |
| Vault password file | No | Secret used to decrypt Vault |
*.retry |
No | Generated run artifact |
.cache/ |
No | Tool cache; ansible-lint recreates it |
__pycache__/ |
No | Generated Python cache |
Common Mistakes
| Mistake | Fix |
|---|---|
| Committing vault password files | Add .vault-pass, vault.pass, and *.vault-password to .gitignore immediately |
Adding a secret to .gitignore after it was committed |
Use git rm --cached <file> and rotate the secret |
| Ignoring encrypted Vault vars by mistake | Commit encrypted vars when the project needs them; exclude only password files |
| Running commands outside the project directory | Open the repo root in VS Code; cd ~/ansible-project in the integrated terminal |
Forgetting to commit requirements.yml |
Commit it so ansible-galaxy collection install -r requirements.yml reproduces the environment |
| Editing YAML with tabs | Use spaces; enable YAML extension formatting |
Committing .retry or .cache/ |
Add *.retry and .cache/ to .gitignore |
| Installing roles manually without recording them | Add requirements.yml for collections and roles |
| Depending only on the VS Code UI | Learn git status, git diff, git add, git commit in the terminal |
Best Practices
- One repo root —
ansible.cfg, inventory, and playbooks stay together; matches EX294 and real team layouts. - Commit early, commit small — playbook + inventory changes in readable commits beat one giant push.
- Lint before push —
ansible-lint playbooks/catches FQCN and formatting issues cheaply. - Never commit secrets — encrypt with Vault; keep password files local and chmod
600. - Pin collections —
requirements.ymlwith versions avoids "works on my laptop" drift. - Editor + CLI — use VS Code for editing and Git graph, terminal for Ansible runs you will automate later.
- Navigator when helpful — use stdout mode on SSH; use TUI when you want task-by-task browsing (navigator guide).
Summary
A solid Ansible workflow on Rocky Linux is: clone (or init) a Git repo with a standard project tree, open that folder in VS Code, install the Ansible and YAML extensions, edit playbooks with spaces and FQCN modules, run ansible-playbook and ansible-lint from the integrated terminal at the repo root, commit ansible.cfg, inventory, playbooks, and requirements.yml, and keep vault password files, .retry files, and .cache/ out of Git. Add Ansible Navigator when you want its run UI or execution-environment path—after the basics feel natural.
References
- Visual Studio Code on Linux — official install paths
- Ansible VS Code extension — ansible-language-server integration
- Ansible Vault — managing passwords — password file safety
- ansible-lint configuring cache —
.cache/in.gitignore - Ansible Navigator — run and review playbook execution

