diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..887c954 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,213 @@ +name: CI +on: + push: + branches: + - docker +jobs: + docker: + runs-on: ubuntu-18.04 + steps: + - name: checkout + uses: actions/checkout@v2 + - name: test + run: | + set -x + for app in hasher rng webui worker + do \ + docker build -t macarenasre/dockercoins:testing-${app} ${app} + done + #creamos redes p cada uno + for app in hasher redis rng webui worker + do \ + docker network create ${app} + done + #ejecyutamos container y creamos volumen + docker run -d --name redis --network redis -v redis:/data redis + # + for app in hasher rng webui worker + do \ + docker run -d --name ${app} --network ${app} macarenasre/dockercoins:testing-${app} + done + #conectar los contenedores a las redes + for app in webui worker + do \ + docker network connect redis ${app} + done + for network in hasher rng + do \ + docker network connect ${network} worker + done + #testear app + while true + do \ + sleep 10 + docker logs hasher 2>& 1 | grep '== Sinatra .* has taken the stage on .* for development with backup from Thin' && break + done + while true + do \ + sleep 10 + docker logs redis 2>& 1 | grep 'Ready to accept connections' && break + done + while true + do \ + sleep 10 + docker logs rng 2>& 1 | grep 'Running on' && break + done + while true + do \ + sleep 10 + docker logs webui 2>& 1 | grep 'WEBUI running on port' && break + done + while true + do \ + sleep 10 + docker logs worker 2>& 1 | grep 'Coin found' && break + done + swarm: + runs-on: ubuntu-18.04 + steps: + - name: checkout + uses: actions/checkout@v2 + - name: test + run: | + set -x + #creo imagen image + for app in hasher rng webui worker + do \ + docker build -t macarenasre/dockercoins:testing-${app} ${app} + done + docker swarm init + project=dockercoins + compose=etc/swarm/manifests/${project}.yaml + #sustituyo latest x testing y despliego con compose + sed -i /image:/s/latest/testing/ ${compose} + sed -i /node.role/s/worker/manager/ ${compose} + #Despliegue en Openshift + #oc apply -f ${compose} + #despliegue en Kubernetes + #kubectl apply -f ${compose} + #desplioegue en swarm + docker stack deploy -c ${compose} ${project} + while true + do \ + sleep 10 + docker service logs ${project}_hasher 2>& 1 | grep '== Sinatra .* has taken the stage on .* for development with backup from Thin' && break + done + while true + do \ + sleep 10 + docker service logs ${project}_redis 2>& 1 | grep 'Ready to accept connections' && break + done + while true + do \ + sleep 10 + docker service logs ${project}_rng 2>& 1 | grep 'Running on' && break + done + while true + do \ + sleep 10 + docker service logs ${project}_webui 2>& 1 | grep 'WEBUI running on port' && break + done + while true + do \ + sleep 10 + docker service logs ${project}_worker 2>& 1 | grep 'Coin found' && break + done + kubernetes: + runs-on: ubuntu-18.04 + steps: + - name: checkout + uses: actions/checkout@v2 + - name: test + run: | + set -x + project=dockercoins + #creo imagen image + for app in hasher rng webui worker + do + docker build -t macarenasre/${project}:testing-${app} ${app} + done + #install kubernetes en ubunto + sudo apt-get update -y + #sudo apt-get install -y docker.io + #sudo systemctl enable --now docker + curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - + echo deb http://apt.kubernetes.io/ kubernetes-xenial main | sudo tee -a /etc/apt/sources.list.d/kubernetes.list + sudo apt-get update -y + sudo apt-get install -y --allow-downgrades kubelet=1.18.14-00 kubeadm=1.18.14-00 kubectl=1.18.14-00 + sudo systemctl enable --now kubelet + #inicializar kubernetes + ip_leader=$( ip r | grep default | awk '{ print $9 }' ) + echo ${ip_leader} kube-apiserver | sudo tee -a /etc/hosts + sudo swapoff --all + sudo kubeadm init --upload-certs --control-plane-endpoint kube-apiserver --pod-network-cidr 192.168.0.0/16 --ignore-preflight-errors all + #copiamos las credenciales a nuestro dir + mkdir -p ${HOME}/.kube + sudo cp /etc/kubernetes/admin.conf ${HOME}/.kube/config + sudo chown -R $( id -u ):$( id -g ) ${HOME}/.kube + #una vez inicializado Kubernetes creamos la red + kubectl apply -f https://docs.projectcalico.org/v3.17/manifests/calico.yaml + #comprobar q el cluster esta listo + while true + do + kubectl get node | grep Ready | grep -v NotReady && break + sleep 10 + done + #limpiar configuracion + sudo sed -i /kube-apiserver/d /etc/hosts + sudo sed -i /127.0.0.1.*localhost/s/$/' 'kube-apiserver/ /etc/hosts + #habilitar el master + master=$( kubectl get node | grep master | awk '{ print $1 }' ) + kubectl taint node ${master} node-role.kubernetes.io/master:NoSchedule- + + compose=etc/kubernetes/manifests/${project}.yaml + #sustituyo latest x testing y despliego con compose + sed -i /image:/s/latest/testing/ ${compose} + sed -i /imagePullPolicy/s/Always/Never/ ${compose} + #Despliegue en Openshift + #oc apply -f ${compose} + #despliegue en Kubernetes + kubectl apply -f ${compose} + #desplioegue en swarm + #docker stack deploy -c ${compose} ${project} + app=hasher + pattern='== Sinatra .* has taken the stage on .* for development with backup from Thin' + while true + do + sleep 10 + kubectl logs deploy/${app} 2>& 1 | grep "${pattern}" && break + done + app=redis + pattern='Ready to accept connections' + while true + do + sleep 10 + #kubecetl deploy/redis + #kubectl describe rs + #kubectl describe po + #kubectl logs describe deploy/redis + #sleep 100 + kubectl logs deploy/${app} 2>& 1 | grep "${pattern}" && break + done + app=rng + pattern='Running on' + while true + do + sleep 10 + kubectl logs ds/${app} 2>& 1 | grep "${pattern}" && break + done + app=webui + pattern='WEBUI running on port' + while true + do + sleep 10 + kubectl logs deploy/${app} 2>& 1 | grep "${pattern}" && break + done + app=worker + pattern='Coin found' + while true + do + sleep 10 + kubectl logs deploy/${app} 2>& 1 | grep "${pattern}" && break + done + diff --git a/README.md b/README.md index 4f16070..1f47845 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # dockercoins +![CI](https://github.com/Macarena-SRE/dockercoins/workflows/CI/badge.svg?branch=docker) This is the demo application originally used in Jérôme Petazzoni's [orchestration workshop](https://github.com/jpetazzo/container.training). diff --git a/etc/kubernetes/manifests/dockercoins.yaml b/etc/kubernetes/manifests/dockercoins.yaml new file mode 100644 index 0000000..153f90d --- /dev/null +++ b/etc/kubernetes/manifests/dockercoins.yaml @@ -0,0 +1,170 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: rng +spec: + selector: + matchLabels: + app: rng + template: + metadata: + labels: + app: rng + spec: + containers: + - + image: macarenasre/dockercoins:latest-rng + imagePullPolicy: Always + name: rng + ports: + - + containerPort: 8080 + protocol: TCP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hasher +spec: + replicas: 1 + selector: + matchLabels: + app: hasher + template: + metadata: + labels: + app: hasher + spec: + containers: + - + image: macarenasre/dockercoins:latest-hasher + imagePullPolicy: Always + name: hasher + ports: + - + containerPort: 8080 + protocol: TCP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - + image: redis + name: redis + ports: + - + containerPort: 6379 + protocol: TCP + volumeMounts: + - + mountPath: /data + name: redis + volumes: + - + name: redis + emptyDir: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: webui +spec: + replicas: 1 + selector: + matchLabels: + app: webui + template: + metadata: + labels: + app: webui + spec: + containers: + - + image: macarenasre/dockercoins:latest-webui + imagePullPolicy: Always + name: webui + ports: + - + containerPort: 8080 + protocol: TCP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: worker +spec: + replicas: 1 + selector: + matchLabels: + app: worker + template: + metadata: + labels: + app: worker + spec: + containers: + - + image: macarenasre/dockercoins:latest-worker + imagePullPolicy: Always + name: worker +--- +apiVersion: v1 +kind: Service +metadata: + name: hasher +spec: + ports: + - + port: 8080 + targetPort: 8080 + selector: + app: hasher +--- +apiVersion: v1 +kind: Service +metadata: + name: redis +spec: + ports: + - + port: 6379 + targetPort: 6379 + selector: + app: redis +--- +apiVersion: v1 +kind: Service +metadata: + name: rng +spec: + ports: + - + port: 8080 + targetPort: 8080 + selector: + app: rng +--- +apiVersion: v1 +kind: Service +metadata: + name: webui +spec: + ports: + - + port: 8080 + targetPort: 8080 + selector: + app: webui +--- diff --git a/etc/swarm/manifests/dockercoins.yaml b/etc/swarm/manifests/dockercoins.yaml new file mode 100644 index 0000000..29d9aa5 --- /dev/null +++ b/etc/swarm/manifests/dockercoins.yaml @@ -0,0 +1,148 @@ +networks: + hasher: + internal: true + redis: + internal: true + rng: + internal: true + webui: + internal: false + worker: + internal: true +services: + hasher: + deploy: + mode: replicated + placement: + constraints: + - node.role == worker + replicas: 1 + resources: + limits: + cpus: "0.1" + memory: 100M + reservations: + cpus: "0.1" + memory: 100M + expose: + - 8080 + healthcheck: + interval: 10s + retries: 3 + start_period: 30s + test: wget -q --spider localhost:8080 + timeout: 1s + image: macarenasre/dockercoins:latest-hasher + # image: macarenasre/dockercoins-hasher:latest esto genera q proyecto x microservicio + networks: + - hasher + redis: + deploy: + mode: replicated + placement: + constraints: + - node.role == worker + replicas: 1 + resources: + limits: + cpus: "0.1" + memory: 100M + reservations: + cpus: "0.1" + memory: 100M + expose: + - 6379 + healthcheck: + interval: 10s + retries: 3 + start_period: 30s + test: redis-cli + timeout: 1s + image: redis:6.0.9-alpine3.12@sha256:aa31e6d2afc72d2222ed3953587197c324f615861771637a64053f9d99ba4b74 + networks: + - redis + # volums escribe en disco, p openshift + volumes: + - redis:/data + rng: + deploy: + #DaemonSet, es una app q se despliega 1vez por worker + mode: global + placement: + constraints: + - node.role == worker + resources: + limits: + cpus: "0.1" + memory: 100M + reservations: + cpus: "0.1" + memory: 100M + expose: + - 8080 + healthcheck: + interval: 10s + retries: 3 + start_period: 30s + test: wget -q --spider localhost:8080 + timeout: 1s + image: macarenasre/dockercoins:latest-rng + networks: + - rng + # volums escribe en disco, p openshift + webui: + deploy: + #DaemonSet, es una app q se despliega 1vez por worker + mode: replicated + placement: + constraints: + - node.role == worker + resources: + limits: + cpus: "0.1" + memory: 100M + reservations: + cpus: "0.1" + memory: 100M + expose: + - 8080 + healthcheck: + interval: 10s + retries: 3 + start_period: 30s + test: curl -f localhost:8080 + timeout: 1s + image: macarenasre/dockercoins:latest-webui + networks: + - redis + - webui + worker: + deploy: + mode: replicated + placement: + constraints: + - node.role == worker + replicas: 1 + resources: + limits: + cpus: "0.1" + memory: 100M + reservations: + cpus: "0.1" + memory: 100M + healthcheck: + interval: 10s + retries: 3 + start_period: 30s + test: netstat -nt | grep ESTABLISHED | grep -q 6379 + timeout: 1s + image: macarenasre/dockercoins:latest-worker + networks: + - hasher + - redis + - rng + - worker +version: '3.8' +volumes: + redis: + diff --git a/hasher/Dockerfile b/hasher/Dockerfile index 2535124..1b1d22a 100644 --- a/hasher/Dockerfile +++ b/hasher/Dockerfile @@ -1,10 +1,8 @@ -FROM ruby:3-alpine -RUN apk add --update build-base curl -RUN gem install sinatra -RUN gem install thin -ADD hasher.rb / -CMD ["ruby", "hasher.rb"] -EXPOSE 80 -HEALTHCHECK \ - --interval=1s --timeout=2s --retries=3 --start-period=1s \ - CMD curl http://localhost/ || exit 1 +FROM ruby:3.0.0-alpine3.12@sha256:df559e1eb3c1b4884a28caa43ce163425a7f81cf9b7372d33883cf0fea67303f +#ejecutamos todos en la misma linea para optimizar +RUN apk add --update build-base && gem install sinatra && gem install thin +#ADD copia y descomprime - COPY solamente copia +COPY hasher.rb / +ENTRYPOINT ["ruby"] +CMD ["hasher.rb"] +EXPOSE 8080 diff --git a/hasher/hasher.rb b/hasher/hasher.rb index 28a929f..2e5c3f4 100644 --- a/hasher/hasher.rb +++ b/hasher/hasher.rb @@ -3,7 +3,7 @@ require 'socket' set :bind, '0.0.0.0' -set :port, 80 +set :port, 8080 post '/' do # Simulate a bit of delay diff --git a/rng/Dockerfile b/rng/Dockerfile index c63b0e9..bc8a59e 100644 --- a/rng/Dockerfile +++ b/rng/Dockerfile @@ -1,5 +1,7 @@ -FROM python:3-alpine +#ponemos el tag para que quede mas calaro y se pueda buscar el fichero '3.9.1-alpine3.13' +FROM python:3.9.1-alpine3.13@sha256:5beb4823c653c428379bc8b811ef233b7171806e8b10bb6879e7af1ed5bb4093 RUN pip install Flask COPY rng.py / -CMD ["python", "rng.py"] -EXPOSE 80 +ENTRYPOINT ["python"] +CMD ["rng.py"] +EXPOSE 8080 diff --git a/rng/rng.py b/rng/rng.py index d9376c5..3c0a424 100644 --- a/rng/rng.py +++ b/rng/rng.py @@ -28,5 +28,5 @@ def rng(how_many_bytes): if __name__ == "__main__": - app.run(host="0.0.0.0", port=80) + app.run(host="0.0.0.0", port=8080) diff --git a/webui/Dockerfile b/webui/Dockerfile index 5e8c9be..6dfb366 100644 --- a/webui/Dockerfile +++ b/webui/Dockerfile @@ -1,7 +1,9 @@ -FROM node:4-slim -RUN npm install express -RUN npm install redis +FROM node:4-slim@sha256:b5ae41b735cad519ae32cd6eeafbc1191c2d8e9056baf421a17f1c666c2a3753 +RUN npm install express && npm install redis +#AUNQUE SE PUSIERA JUNTO ESTARIAN EN DIFERENTES CAPAS (diferentes rutas no empeoran el rendimiento, la misma ya penaliza mas) +#si en la misma linea creas y borras archivos tambien es optimo (la capa se guarda al final) COPY files/ /files/ COPY webui.js / -CMD ["node", "webui.js"] -EXPOSE 80 +ENTRYPOINT ["node"] +CMD ["webui.js"] +EXPOSE 8080 diff --git a/webui/webui.js b/webui/webui.js index 5b2bdc5..ecc346b 100644 --- a/webui/webui.js +++ b/webui/webui.js @@ -26,7 +26,7 @@ app.get('/json', function (req, res) { app.use(express.static('files')); -var server = app.listen(80, function () { - console.log('WEBUI running on port 80'); +var server = app.listen(8080, function () { + console.log('WEBUI running on port 8080'); }); diff --git a/worker/Dockerfile b/worker/Dockerfile index 5e2264c..e49ade4 100644 --- a/worker/Dockerfile +++ b/worker/Dockerfile @@ -1,5 +1,5 @@ -FROM python:3-alpine -RUN pip install redis -RUN pip install requests +FROM python:3.9.1-alpine3.13@sha256:5beb4823c653c428379bc8b811ef233b7171806e8b10bb6879e7af1ed5bb4093 +RUN pip install redis && pip install requests COPY worker.py / -CMD ["python", "worker.py"] +ENTRYPOINT ["python"] +CMD ["worker.py"] diff --git a/worker/worker.py b/worker/worker.py index 01bfade..e5a712b 100644 --- a/worker/worker.py +++ b/worker/worker.py @@ -18,12 +18,12 @@ def get_random_bytes(): - r = requests.get("http://rng/32") + r = requests.get("http://rng:8080/32") return r.content def hash_bytes(data): - r = requests.post("http://hasher/", + r = requests.post("http://hasher:8080/", data=data, headers={"Content-Type": "application/octet-stream"}) hex_hash = r.text