1
0
Fork 0

First Kubernetes implementation

This commit is contained in:
Joao M 2022-08-23 01:06:16 +00:00
parent eb5f7e313f
commit bbf3dca6fd
5 changed files with 183 additions and 22 deletions

View file

@ -47,7 +47,7 @@ The environment variables will setup the HAProxy.
| Environment Variable | Description | | Environment Variable | Description |
|-------------------------------|---------------------------------------------------------------------------------------------------------------| |-------------------------------|---------------------------------------------------------------------------------------------------------------|
| EASYHAPROXY_DISCOVER | How `haproxy.cfg` will be created: `static`, `docker` or `swarm` | | EASYHAPROXY_DISCOVER | How `haproxy.cfg` will be created: `static`, `docker`, `swarm` or `kubernetes` |
| EASYHAPROXY_LABEL_PREFIX | (Optional) The key will search for matching resources. Default: `easyhaproxy`. | | EASYHAPROXY_LABEL_PREFIX | (Optional) The key will search for matching resources. Default: `easyhaproxy`. |
| EASYHAPROXY_LETSENCRYPT_EMAIL | (Optional) The email will be used to request the certificate to Letsencrypt | | EASYHAPROXY_LETSENCRYPT_EMAIL | (Optional) The email will be used to request the certificate to Letsencrypt |
| EASYHAPROXY_SSL_MODE | (Optional) `STRICT` supports only the most recent TLS version; `DEFAULT` good SSL integration with recent browsers; `LOOSE` supports all old SSL protocols for old browsers (not recommended). | | EASYHAPROXY_SSL_MODE | (Optional) `STRICT` supports only the most recent TLS version; `DEFAULT` good SSL integration with recent browsers; `LOOSE` supports all old SSL protocols for old browsers (not recommended). |
@ -100,7 +100,48 @@ The discovery will occur every minute.
Important: easyhaproxy needs to be in the same network of the containers or otherwise will not access. Important: easyhaproxy needs to be in the same network of the containers or otherwise will not access.
### Docker Container (Swarm or Docker) tags: ### EASYHAPROXY_DISCOVER: kubernetes (experimental and limited)
This will query all `ingress` in the kubernetes cluster and check the annotation `kubernetes.io/ingress.class: easyhaproxy-ingress`.
e.g.:
```
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: easyhaproxy-ingress
name: example-ingress
namespace: example
spec:
rules:
- host: example.org
http:
paths:
- backend:
service:
name: example-service
port:
number: 8080
pathType: ImplementationSpecific
- host: www.example.org
http:
paths:
- backend:
service:
name: example-service
port:
number: 8080
pathType: ImplementationSpecific
```
At this point the implementation is very limited and doesn't support all ingress properties nor wildcard domains.
The system will read only `host` and `port.number`
There is no necessary to add labels or annotations.
### Container (Docker or Swarm) labels:
| Tag | Description | Example | | Tag | Description | Example |
|---------------------------------------|---------------------------------------------------------------------------------------------------------|--------------| |---------------------------------------|---------------------------------------------------------------------------------------------------------|--------------|

View file

@ -6,11 +6,6 @@ cd /scripts
RELOAD="true" RELOAD="true"
if [[ "static|docker|swarm" != *"$EASYHAPROXY_DISCOVER"* ]];then
log "error" "CONF_CHECK" "EASYHAPROXY_DISCOVER should be 'static', 'docker', or 'swarm'. I got '$EASYHAPROXY_DISCOVER' instead."
exit 1
fi
if [[ "$EASYHAPROXY_DISCOVER" == "static" ]]; then if [[ "$EASYHAPROXY_DISCOVER" == "static" ]]; then
CONTROL_FILE="/etc/haproxy/haproxy.cfg" CONTROL_FILE="/etc/haproxy/haproxy.cfg"
touch ${CONTROL_FILE} touch ${CONTROL_FILE}
@ -22,21 +17,34 @@ else
mv ${CONTROL_FILE} ${CONTROL_FILE}.old mv ${CONTROL_FILE} ${CONTROL_FILE}.old
touch ${CONTROL_FILE} touch ${CONTROL_FILE}
if [[ "$EASYHAPROXY_DISCOVER" == "docker" ]]; then case "$EASYHAPROXY_DISCOVER" in
docker)
CONTAINERS=$(docker ps -q | sort | uniq) CONTAINERS=$(docker ps -q | sort | uniq)
LABEL_PATH=".Config.Labels" LABEL_PATH=".Config.Labels"
for container in ${CONTAINERS}; do for container in ${CONTAINERS}; do
docker inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE} docker inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE}
done done
else ;;
swarm)
CONTAINERS=$(docker node ps $(docker node ls -q) --format "{{ .Name }}" --filter desired-state=running | cut -d. -f1 | sort | uniq) CONTAINERS=$(docker node ps $(docker node ls -q) --format "{{ .Name }}" --filter desired-state=running | cut -d. -f1 | sort | uniq)
LABEL_PATH=".Spec.Labels" LABEL_PATH=".Spec.Labels"
for container in ${CONTAINERS}; do for container in ${CONTAINERS}; do
docker service inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE} docker service inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE}
done done
fi ;;
kubernetes)
python3 /scripts/k8s.py > ${CONTROL_FILE}
;;
*)
log "error" "CONF_CHECK" "EASYHAPROXY_DISCOVER should be 'static', 'docker', 'swarm' or kubernetes. I got '$EASYHAPROXY_DISCOVER' instead."
exit 1
;;
esac
if cmp -s ${CONTROL_FILE} ${CONTROL_FILE}.old ; then if cmp -s ${CONTROL_FILE} ${CONTROL_FILE}.old ; then
RELOAD="false" RELOAD="false"

50
assets/scripts/k8s.py Normal file
View file

@ -0,0 +1,50 @@
from kubernetes import client, config
from kubernetes.client.rest import ApiException
import json
# https://github.com/kubernetes-client/python/tree/master/kubernetes/docs
def main():
config.load_incluster_config()
api_instance = client.CoreV1Api()
v1 = client.NetworkingV1Api()
ret = v1.list_ingress_for_all_namespaces(watch=False)
discover = {}
for i in ret.items:
if i.metadata.annotations['kubernetes.io/ingress.class'] != "easyhaproxy-ingress":
continue
data = {}
#ingress_name = i.metadata.name
data["creation_timestamp"] = i.metadata.creation_timestamp.strftime("%x %X")
data["resource_version"] = i.metadata.resource_version
data["namespace"] = i.metadata.namespace
for rule in i.spec.rules:
rule_data = {}
port_number = rule.http.paths[0].backend.service.port.number
definition = rule.host.replace(".", "-")
rule_data["easyhaproxy.%s_%s.host" % (definition, port_number)] = rule.host
rule_data["easyhaproxy.%s_%s.port" % (definition, port_number)] = "80"
rule_data["easyhaproxy.%s_%s.localport" % (definition, port_number)] = port_number
service_name = rule.http.paths[0].backend.service.name
try:
api_response = api_instance.read_namespaced_service(service_name, i.metadata.namespace)
cluster_ip = api_response.spec.cluster_ip
except ApiException as e:
cluster_ip = None
# print("Exception when calling CoreV1Api->read_namespaced_service: %s\n" % e)
if cluster_ip is not None:
if cluster_ip not in discover.keys():
discover[cluster_ip] = data
discover[cluster_ip].update(rule_data)
for k in discover.keys():
print("%s=%s" % (k, json.dumps(discover[k])))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,61 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: easyhaproxy
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: easyhaproxy-ingress
namespace: easyhaproxy
spec:
selector:
matchLabels:
app: easyhaproxy-ingress
template:
metadata:
labels:
app: easyhaproxy-ingress
spec:
serviceAccountName: easyhaproxy-ingress
containers:
- image: byjg/easy-haproxy:kubernetes
imagePullPolicy: IfNotPresent
name: easyhaproxy-ingress
ports:
- name: http
containerPort: 80
hostPort: 80
- name: https
containerPort: 443
hostPort: 443
- name: stats
containerPort: 1943
hostPort: 1943
resources:
requests:
cpu: "100m"
memory: "128Mi"
#limits:
# cpu: "1"
# memory: "1Gi"
securityContext:
allowPrivilegeEscalation: true
#runAsUser: 101 #nginx
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: EASYHAPROXY_DISCOVER
value: kubernetes
- name: HAPROXY_USERNAME
value: admin
- name: HAPROXY_PASSWORD
value: password
- name: EASYHAPROXY_REFRESH_CONF
value: 10

View file

@ -2,3 +2,4 @@ pyyaml
docker docker
jinja2 jinja2
pytest pytest
kubernetes