Introduction

A simple container manager is designed to ease life for the developers and DevOps engineers running containers on Docker.

Introducing objects which can be defined as YAML definition and sent to the simplecontainer manager to produce Docker container via reconciliation:

  • Containers
  • Container
  • Configuration
  • Resource
  • Gitops
  • CertKey
  • HttpAuth

These objects lets you configure Docker containers.

Features:

  • Single Docker daemon only (Currently)
  • Integrated DNS server isolated from Docker daemon
  • GitOps: deploy objects from the GitOps repositories
  • Replication of containers
  • Reconciliation and tracking the lifecycle of the Docker containers
  • Operators to implement third-party functionalities
  • CLI client to interact with the simplecontainer manager
  • Fast learning curve - no over complication
  • Reliable dependency ordering and readiness probes
  • Templating of the container objects to leverage secrets and configuration

Example

Bundle directory structure

├── configuration.yaml
└── container.yaml

Bundle directory structure

Configuration

Configuration can reference the secret objects from the key value store.

kind: configuration
spec:
  meta:
    group: mysql
    identifier: "*"
  spec:
    data:
      password: "{{ secret.mysql.mysql.password }}"

configuration.yaml

Container

All external configuration is references in the configuration block. The elements in the container are referencing elements from the configuration block.

kind: containers
meta:
  name: logical-group
  group: test
spec:
  mysql:
    meta:
      name: mysql
      group: mysql
    spec:
      options:
        enabled: false
      container:
        image: "mysql"
        tag: "8.0"
        replicas: 1
        envs:
          - "MYSQL_ROOT_PASSWORD={{ configuration.password }}"
        networks:
          - "ghost"
        ports:
          - container: "3306"
        readiness:
          - name: "mysql[*]"
            operator: DatabaseReady
            timeout: "20s"
            body:
              ip: "mysql.mysql-mysql-1.docker.private"
              username: "{{ configuration.username }}"
              password: "{{ configuration.password }}"
              port: "3306"
        configuration:
          username: "root"
          password: "{{ configuration.mysql[*].password }}"

container.yaml

Deployment

Simplecontainer is designed using client-server architecture. CLI speaks to the agent running as a container in the Docker daemon. Docker daemon is manipulated using agent and reconciled to the defined YAML files.

Client and server are using mTLS for authentication - so exposing the simplecontainer agent via public internet is secured. You can read more about contexts and security here.

smr secret create secret.mysql.mysql.password 123456789
smr apply configuration.yaml
smr apply container.yaml
smr ps

GROUP    NAME     DOCKER NAME        IMAGE         IP                                      PORTS                      DEPS  DOCKER STATE  SMR STATE                
mysql    mysql    mysql-mysql-1      mysql:8.0     10.10.0.4 (ghost), 172.17.0.5 (bridge)  3306                             running       running (24.72208817s)   

On the other hand:

docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS                                NAMES
71551f1bc475   mysql:8.0     "docker-entrypoint.s…"   6 seconds ago   Up 6 seconds   33060/tcp, 0.0.0.0:32805->3306/tcp   mysql-mysql-1
3d36e2ac9599   smr:7850f20   "/bin/sh -c '/opt/sm…"   7 minutes ago   Up 7 minutes   0.0.0.0:1443->1443/tcp, 8080/tcp     smr-agent

There are 2 containers:

  • simplecontainer agent
  • mysql container created by the simplecontainer agent

Simplecontainer is tracking all the time state of the Docker container. If state drifts from one defined it will reconcile to the defined state.

That's it. It is simple and straightforward.

If the container is constantly restarting smr will stop trying to recreate the container and push it to backoff state. Container needs to be recreated after backoff.

smr ps
GROUP  NAME   DOCKER NAME    IMAGE      IP  PORTS  DEPS  DOCKER STATE  SMR STATE                  
mysql  mysql  mysql-mysql-1  mysql:8.0      3306         exited        backoff (5m58.200292435s)  

To track control plane logs:

smr logs container mysql mysql-mysql-1
{"level":"info","ts":1720442781.5385828,"caller":"container/Impl.go:123","msg":"new container object created","group":"mysql","identifier":"mysql"}
{"level":"info","ts":1720442781.53874,"caller":"reconcile/Reconciler.go:65","msg":"container already reconciling, waiting for the free slot"}
{"level":"info","ts":1720442786.5387728,"caller":"reconcile/Reconciler.go:85","msg":"trying to run container","group":"mysql","name":"mysql"}
{"level":"info","ts":1720442791.5426116,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442796.5445535,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442801.5435655,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442806.5441086,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442811.543327,"caller":"reconcile/Reconciler.go:119","msg":"stopping container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442814.370602,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442814.3706663,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442814.3706923,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442814.3707106,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442814.3707266,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442814.3707402,"caller":"reconcile/Reconciler.go:85","msg":"trying to run container","group":"mysql","name":"mysql"}
{"level":"info","ts":1720442816.5429473,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442821.543589,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442826.5443048,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442831.5436978,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442836.54295,"caller":"reconcile/Reconciler.go:119","msg":"stopping container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442839.0057871,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442839.0058384,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442839.0058599,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442839.0058775,"caller":"reconcile/Reconciler.go:85","msg":"trying to run container","group":"mysql","name":"mysql"}
{"level":"info","ts":1720442841.543751,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442846.5429995,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442851.5508125,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442856.5432806,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442861.5432427,"caller":"reconcile/Reconciler.go:119","msg":"stopping container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442893.31383,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442893.3138793,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442893.3139143,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442893.313932,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442893.3139472,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442893.3139634,"caller":"reconcile/Reconciler.go:85","msg":"trying to run container","group":"mysql","name":"mysql"}
{"level":"info","ts":1720442896.5428667,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442901.5433958,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442906.5488963,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442911.544553,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442916.5438023,"caller":"reconcile/Reconciler.go:119","msg":"stopping container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5700443,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5700936,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5701156,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5701346,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5701513,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5701964,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5702176,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442919.5702631,"caller":"reconcile/Reconciler.go:85","msg":"trying to run container","group":"mysql","name":"mysql"}
{"level":"info","ts":1720442921.54323,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442926.5432396,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442931.5431097,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442936.5440998,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442941.5429473,"caller":"reconcile/Reconciler.go:119","msg":"stopping container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442973.817524,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442973.8176115,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442973.8176417,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442973.8176866,"caller":"reconcile/Reconciler.go:80","msg":"Solving dependencies for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442973.8177037,"caller":"reconcile/Reconciler.go:85","msg":"trying to run container","group":"mysql","name":"mysql"}
{"level":"info","ts":1720442976.5425942,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442981.5427427,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442986.5432918,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442991.543267,"caller":"reconcile/Reconciler.go:114","msg":"Solving readiness for the container","container":"mysql-mysql-1"}
{"level":"info","ts":1720442996.5433228,"caller":"reconcile/Reconciler.go:119","msg":"stopping container","container":"mysql-mysql-1"}
{"level":"error","ts":1720443028.9007828,"caller":"reconcile/Reconciler.go:152","msg":"mysql-mysql-1 container is backoff restarting","stacktrace":"github.com/simplecontainer/smr/implementations/container/reconcile.ReconcileContainer\n\t/home/qdnqn/projects/smr/smr/implementations/container/reconcile/Reconciler.go:152"}
{"level":"info","ts":1720443028.9009066,"caller":"reconcile/Reconciler.go:172","msg":"mysql-mysql-1 container is in backoff state"}
{"level":"info","ts":1720443031.539407,"caller":"reconcile/Reconciler.go:172","msg":"mysql-mysql-1 container is in backoff state"}

Delete

smr delete container.yaml
smr delete configuration.yaml

After running these commands everything will be removed.


This is quick introduction of the basic running, inspecting and deleting the objects. For detailed documentation reference the other resources.