working state
This commit is contained in:
parent
f81d7865f1
commit
739e61d89e
87
README.md
87
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
|
||||
<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
|
||||
```
|
||||
@ -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"]
|
||||
@ -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 %}
|
||||
|
||||
4
ansible/haproxy/Dockerfile
Normal file
4
ansible/haproxy/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
||||
FROM haproxy:lts-alpine
|
||||
|
||||
ADD haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
|
||||
# TODO certs
|
||||
@ -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
5
ansible/nginx/Dockerfile
Normal 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
10
ansible/nginx/init.sh
Normal 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
|
||||
@ -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 }}'
|
||||
|
||||
...
|
||||
Loading…
x
Reference in New Issue
Block a user