simple_docker

User Guide

Getting Started

Prerequisites

Installation

  1. Clone the repository:
    git clone https://github.com/simple-eiffel/simple_docker.git
  2. Set environment variables:
    # Windows
    set SIMPLE_EIFFEL=D:\prod
    
    # MSYS2/Git Bash
    export SIMPLE_EIFFEL=/d/prod
  3. Add to your ECF file:
    <library name="simple_docker" location="$SIMPLE_EIFFEL/simple_docker/simple_docker.ecf"/>

Dependencies

Ensure these libraries are available:

Beginner API (SIMPLE_DOCKER_QUICK)

New to Docker? The SIMPLE_DOCKER_QUICK class provides one-liner operations that handle all the complexity for you. No Docker knowledge required!

Getting Started

local
    docker: SIMPLE_DOCKER_QUICK
do
    create docker.make

    -- That's it! You're ready to use Docker.
end

Web Servers

-- Serve files from a folder on port 8080
docker.web_server ("C:\my_website", 8080)

-- Or explicitly choose Nginx or Apache
docker.web_server_nginx ("C:\my_website", 8080)
docker.web_server_apache ("C:\my_website", 8081)

Databases

-- PostgreSQL on default port 5432
docker.postgres ("mypassword")

-- PostgreSQL on custom port
docker.postgres_on_port ("mypassword", 5433)

-- MySQL on port 3306
docker.mysql ("mypassword")

-- MariaDB
docker.mariadb ("mypassword")

-- MongoDB (no auth)
docker.mongodb

Caches & Message Queues

-- Redis on port 6379
docker.redis

-- Redis on custom port
docker.redis_on_port (6380)

-- Memcached
docker.memcached

-- RabbitMQ (ports 5672 and 15672 for management UI)
docker.rabbitmq

Running Scripts

-- Run a shell script and get output
print (docker.run_script ("echo hello && date"))

-- Run Python code
print (docker.run_python ("print(2+2)"))

Cleanup

-- Stop all containers started by this facade
docker.stop_all

-- Stop AND remove all containers
docker.cleanup

Checking Status

-- Is Docker available?
if docker.is_available then
    print ("Docker is running%N")
end

-- How many containers are we managing?
print ("Managing " + docker.container_count.out + " containers%N")

-- Did the last operation fail?
if docker.has_error then
    print ("Error: " + docker.last_error_message + "%N")
end

Advanced Access

Need more control? Access the underlying DOCKER_CLIENT:

-- Get full control when needed
docker.client.list_containers (True).do_nothing

Full API: Connecting to Docker

Creating a Client

local
    client: DOCKER_CLIENT
do
    create client.make

    -- Check connection
    if client.ping then
        print ("Docker daemon is responsive%N")
    else
        print ("Cannot connect to Docker%N")
    end
end

Getting Version Information

if attached client.version as v then
    print ("Docker Version: " + v.to_json + "%N")
end

if attached client.info as i then
    print ("Docker Info: " + i.to_json + "%N")
end

Working with Containers

Creating a Container Specification

Use the fluent builder API to configure containers:

local
    spec: CONTAINER_SPEC
do
    create spec.make ("alpine:latest")
    spec.set_name ("my-container")
        .set_hostname ("myhost")
        .set_cmd (<<"echo", "Hello!">>)
        .add_env ("DEBUG", "true")
        .add_env ("APP_NAME", "myapp").do_nothing
end

Port Mapping

spec.add_port (80, 8080)        -- Map container:80 to host:8080
    .add_port (443, 8443)       -- Map container:443 to host:8443
    .add_port_udp (53, 5353)    -- UDP port mapping
    .do_nothing

Volume Mounts

spec.add_volume ("/host/data", "/container/data")
    .add_volume_readonly ("/host/config", "/etc/config")
    .do_nothing

Resource Limits

spec.set_memory_limit (512 * 1024 * 1024)  -- 512 MB
    .set_cpu_shares (1024)
    .do_nothing

Restart Policies

spec.set_restart_policy ("no")             -- Never restart
spec.set_restart_policy ("always")         -- Always restart
spec.set_restart_policy ("on-failure")     -- Restart on failure
spec.set_restart_policy ("unless-stopped") -- Restart unless stopped

Running Containers

local
    container: detachable DOCKER_CONTAINER
do
    -- Create and start in one step
    container := client.run_container (spec)

    -- Or create then start separately
    container := client.create_container (spec)
    if attached container as c then
        client.start_container (c.id).do_nothing
    end
end

Container Lifecycle

-- Stop with timeout (seconds)
client.stop_container (container.id, 10).do_nothing

-- Pause/unpause
client.pause_container (container.id).do_nothing
client.unpause_container (container.id).do_nothing

-- Restart
client.restart_container (container.id, 10).do_nothing

-- Kill (force stop)
client.kill_container (container.id).do_nothing

-- Remove (force removes running containers)
client.remove_container (container.id, True).do_nothing

Getting Logs

if attached client.container_logs (container.id, True, True, 100) as logs then
    -- True, True = stdout, stderr
    -- 100 = last 100 lines
    print (logs)
end

Waiting for Exit

local
    exit_code: INTEGER
do
    exit_code := client.wait_container (container.id)
    print ("Container exited with code: " + exit_code.out + "%N")
end

Working with Images

Listing Images

across client.list_images as img loop
    print (img.out + "%N")
    -- Shows: short_id (tags) size_mb MB
end

Checking Image Existence

if client.image_exists ("alpine:latest") then
    print ("Alpine image is available%N")
end

Pulling Images

if client.pull_image ("nginx:alpine") then
    print ("Image pulled successfully%N")
else
    print ("Failed to pull image%N")
end

Removing Images

-- Remove image (force=False means won't remove if in use)
client.remove_image ("old-image:v1", False).do_nothing

-- Force remove
client.remove_image ("old-image:v1", True).do_nothing

Error Handling

Checking for Errors

container := client.create_container (spec)

if client.has_error then
    if attached client.last_error as err then
        print ("Error: " + err.out + "%N")
    end
end

Error Types

if attached client.last_error as err then
    if err.is_connection_error then
        -- Cannot connect to Docker daemon
    elseif err.is_timeout_error then
        -- Operation timed out
    elseif err.is_not_found then
        -- Container/image not found (404)
    elseif err.is_conflict then
        -- Name already in use (409)
    elseif err.is_server_error then
        -- Docker daemon error (5xx)
    end

    if err.is_retryable then
        -- Connection/timeout errors can be retried
    end
end

Common Error Recovery Patterns

-- Auto-pull missing images
container := client.create_container (spec)
if client.has_error and then
   attached client.last_error as err and then
   err.is_not_found then
    if client.pull_image (spec.image) then
        container := client.create_container (spec)
    end
end

-- Handle name conflicts
if client.has_error and then
   attached client.last_error as err and then
   err.is_conflict then
    -- Remove existing container and retry
    client.remove_container (spec.name, True).do_nothing
    container := client.create_container (spec)
end

Container State

Querying State

if container.is_running then
    print ("Container is running%N")
elseif container.is_paused then
    print ("Container is paused%N")
elseif container.is_exited then
    print ("Container has exited%N")
    print ("Exit code: " + container.exit_code.out + "%N")
elseif container.is_dead then
    print ("Container is dead%N")
end

Checking Available Operations

if container.can_start then
    client.start_container (container.id).do_nothing
end

if container.can_stop then
    client.stop_container (container.id, 10).do_nothing
end

if container.has_exited_successfully then
    print ("Container completed successfully%N")
end