working state

This commit is contained in:
fix 2023-11-15 19:06:09 +01:00
parent f81d7865f1
commit 739e61d89e
8 changed files with 200 additions and 80 deletions

View File

@ -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
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.23.4</center>
</body>
</html>
$ curl -k https://localhost:8443/index.html
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
(venv) [fix@neon
```

View File

@ -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"]

View File

@ -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 %}

View File

@ -0,0 +1,4 @@
FROM haproxy:lts-alpine
ADD haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
# TODO certs

View File

@ -1,3 +1,4 @@
docker_host:
localhost:
ansible_host: 127.0.0.1
hosts:
localhost:
ansible_host: 127.0.0.1

5
ansible/nginx/Dockerfile Normal file
View File

@ -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

10
ansible/nginx/init.sh Normal file
View File

@ -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

View File

@ -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 }}'
...