Scripting & CI
Using mkunit in automation, CI/CD pipelines, and dotfiles.
Non-Interactive Mode
For scripts and CI, use --no-interactive to prevent prompts:
mkunit service myapp \
--exec "./server" \
--restart on-failure \
--install \
--no-interactive
mkunit also auto-detects non-interactive environments (no TTY, CI variable set).
Dry Run for Validation
Use --dry-run to generate unit files without writing them:
# Preview the unit file
mkunit service myapp --exec "./server" --dry-run
# Write to a specific location for review
mkunit service myapp --exec "./server" --dry-run > myapp.service
# Validate the generated file
mkunit validate ./myapp.service --strict
Exit Codes
mkunit uses standard exit codes for scripting:
| Code | Meaning |
|---|---|
0 | Success |
1 | General error |
2 | Invalid arguments or missing required options |
3 | Unit not found |
4 | Validation failed |
5 | Permission denied |
Example: Deployment Script
#!/bin/bash
set -e
APP_NAME="myapp"
APP_DIR="/opt/myapp"
APP_USER="myapp"
# Create or update the service
sudo mkunit service "$APP_NAME" \
--exec "$APP_DIR/bin/server" \
--workdir "$APP_DIR" \
--user "$APP_USER" \
--env-file "$APP_DIR/.env" \
--restart on-failure \
--hardening \
--system \
--install \
--no-interactive
# Reload and restart
sudo systemctl daemon-reload
sudo systemctl restart "$APP_NAME"
# Verify it's running
if mkunit status "$APP_NAME" --system -q; then
echo "✓ $APP_NAME is running"
else
echo "✗ $APP_NAME failed to start"
mkunit logs "$APP_NAME" --system -n 50
exit 1
fi
Example: GitHub Actions
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install mkunit
run: cargo install mkunit
- name: Generate unit file
run: |
mkunit service myapp \
--exec "./server" \
--restart on-failure \
--hardening \
--dry-run > myapp.service
- name: Validate unit file
run: mkunit validate ./myapp.service --strict
- name: Deploy to server
run: |
scp myapp.service server:/tmp/
ssh server 'sudo mv /tmp/myapp.service /etc/systemd/system/ && \
sudo systemctl daemon-reload && \
sudo systemctl restart myapp'
Example: Ansible Integration
- name: Create systemd service with mkunit
command: >
mkunit service {{ app_name }}
--exec "{{ app_exec }}"
--workdir "{{ app_dir }}"
--user "{{ app_user }}"
--restart on-failure
--hardening
--system
--install
--no-interactive
become: yes
notify: restart app
- name: Ensure service is enabled
systemd:
name: "{{ app_name }}"
enabled: yes
state: started
become: yes
Example: Dotfiles Bootstrap
Set up user services when bootstrapping a new machine:
#!/bin/bash
# ~/.dotfiles/setup-services.sh
# SSH agent service
mkunit service ssh-agent \
--exec "/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK" \
--env "SSH_AUTH_SOCK=$HOME/.ssh/agent.sock" \
--install --enable \
--no-interactive
# Syncthing
mkunit service syncthing \
--exec "/usr/bin/syncthing serve --no-browser --no-restart" \
--restart on-failure \
--install --enable \
--no-interactive
# Start services
systemctl --user start ssh-agent syncthing
echo "Services installed and started"
JSON Output
Use --json for machine-readable output:
# List units as JSON
mkunit list --json | jq '.[] | select(.state == "active")'
# Get status as JSON
mkunit status myapp --json | jq '.pid'
# Validate with JSON output
mkunit validate myapp --json | jq '.warnings'
Idempotent Operations
mkunit commands are idempotent - running them multiple times has the same effect:
# Safe to run multiple times - just overwrites the unit file
mkunit service myapp --exec "./server" --install --no-interactive
# Remove is also safe if unit doesn't exist
mkunit remove myapp --force 2>/dev/null || true
Error Handling
#!/bin/bash
set -e
# Create service with error handling
if ! mkunit service myapp --exec "./server" --install --no-interactive 2>&1; then
echo "Failed to create service"
exit 1
fi
# Check if service is healthy after starting
systemctl --user start myapp
sleep 2
if ! mkunit status myapp -q; then
echo "Service failed to start. Logs:"
mkunit logs myapp -n 20
exit 1
fi
See Also
- Interactive Mode - How prompts work
- validate command - Validate unit files
- status command - Check unit status