diff --git a/README.md b/README.md
index bc36810..dd7a37c 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,88 @@
# the task
see ()[task.md]
-# setup
+# deploy
-## use ansible runtime container
+## python virtualenv
Because ansible setups have requirements towards used python versions, libraries etc,
-I provide a unified solution everyone that has a contaner runtime like `docker` installed can use.
-
-This also prevents me from needing to handle python dependencies in conflicting versions.
+we use a separate python virtualenv.
```shell
-# build the container
-docker build -t ansible-runtime:local ansible-runtime
+export VENV_PATH='/tmp/venv'
+# create the env
+$ python -m venv "${VENV_PATH}"
-# then run it
-docker run -v ${PWD}/ansible:/home/user/workdir:ro --rm -it ansible-runtime:local
+# activate it
+$ . "${VENV_PATH}/bin/activate"
+
+# install pip dependencies
+pip install -r ansible-runtime/requirements.txt
```
+
+## kick off the deployment
+
+assumptions:
+* you have initialized and activated the venv as described above
+* the current user has ssh access to `localhost`
+* the current user can access the docker socket at `/var/run/docker.sock`
+
+```shell
+$ cd ansible
+$ ansible-playbook -i inventory.yaml playbook.yaml
+```
+
+This deploys three containers and a network. List them:
+```shell
+# quick and dirty:
+docker ps -a | grep userlike
+# or with something like this:
+docker ps --format json -a | yq -p json -ojson 'select(.Names|test("userlike-.*"))'
+```
+
+And confirm the routing works as expected:
+```shell
+curl -k https://localhost:8443/ # shall return one/two backend alternating responses
+curl -k https://localhost:8443/one # shall only return "one" responses
+curl -k https://localhost:8443/two # shall only return "two" responses
+
+```
+
+## testing
+some example queries to test for the given [task](./task.md)
+```shell
+$ curl -k https://localhost:8443/
+hello my friend, this is backend host "one" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/
+hello my friend, this is backend host "two" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/one
+hello my friend, this is backend host "one" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/one
+hello my friend, this is backend host "one" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/two
+hello my friend, this is backend host "two" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/two
+hello my friend, this is backend host "two" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/two/index.html
+hello my friend, this is backend host "two" speaking.
+have a nice day, mate.
+$ curl -k https://localhost:8443/two/index.html.nonexistent
+
+
404 Not Found
+
+404 Not Found
+
nginx/1.23.4
+
+
+$ curl -k https://localhost:8443/index.html
+503 Service Unavailable
+No server is available to handle this request.
+
+(venv) [fix@neon
+```
\ No newline at end of file
diff --git a/ansible-runtime/Dockerfile b/ansible-runtime/Dockerfile
deleted file mode 100644
index 7d120ce..0000000
--- a/ansible-runtime/Dockerfile
+++ /dev/null
@@ -1,18 +0,0 @@
-
-FROM python:3.11-alpine as base
-ARG UID=1000
-ENV UID=${UID}
-ARG DOCKER_GID
-ENV DOCKER_GID=${DOCKER_GID:-972}
-
-ADD requirements.txt /requirements.txt
-
-# RUN --mount=type=cache,target=/var/cache apk update
-RUN --mount=type=cache,target=/var/cache pip --cache-dir=/var/cache/pip install -r /requirements.txt
-
-FROM base as runtime
-RUN addgroup -g ${DOCKER_GID} docker && adduser -G docker -Du ${UID} user
-
-WORKDIR /home/user
-USER user
-ENTRYPOINT ["/bin/ash"]
diff --git a/ansible/haproxy.cfg.template b/ansible/haproxy.cfg.template
index b05c804..574099d 100644
--- a/ansible/haproxy.cfg.template
+++ b/ansible/haproxy.cfg.template
@@ -1,7 +1,10 @@
global
log stdout format raw local0 debug
- # user haproxy
- # group haproxy
+ user haproxy
+ group haproxy
+ # this is to tackle a weird problem I observed
+ # https://github.com/docker-library/haproxy/issues/180
+ fd-hard-limit 10000
daemon
defaults
@@ -9,23 +12,34 @@ defaults
mode http
option httplog
option dontlognull
+ maxconn 1000
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http_front
- bind *:8443 ssl crt /usr/local/etc/haproxy/tls/certificate.pem
+ bind :8443 ssl crt /usr/local/etc/haproxy/tls/certificate.pem
- acl be_one path_beg /one
- acl be_two path_beg /two
+{% for hostname in nginx_names %}
+ acl be_{{ hostname }} path_beg /{{ hostname }}
+{% endfor %}
+{% for hostname in nginx_names %}
+ use_backend be_{{ hostname }} if be_{{ hostname }}
+{% endfor %}
- use_backend be_one if be_one
- use_backend be_two if be_two
+ acl be_round_robin path /
+ use_backend be_round_robin if be_round_robin {% for hostname in nginx_names %} !be_{{ hostname }} {% endfor %}
-backend be_one
+{% for hostname in nginx_names %}
+backend be_{{ hostname }}
mode http
- server one http://one:8080/
+ http-request set-path %[path,regsub(^/{{ hostname }},"")]
+ server {{ hostname }} {{ hostname }}:80/
+{% endfor %}
-backend be_two
+backend be_round_robin
mode http
- server two http://two:8080/
+{% for hostname in nginx_names %}
+ http-request set-path %[path,regsub(^/{{ hostname }}/,/)]
+ server {{ hostname }} {{ hostname }}:80/
+{% endfor %}
diff --git a/ansible/haproxy/Dockerfile b/ansible/haproxy/Dockerfile
new file mode 100644
index 0000000..3d3521d
--- /dev/null
+++ b/ansible/haproxy/Dockerfile
@@ -0,0 +1,4 @@
+FROM haproxy:lts-alpine
+
+ADD haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
+# TODO certs
diff --git a/ansible/inventory.yaml b/ansible/inventory.yaml
index 1aca5de..74c37de 100644
--- a/ansible/inventory.yaml
+++ b/ansible/inventory.yaml
@@ -1,3 +1,4 @@
docker_host:
- localhost:
- ansible_host: 127.0.0.1
+ hosts:
+ localhost:
+ ansible_host: 127.0.0.1
diff --git a/ansible/nginx/Dockerfile b/ansible/nginx/Dockerfile
new file mode 100644
index 0000000..213548e
--- /dev/null
+++ b/ansible/nginx/Dockerfile
@@ -0,0 +1,5 @@
+ARG BASE_IMAGE
+FROM ${BASE_IMAGE} as base
+
+COPY init.sh /docker-entrypoint.d/init.sh
+RUN chmod 755 /docker-entrypoint.d/init.sh
diff --git a/ansible/nginx/init.sh b/ansible/nginx/init.sh
new file mode 100644
index 0000000..41798e3
--- /dev/null
+++ b/ansible/nginx/init.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+set -xe
+
+HOSTNAME=$(cat /etc/hostname)
+cat << EOF > /usr/share/nginx/html/index.html
+hello my friend, this is backend host "${HOSTNAME}" speaking.
+have a nice day, mate.
+EOF
+
+exit 0
\ No newline at end of file
diff --git a/ansible/playbook.yaml b/ansible/playbook.yaml
index 3969803..dc01c50 100644
--- a/ansible/playbook.yaml
+++ b/ansible/playbook.yaml
@@ -1,83 +1,118 @@
---
-- name: generate fake cert
- hosts: &hosts localhost
+- name: userlike deployment
+ hosts: localhost
become: false
+ vars:
+ temp_dir: /tmp/userlike
+ images:
+ haproxy: haproxy:lts-alpine
+ nginx: nginx:1.23-alpine
+ nginx_names:
+ - one
+ - two
tasks:
# adopted from https://docs.ansible.com/ansible/latest/collections/community/crypto/docsite/guide_selfsigned.html
- name: ensure local cert dir exists
file:
- path: /home/user/userlike/haproxy/tls
+ path: '{{ temp_dir }}/haproxy/tls'
state: directory
mode: 0755
recurse: yes
- name: create private key
community.crypto.openssl_privatekey:
- path: /home/user/userlike/haproxy/tls/certificate.pem.key
+ path: '{{ temp_dir }}/haproxy/tls/certificate.key'
+ size: 2048
+ mode: '0644'
type: RSA
+ return_content: true
- name: create self-signed certificate
community.crypto.x509_certificate:
- path: /home/user/userlike/haproxy/tls/certificate.pem
- privatekey_path: /home/user/userlike/haproxy/tls/certificate.pem.key
+ path: '{{ temp_dir }}/haproxy/tls/certificate.crt'
+ privatekey_path: '{{ temp_dir }}/haproxy/tls/certificate.key'
provider: selfsigned
+ selfsigned_not_after: '+365d'
+ mode: '0644'
-- name: docker preparations
- hosts: *hosts
- tasks:
- - name: set DOCKER_HOST env var
- ansible.builtin.shell:
- cmd: export DOCKER_HOST=unix:///var/run/docker.sock
+ - name: concatenate key and certificate
+ ansible.builtin.copy:
+ dest: '{{ temp_dir }}/haproxy/tls/certificate.pem'
+ content: |
+ {{ lookup('file', '{{ temp_dir }}/haproxy/tls/certificate.key') }}
+ {{ lookup('file', '{{ temp_dir }}/haproxy/tls/certificate.crt') }}
- - name: 'pull image {{ item }}'
+ - name: remove on-disk certificate remnants
+ file:
+ path: '{{ temp_dir }}/haproxy/tls/certificate.{{ item }}'
+ state: absent
+ with_items:
+ - crt
+ - key
+
+ # docker prepratations
+ - name: 'pull images {{ item }}'
community.docker.docker_image:
name: '{{ item }}'
state: present
source: pull
- with_items:
- - haproxy:lts-alpine
- - nginx:1.23-alpine
+ with_items: '{{ images.values() }}'
- - name: create network
+ - name: create docker network
community.docker.docker_network:
name: userlike
-- name: run haproxy container
- hosts: *hosts
- tasks:
+ # haproxy tasks
+ - name: ensure local haproxy dir exists
+ file:
+ path: '{{ temp_dir }}/haproxy'
+ state: directory
+ mode: 0755
+
- name: render haproxy config
ansible.builtin.template:
src: haproxy.cfg.template
- dest: /home/user/userlike/haproxy/haproxy.cfg
+ dest: '{{ temp_dir }}/haproxy/haproxy.cfg'
mode: '0644'
- - name: build container
- community.docker.docker_container:
- name: userlike-haproxy:local
- build:
- path: ./haproxy
-
- source: build
- - name: run container
+ - name: run haproxy container
community.docker.docker_container:
name: userlike-haproxy
recreate: true
detach: true
- image: haproxy:lts-alpine
+ image: '{{ images.haproxy }}'
+ restart_policy: 'unless-stopped'
networks:
- name: userlike
ports:
- - '127.0.0.1:8080:8080'
+ - '127.0.0.1:8443:8443'
volumes:
- # has to be host directory
- - /tmp/userlike/haproxy:/usr/local/etc/haproxy:ro
+ - '{{ temp_dir }}/haproxy:/usr/local/etc/haproxy:ro'
-# - name: run nginx containers
-# hosts: *hosts
-# tasks:
-# - name: create config
-# - name: pull container
-# - name: create container
-# - name: run container
+ # nginx tasks
+ - name: ensure local nginx dir exists
+ file:
+ path: '{{ temp_dir }}/nginx'
+ state: directory
+ mode: 0755
+
+ - name: copy nginx init file
+ copy:
+ src: nginx/init.sh
+ dest: '{{ temp_dir }}/nginx/init.sh'
+ mode: '0755'
+
+ - name: run nginx container
+ community.docker.docker_container:
+ name: 'userlike-nginx-{{ item }}'
+ hostname: '{{ item }}'
+ recreate: true
+ detach: true
+ image: '{{ images.nginx }}'
+ networks:
+ - name: userlike
+ volumes:
+ - '{{ temp_dir }}/nginx/init.sh://docker-entrypoint.d/init.sh:ro'
+ with_items: '{{ nginx_names }}'
...
\ No newline at end of file