Custom Spins¶
Guide for creating custom organization-specific variants of the developer environment.
Overview¶
Custom spins are organization-level variants that:
- Extend the base image
- Add organization-specific tools
- Apply custom configurations
- Serve as starting points for programs
Creating a Custom Spin¶
1. Directory Structure¶
Create a new spin:
Structure:
my-spin/
├── Vagrantfile # VM configuration
├── ansible/
│ ├── group_vars/
│ │ └── all.yml # Spin-specific variables
│ ├── playbooks/
│ │ └── spin-setup.yml # Setup playbook
│ └── roles/ # Custom roles (optional)
└── README.md # Documentation
2. Vagrantfile¶
Create Vagrantfile:
Vagrant.configure("2") do |config|
# Use base image
config.vm.box = "base-rocky9"
# VM settings
config.vm.hostname = "my-spin"
# Resources
config.vm.provider "virtualbox" do |vb|
vb.name = "my-spin"
vb.memory = "4096"
vb.cpus = 2
end
# Ansible provisioning
config.vm.provision "ansible" do |ansible|
ansible.playbook = "ansible/playbooks/spin-setup.yml"
ansible.groups = {
"spin" => ["default"]
}
end
end
3. Configuration¶
ansible/group_vars/all.yml:
---
# Spin Information
spin_name: "my-spin"
spin_description: "Custom spin for specific use case"
# Inherit from organization apps
apps:
docker:
enabled: true
version: "24.0"
python:
enabled: true
version: "3.11"
packages:
- requests
- flask
nodejs:
enabled: true
version: "18"
# Spin-specific configuration
custom_tools:
- name: "internal-cli"
version: "1.0.0"
repository: "https://github.com/org/internal-cli"
# Organization settings
organization:
name: "MyOrg"
domain: "example.com"
proxy: "http://proxy.example.com:8080"
4. Setup Playbook¶
ansible/playbooks/spin-setup.yml:
---
- name: Setup Custom Spin
hosts: all
become: true
pre_tasks:
- name: Display spin information
ansible.builtin.debug:
msg: "Setting up {{ spin_name }}"
roles:
# Include organization roles
- role: app-docker
when: apps.docker.enabled | default(false)
- role: app-python
when: apps.python.enabled | default(false)
- role: app-nodejs
when: apps.nodejs.enabled | default(false)
tasks:
- name: Install custom tools
ansible.builtin.git:
repo: "{{ item.repository }}"
dest: "/opt/{{ item.name }}"
version: "{{ item.version }}"
loop: "{{ custom_tools }}"
- name: Configure organization proxy
ansible.builtin.template:
src: proxy.conf.j2
dest: /etc/profile.d/proxy.sh
when: organization.proxy is defined
- name: Create spin marker
ansible.builtin.copy:
content: |
Spin: {{ spin_name }}
Version: {{ spin_version | default('1.0.0') }}
Built: {{ ansible_date_time.iso8601 }}
dest: /etc/spin-info
5. Building the Spin¶
# Build
cd packages/organization/spins/my-spin
vagrant up
# Package (optional)
vagrant package --output ../../artifacts/my-spin.box
# Add to Vagrant
vagrant box add my-spin ../../artifacts/my-spin.box
Use Cases¶
Development Spin¶
Pre-configured for web development:
apps:
docker: { enabled: true }
python: { enabled: true, version: "3.11" }
nodejs: { enabled: true, version: "18" }
postgresql: { enabled: true, version: "15" }
redis: { enabled: true }
Data Science Spin¶
Optimized for data science work:
apps:
python:
enabled: true
version: "3.11"
packages:
- numpy
- pandas
- scikit-learn
- jupyter
- matplotlib
r:
enabled: true
version: "4.3"
packages:
- tidyverse
- ggplot2
DevOps Spin¶
Tooling for infrastructure work:
apps:
docker: { enabled: true }
kubernetes: { enabled: true }
terraform: { enabled: true }
ansible: { enabled: true }
helm: { enabled: true }
k9s: { enabled: true }
Best Practices¶
Naming Conventions¶
- Use descriptive names:
data-science-spin,devops-spin - Follow semantic versioning
- Document purpose clearly
Configuration Management¶
- Keep spin-specific settings minimal
- Document deviations from standard organization setup
- Use variables for flexibility
Testing¶
Create tests for your spin:
mkdir -p tests
cat > tests/verify-spin.yml << 'EOF'
---
- name: Verify Custom Spin
hosts: all
tasks:
- name: Check spin marker
ansible.builtin.stat:
path: /etc/spin-info
register: spin_marker
- name: Verify tools installed
ansible.builtin.command:
cmd: "{{ item }} --version"
loop:
- docker
- python3
- node
EOF
Documentation¶
Create comprehensive README:
# My Custom Spin
## Purpose
Optimized for [specific use case]
## Installed Tools
- Docker 24.0
- Python 3.11
- Node.js 18
- [Custom tool list]
## Configuration
- Organization proxy configured
- Custom repositories added
- Specific settings applied
## Usage
\`\`\`bash
vagrant init my-spin
vagrant up
\`\`\`
## Differences from Standard Spin
- [List key differences]
Maintenance¶
Updating Spins¶
- Update configuration/playbooks
- Test changes thoroughly
- Rebuild and repackage
- Update version number
- Distribute to teams
Version Control¶
Commit spin configurations:
git add packages/organization/spins/my-spin/
git commit -m "feat: add my-spin v1.1.0"
git tag -a my-spin-v1.1.0 -m "My Spin version 1.1.0"
Distribution¶
Share spins with organization:
# Upload to artifact repository
cp artifacts/my-spin.box /shared/vagrant-boxes/
# Or use Vagrant Cloud
vagrant cloud publish org/my-spin 1.1.0 virtualbox artifacts/my-spin.box
Troubleshooting¶
Spin Won't Build¶
- Verify base image exists:
vagrant box list | grep base-rocky9 - Check Ansible syntax:
ansible-playbook --syntax-check playbooks/spin-setup.yml - Review logs:
vagrant up --debug
Configuration Not Applied¶
- Check variable precedence
- Verify playbook execution
- Test with
vagrant provision