Infrastructure as Code

4 min read Updated 2 months ago

Infrastructure as code

Define and manage your entire application infrastructure using YAML configuration files. This allows you to version control your infrastructure, automate deployments, and ensure consistency across environments.

How it works

Infrastructure as code lets you describe your application, services, domains, and secrets in a single YAML file. When you apply this configuration, the platform automatically creates or updates all resources to match your desired state.

Configuration structure

Your infrastructure configuration follows this structure:

apiVersion: v1
kind: Infrastructure
metadata:
  name: your-app-name
  team: your-team-name-or-id
spec:
  application: {...}
  domains: [...]
  secrets: [...]
  volumes: [...]
  services: [...]
  container_services: [...]

Complete example

Here's a comprehensive example showing all available configuration options:

apiVersion: v1
kind: Infrastructure
metadata:
  name: production-app
  team: 1  # Your team ID or name
spec:
  application:
    name: production-app
    type: laravel  # laravel, nodejs, or wordpress
    version: "11.x"
    repository:
      url: https://github.com/yourorg/yourrepo
      owner: yourorg
      name: yourrepo
      branch: main
    runtime:
      php_version: "8.4"
      nodejs_version: "22"
    commands:
      build:
        - composer install --no-dev --optimize-autoloader
        - npm ci
        - npm run build
      init:
        - php artisan migrate --force
        - php artisan config:cache
        - php artisan route:cache
      start: php artisan serve --host=0.0.0.0 --port=8000
    settings:
      health_check_path: /health
      scheduler_enabled: true
      replicas: 3
      memory: 1024Mi
    php:
      extensions:
        - redis
        - imagick
        - gd
        - zip
      settings:
        - memory_limit=512M
        - max_execution_time=120
        - upload_max_filesize=100M
        - post_max_size=100M

  domains:
    - domain: app.example.com
    - domain: www.example.com
    - domain: api.example.com

  secrets:
    - key: APP_KEY
      value: base64:your_generated_key_here
    - key: DB_PASSWORD
      value: your_secure_password
    - key: STRIPE_KEY
      value: sk_live_your_stripe_key
    - key: AWS_ACCESS_KEY_ID
      value: your_aws_key
    - key: AWS_SECRET_ACCESS_KEY
      value: your_aws_secret

  volumes:
    - name: storage
      mount_path: /var/www/html/storage
      volume_size: 20  # Size in GB
    - name: uploads
      mount_path: /var/www/html/public/uploads
      volume_size: 10

  services:
    # Database services
    - name: database
      type: mysql
      version: "8.0"
      memory: 2Gi
      volume_size: 50  # Size in GB
      settings:
        database: production

    - name: postgres
      type: postgresql
      version: "15"
      memory: 2Gi
      volume_size: 50
      settings:
        database: app_production
        extensions:
          - postgis
          - pg_trgm
          - uuid-ossp

    # Cache services
    - name: cache
      type: redis
      version: "7.2"
      memory: 512Mi
      volume_size: 1

    - name: sessions
      type: valkey
      version: "7.2"
      memory: 256Mi
      volume_size: 1

    # Queue services
    - name: queue
      type: rabbitmq
      version: "3.12"
      memory: 1Gi
      volume_size: 5

    # Storage services
    - name: files
      type: minio
      version: latest
      memory: 1Gi
      volume_size: 100

    - name: ftp
      type: sftp
      version: latest
      memory: 256Mi
      volume_size: 50
      settings:
        username: ftpuser
        password: secure_ftp_password

    # Worker services
    - name: default-worker
      type: worker
      memory: 1Gi
      command: php artisan queue:work --queue=default --tries=3

    - name: email-worker
      type: worker
      memory: 512Mi
      command: php artisan queue:work --queue=emails --tries=5

    - name: heavy-worker
      type: worker
      memory: 2Gi
      command: php artisan queue:work --queue=heavy --timeout=3600

  container_services:
    - name: pdf-generator
      type: gotenberg
      version: "8"
      memory: 1Gi
      settings:
        LOG_LEVEL: info
        DEFAULT_WAIT_TIMEOUT: "60"

    - name: browser
      type: chrome-headless
      version: stable
      memory: 2Gi

    - name: analytics
      type: clickhouse
      version: "23.8"
      memory: 4Gi
      volume_size: 100

    - name: search
      type: meilisearch
      version: "1.5"
      memory: 1Gi
      volume_size: 5

Applying your configuration

You can apply your infrastructure configuration using the API. Send a POST request with your YAML content:

curl -X POST https://api.ploi.cloud/api/v1/infrastructure/apply \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/yaml" \
  --data-binary @your-infrastructure.yaml

Dry run mode

Preview what changes would be made without actually applying them:

curl -X POST "https://api.ploi.cloud/api/v1/infrastructure/apply?dry_run=true" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/yaml" \
  --data-binary @your-infrastructure.yaml

Manual deployment

By default, changes are automatically deployed. To apply changes without triggering a deployment:

curl -X POST "https://api.ploi.cloud/api/v1/infrastructure/apply?auto_deploy=false" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/yaml" \
  --data-binary @your-infrastructure.yaml

Response format

The API returns details about what was changed:

{
  "success": true,
  "team": "Your Team",
  "dry_run": false,
  "changes": [
    "Application 'production-app' created",
    "Domain 'app.example.com' added",
    "Secret 'APP_KEY' created",
    "Service 'database' (mysql) created"
  ],
  "structured_changes": {
    "application": { "action": "created", "name": "production-app" },
    "domains": [{ "action": "created", "domain": "app.example.com" }],
    "secrets": [{ "action": "created", "key": "APP_KEY" }],
    "services": [{ "action": "created", "name": "database", "type": "mysql" }]
  },
  "errors": [],
  "needs_deployment": true,
  "auto_deploy_enabled": true,
  "deployment_id": 456
}

Important notes

  • The application name must be unique within your team
  • Some fields like application type cannot be changed after creation
  • Services and volumes are automatically connected to your application
  • All resources are managed together - updating the configuration will update all resources
  • Removing items from the configuration will not delete them (for safety)

For complete API documentation and additional options, see the API reference.