├── docker ├── demo │ ├── README.md │ ├── janustlsdemo │ ├── Dockerfile │ ├── apitlspatch │ ├── privkey.pem │ └── fullchain.pem ├── api │ ├── README.md │ ├── helloworld.py │ ├── run.sh │ ├── Dockerfile │ ├── curl.py │ └── janus_url_generator.py ├── rtp-init │ ├── README.md │ ├── Dockerfile │ └── run.sh ├── nginx │ ├── run.sh │ ├── README.md │ ├── Dockerfile │ ├── janus.tpl │ ├── privkey.pem │ └── fullchain.pem └── janus │ ├── README.md │ ├── run.sh │ └── Dockerfile ├── README.md ├── compose ├── ecs-params.yml ├── docker-compose-janus.yml ├── README.md ├── janus_cluster.sh └── docker-compose-core.yml └── cluster ├── README.md └── janus-ecs-ec2-spot-fleet.yaml /docker/demo/README.md: -------------------------------------------------------------------------------- 1 | # janus-cluster 2 | ## Build 3 | 4 | docker build -t demo:v0.1 . 5 | -------------------------------------------------------------------------------- /docker/api/README.md: -------------------------------------------------------------------------------- 1 | # janus-cluster 2 | ## Build 3 | 4 | docker build -t api:v0.1 . 5 | 6 | -------------------------------------------------------------------------------- /docker/rtp-init/README.md: -------------------------------------------------------------------------------- 1 | # janus-cluster 2 | ## Build 3 | 4 | docker build -t rtp-init:v0.1 . 5 | -------------------------------------------------------------------------------- /docker/api/helloworld.py: -------------------------------------------------------------------------------- 1 | from klein import resource, route 2 | 3 | @route('/') 4 | def hello(request): 5 | return "Hello, world!" 6 | -------------------------------------------------------------------------------- /docker/api/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | pip install klein requests 4 | cd / && PYTHONPATH=. twistd -n web --class=janus_url_generator.resource 5 | -------------------------------------------------------------------------------- /docker/rtp-init/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | RUN set -x \ 4 | && apt-get update && apt-get install -y curl jq 5 | 6 | COPY run.sh /run.sh 7 | 8 | CMD /run.sh 9 | -------------------------------------------------------------------------------- /docker/nginx/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Run nginx from consul-temlate 4 | /etc/init.d/nginx start 5 | consul-template -consul-addr=consul:8500 -template "/janus.tpl:/etc/nginx/sites-enabled/default:/etc/init.d/nginx reload" -log-level debug 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # janus-cluster 2 | 3 | Set of tools to deploy Janus cluster locally or on AWS as ECS. 4 | 5 | Ubuntu 18 and docker.io are necesary 6 | 7 | Build docker images before running docker compose script to setup the Janus POD. 8 | 9 | 10 | -------------------------------------------------------------------------------- /compose/ecs-params.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | task_definition: 3 | services: 4 | registrator: 5 | cpu_shares: 100 6 | mem_limit: 524288000 7 | janus: 8 | cpu_shares: 100 9 | mem_limit: 524288000 10 | consul: 11 | cpu_shares: 100 12 | mem_limit: 524288000 13 | -------------------------------------------------------------------------------- /docker/api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | RUN set -x \ 4 | && apt-get update && apt-get install -y nginx wget python virtualenv vim curl python-pip python-twisted 5 | 6 | COPY run.sh /run.sh 7 | COPY helloworld.py /helloworld.py 8 | COPY janus_url_generator.py /janus_url_generator.py 9 | 10 | EXPOSE 8080 11 | 12 | CMD /run.sh 13 | -------------------------------------------------------------------------------- /compose/docker-compose-janus.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | janus: 4 | #image: 207142521427.dkr.ecr.us-east-1.amazonaws.com/janus 5 | image: janus-gateway:v0.1 6 | networks: 7 | - compose_some-net 8 | deploy: 9 | mode: replicated 10 | replicas: 1 11 | labels: 12 | - "com.example.description=janus-${PROJECT}" 13 | ports: 14 | - 80 15 | - 7088 16 | 17 | networks: 18 | compose_some-net: 19 | external: true 20 | -------------------------------------------------------------------------------- /docker/api/curl.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import pprint 4 | import random 5 | 6 | 7 | response = requests.get('http://localhost:8500/v1/catalog/service/janus-gateway-80') 8 | 9 | input_dict = json.loads(response.text) 10 | 11 | endpoint_index_len = len(input_dict) 12 | 13 | print (endpoint_index_len-1) 14 | 15 | some_endpoint_port_index = (random.randint(0, endpoint_index_len)-1) 16 | 17 | print ("https://janus.webcall.ninjapbx.com/janus-gateway-80janus_"+json.dumps(input_dict[some_endpoint_port_index][u'ServicePort'])) 18 | -------------------------------------------------------------------------------- /docker/janus/README.md: -------------------------------------------------------------------------------- 1 | # janus-cluster 2 | ## Build 3 | ```bash 4 | docker build -t janus-gateway:v0.1 . 5 | ``` 6 | ## Upload janus container to AWS container registry 7 | # Required once 8 | ```bash 9 | aws ecr create-repository --repository-name janus 10 | ``` 11 | # Pushing every release 12 | ```bash 13 | docker tag janus-gateway:v0.01 207142521427.dkr.ecr.us-east-1.amazonaws.com/janus 14 | aws ecr get-login --no-include-email 15 | ``` 16 | # Copy from previous command 17 | ```bash 18 | docker login -u AWS -p eyJwY... 19 | docker push 207142521427.dkr.ecr.us-east-1.amazonaws.com/janus 20 | ``` 21 | -------------------------------------------------------------------------------- /docker/api/janus_url_generator.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import pprint 4 | import random 5 | from klein import resource, route 6 | 7 | @route('/') 8 | def hello(request): 9 | return 'I am the root page!' 10 | 11 | 12 | @route('/v0.1/janus_url') 13 | def janus_url(request): 14 | response = requests.get('http://consul:8500/v1/catalog/service/janus-gateway-80') 15 | input_dict = json.loads(response.text) 16 | endpoint_index_len = len(input_dict) 17 | some_endpoint_port_index = (random.randint(0, endpoint_index_len-1)) 18 | return ("https://janus.webcall.ninjapbx.com/janus-gateway-80janus_"+json.dumps(input_dict[some_endpoint_port_index][u'ServicePort'])) 19 | -------------------------------------------------------------------------------- /compose/README.md: -------------------------------------------------------------------------------- 1 | # running on aws 2 | 3 | # install ecs cli tool 4 | 5 | sudo curl -o /usr/local/bin/ecs-cli https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-linux-amd64-latest 6 | 7 | sudo chmod +x /usr/local/bin/ecs-cli 8 | 9 | # Configure cluster 10 | 11 | ecs-cli configure --cluster janus-ecsCluster-DDDDD111111 --region us-east-1 12 | 13 | # Deploy on the aws cloud 14 | 15 | ecs-cli compose --verbose up --cluster janus-ecsCluster-DDDDD11111 16 | 17 | ecs-cli compose up --cluster janus-ecsCluster-DDDDDD1111 18 | 19 | ecs-cli ps 20 | 21 | ecs-cli down 22 | 23 | # deploy on local docker host acting as swarm local 24 | 25 | sudo docker-compose -f docker-compose-core.yml up -d 26 | sudo bash 27 | -------------------------------------------------------------------------------- /docker/nginx/README.md: -------------------------------------------------------------------------------- 1 | # janus-cluster 2 | ## Build 3 | 4 | docker build -t nginx-lb:v0.1 . 5 | 6 | 7 | ## TLS Cert issusing 8 | 9 | wget https://dl.eff.org/certbot-auto 10 | chmod a+x certbot-auto 11 | 12 | # How to get single cert for subdmain domain 13 | # Non interactive 14 | sudo ./certbot-auto certonly --manual -d *.webcall.ninjapbx.com -m cristian.paul@prexenx.com --agree-tos 15 | - Congratulations! Your certificate and chain have been saved at: 16 | /etc/letsencrypt/live/webcall.ninjapbx.com/fullchain.pem 17 | Your key file has been saved at: 18 | /etc/letsencrypt/live/webcall.ninjapbx.com/privkey.pem 19 | 20 | 21 | # Backup to S3 22 | aws s3 cp fullchain.pem s3://webcall-ninjapbx-certbot/ 23 | aws s3 cp privkey.pem s3://webcall-ninjapbx-certbot/ 24 | -------------------------------------------------------------------------------- /docker/rtp-init/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Run rtp seats initialization 4 | for i in $(seq 20000 20100); do curl -s --request PUT --data "avaliable" http://consul:8500/v1/kv/rtp/$i; done 5 | while true; do echo "I'm done here, but cant die"; sleep 1d; done 6 | 7 | # Do not run this or will kill consul, needs to be done as transaction 8 | #while true 9 | #do 10 | # avaliable=0 11 | # busy=0 12 | # for i in $(seq 20000 20100) 13 | # do 14 | # seat=$(curl -s http://consul:8500/v1/kv/rtp/$i | jq .[].Value | base64 -di) 15 | # if [ "$seat" == "avaliable" ] 16 | # then 17 | # avaliable=$((avaliable+1)) 18 | # fi 19 | # done 20 | # 21 | # echo -n aval:$avaliable 22 | # echo busy:$busy 23 | # sleep 5 24 | #done 25 | -------------------------------------------------------------------------------- /docker/demo/janustlsdemo: -------------------------------------------------------------------------------- 1 | server { 2 | server_name janus.webcall.ninjapbx.com; 3 | ssl_certificate /etc/letsencrypt/live/webcall.ninjapbx.com/fullchain.pem; 4 | ssl_certificate_key /etc/letsencrypt/live/webcall.ninjapbx.com/privkey.pem; 5 | 6 | ssl_dhparam /etc/nginx/ssl/dhparams.pem; 7 | 8 | listen 443; 9 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; 10 | ssl on; 11 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 12 | ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; 13 | ssl_prefer_server_ciphers on; 14 | ssl_session_cache shared:SSL:10m; 15 | root /var/www/html/janus-gateway/html/; 16 | location / { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docker/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | RUN set -x \ 4 | && apt-get update && apt-get install -y nginx wget python virtualenv vim curl\ 5 | && wget https://releases.hashicorp.com/consul-template/0.19.5/consul-template_0.19.5_linux_amd64.tgz \ 6 | && tar xfv consul-template_0.19.5_linux_amd64.tgz \ 7 | && mv consul-template /usr/bin/ \ 8 | && mkdir -p /etc/nginx/ssl/ \ 9 | && mkdir -p /etc/letsencrypt/live/webcall.ninjapbx.com/ \ 10 | && openssl dhparam -out /etc/nginx/ssl/dhparams.pem 2048 11 | 12 | COPY run.sh /run.sh 13 | COPY janus.tpl /janus.tpl 14 | COPY fullchain.pem /etc/letsencrypt/live/webcall.ninjapbx.com/fullchain.pem 15 | COPY privkey.pem /etc/letsencrypt/live/webcall.ninjapbx.com/privkey.pem 16 | 17 | EXPOSE 80 18 | EXPOSE 443 19 | 20 | CMD /run.sh 21 | -------------------------------------------------------------------------------- /compose/janus_cluster.sh: -------------------------------------------------------------------------------- 1 | export read_only capacity=$(seq 1 3) 2 | export read_only max_capacity=$(seq 1 10) 3 | 4 | if [ "$1" == "down" ]; then 5 | for i in $capacity; do export PROJECT=myproj_${i} && docker-compose -p $PROJECT -f docker-compose-janus.yml down; done 6 | docker-compose -f docker-compose-core.yml down 7 | docker network prune -f 8 | docker container prune -f 9 | fi 10 | 11 | if [ "$1" == "up" ]; then 12 | docker-compose -f docker-compose-core.yml up -d 13 | for i in $capacity; do export PROJECT=myproj_${i} && docker-compose -p $PROJECT -f docker-compose-janus.yml up -d ; done 14 | fi 15 | 16 | if [ "$1" == "update" ]; then 17 | docker-compose -f docker-compose-core.yml up -d 18 | for i in $max_capacity; do export PROJECT=myproj_${i} && docker-compose -p $PROJECT -f docker-compose-janus.yml down; done 19 | for i in $capacity; do export PROJECT=myproj_${i} && docker-compose -p $PROJECT -f docker-compose-janus.yml up -d ; done 20 | fi 21 | -------------------------------------------------------------------------------- /docker/janus/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Enable admin api 4 | sed -i "s/admin_http = false/admin_http = true/g" /opt/janus/etc/janus/janus.transport.http.jcfg 5 | 6 | myip=$(curl -4 ifconfig.co/ip) 7 | sed -i "s/#stun_server/stun_server/g" /opt/janus/etc/janus/janus.jcfg 8 | sed -i "s/#stun_port/stun_port/g" /opt/janus/etc/janus/janus.jcfg 9 | sed -i "s/#rtp_port_range/rtp_port_range/g" /opt/janus/etc/janus/janus.jcfg 10 | sed -i "s/#nat_1_1_mapping = 1.2.3.4/nat_1_1_mapping = $myip/g" /opt/janus/etc/janus/janus.jcfg 11 | 12 | #Set RTP port 13 | sed -i "s/20000-40000/20000/g" /opt/janus/etc/janus/janus.* 14 | 15 | #Run with admin api enabled 16 | screen -S janus -d -m 17 | screen -r janus -X stuff $'/opt/janus/bin/janus -C /opt/janus/etc/janus/janus.jcfg -A -L /tmp/janus.log\n' 18 | # Get your self a Token 19 | http POST localhost:7088/admin/ admin_secret=janusoverlord transaction=FromLocalhost janus=add_token token=mytoken --ignore-stdin 20 | tail -F /tmp/janus.log 21 | -------------------------------------------------------------------------------- /docker/demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | RUN set -x \ 4 | && apt-get update && apt-get install -y nginx wget python vim git\ 5 | && cd /var/www/html/ \ 6 | && git clone https://github.com/meetecho/janus-gateway.git \ 7 | && mkdir -p /etc/nginx/ssl/ \ 8 | && mkdir -p /etc/letsencrypt/live/webcall.ninjapbx.com/ \ 9 | && openssl dhparam -out /etc/nginx/ssl/dhparams.pem 2048 10 | 11 | # forward request and error logs to docker log collector 12 | RUN ln -sf /dev/stdout /var/log/nginx/access.log \ 13 | && ln -sf /dev/stderr /var/log/nginx/error.log 14 | 15 | # Basic https site 16 | COPY janustlsdemo /etc/nginx/sites-enabled/janustlsdemo 17 | 18 | COPY fullchain.pem /etc/letsencrypt/live/webcall.ninjapbx.com/fullchain.pem 19 | COPY privkey.pem /etc/letsencrypt/live/webcall.ninjapbx.com/privkey.pem 20 | COPY apitlspatch /var/www/html/janus-gateway/html/apitlspatch 21 | 22 | RUN set -x \ 23 | && cd /var/www/html/janus-gateway/html \ 24 | && git apply apitlspatch 25 | 26 | EXPOSE 443 27 | 28 | STOPSIGNAL SIGTERM 29 | 30 | CMD ["nginx", "-g", "daemon off;"] 31 | -------------------------------------------------------------------------------- /docker/nginx/janus.tpl: -------------------------------------------------------------------------------- 1 | server { 2 | server_name janus.webcall.ninjapbx.com; 3 | 4 | ssl_certificate /etc/letsencrypt/live/webcall.ninjapbx.com/fullchain.pem; 5 | ssl_certificate_key /etc/letsencrypt/live/webcall.ninjapbx.com/privkey.pem; 6 | # Ensure this line points to your dhparams file 7 | ssl_dhparam /etc/nginx/ssl/dhparams.pem; 8 | 9 | # These shouldn't need to be changed 10 | listen 443; 11 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; 12 | ssl on; 13 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 14 | ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; 15 | ssl_prefer_server_ciphers on; 16 | ssl_session_cache shared:SSL:10m; 17 | 18 | proxy_buffering off; 19 | {{range services}} {{$name := .Name}} {{$service := service .Name}} 20 | 21 | 22 | {{range $service}}location /{{$name}}janus_{{.Port}} { 23 | proxy_pass http://{{.Address}}:80/janus; 24 | } 25 | 26 | {{else}}# something missing {{end}} 27 | {{end}} 28 | 29 | location /stub_status { 30 | stub_status; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /compose/docker-compose-core.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | consul: 4 | image: consul 5 | container_name: consul 6 | networks: 7 | - some-net 8 | ports: 9 | - 8500:8500 #Needs to expose consult to be reachable from registrator 10 | 11 | registrator: 12 | image: gliderlabs/registrator:latest 13 | container_name: registrator 14 | networks: 15 | - some-net 16 | command: -cleanup -deregister="always" -internal=false -resync=10 -ttl=6 -ttl-refresh=5 -retry-attempts=-1 consul://consul:8500 17 | volumes: 18 | - /var/run/docker.sock:/tmp/docker.sock 19 | 20 | loadbalancer: 21 | image: nginx-lb:v0.1 22 | networks: 23 | - some-net 24 | ports: 25 | - 80:80 26 | - 443:443 27 | 28 | rtp-init: 29 | image: rtp-init:v0.1 30 | container_name: rtp-init 31 | networks: 32 | - some-net 33 | 34 | demo: 35 | image: demo:v0.1 36 | container_name: demo 37 | networks: 38 | - some-net 39 | ports: 40 | - 4443:443 41 | 42 | api: 43 | image: api:v0.1 44 | container_name: api 45 | networks: 46 | - some-net 47 | ports: 48 | - 8080:8080 49 | 50 | 51 | networks: 52 | some-net: 53 | driver: bridge 54 | -------------------------------------------------------------------------------- /docker/demo/apitlspatch: -------------------------------------------------------------------------------- 1 | From 355c585ffdbd8abf7d0225d86e240785f3fe567c Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Cristian=20Paul=20Pe=C3=B1aranda=20=20Rojas?= 3 | 4 | Date: Wed, 7 Nov 2018 05:11:32 +0000 5 | Subject: [PATCH] janus default token for demo 6 | 7 | --- 8 | html/echotest.js | 4 ++-- 9 | 1 file changed, 2 insertions(+), 2 deletions(-) 10 | 11 | diff --git a/html/echotest.js b/html/echotest.js 12 | index 4036e851..b3559bed 100644 13 | --- a/html/echotest.js 14 | +++ b/html/echotest.js 15 | @@ -46,7 +46,7 @@ var server = null; 16 | if(window.location.protocol === 'http:') 17 | server = "http://" + window.location.hostname + ":8088/janus"; 18 | else 19 | - server = "https://" + window.location.hostname + ":8089/janus"; 20 | + server = "https://" + window.location.hostname + "/janus-gateway-7088janus_32834"; 21 | 22 | var janus = null; 23 | var echotest = null; 24 | @@ -82,7 +82,7 @@ $(document).ready(function() { 25 | // iceServers: [{urls: "turn:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}], 26 | // iceServers: [{urls: "turns:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}], 27 | // Should the Janus API require authentication, you can specify either the API secret or user token here too 28 | - // token: "mytoken", 29 | + token: "mytoken", 30 | // or 31 | // apisecret: "serversecret", 32 | success: function() { 33 | -- 34 | 2.17.1 35 | 36 | -------------------------------------------------------------------------------- /docker/demo/privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDvEQVEn69KiiQi 3 | bs8UeH9TinfUgqqhEYez7vYpnh7W7YjnVDKy2tjaFNcHXxj/Kt/9Z2Od+dI0Gebo 4 | Lv25QnnJU9J+2sBWteb27c3ze96y/f5G2r9a6FiP2ZCemBZ/ipZ3kdOmlb8154vf 5 | Y4p6TwgOFiMWqP4f+SKJFIGuIMc5l2ItyfVi8E6GMRgUY3lQGEtZBYwyBJVKiuZ7 6 | 7BCKQv3qx9BO2CEodt0KkEsL61tDc75QzhtweILAix/tDjd+yBgTcedEjmIIAzRH 7 | HwWjcZIdgbJwnMfeGR8djYB7TLl6tVGpmvVRGVPoMoV7BGfEJ+1GsjbSjvQBZRYz 8 | tupMLXmnAgMBAAECggEBAOFRYW20MzpFyJjLZ1Eb4KWUNCyOmtMD+qqT5l6DMP3R 9 | Et80dDQuH4QrcB76ekzE1Ce5ciJKetuwLflXkLsy9CXUYug8tFsFRpIkv59keBir 10 | WyTcts2vfwjVPYC8RzgeHoLDZn/zUywy95mr77AnHKhqJNgOnrTz0qDwOukq65pS 11 | SUtGE3aagCHsFfodMvQlIpK2YCqGUhx+RnlUWM9S0q1SK5EwyDvQWcUWFzXBvTic 12 | Ra3CNCZAQi/RjyPRpO5iK2yZrzUK+QYbW+TCwb6IG6jKrA5SxpZX/Ex9peEVK7MB 13 | h//J8BWdAuM4mexXgPLtqP7/NyQBEep5miBQisEOc4ECgYEA+1BW2KYeaTnN60Bo 14 | Qb+AlhcFw+bua1vfLpWINFJl6oPk/1ZLhWy8CLjLJELLWjjRO0uNMp8UgOCBbpuy 15 | KAJcDK5u1iXepR32eOWosSxCGtnK1hsZWzSgZzkvaBbasbp1wiZ3wFnLWbFsdagx 16 | voROdoom10/hHXBv+zxctfRZ6W8CgYEA84Y3zQKn01etHTgIsM/awWTGtVt42dke 17 | GGtvSlCuv4QLIXXlMjX5ibpx+kYe1M0fpp87ZchBIAOQ4BQ/zuW68valhGBkrhbC 18 | a5so6oaYbgKaKQ28GfcpqaZB+Al8KALnayreCxdpdkA1chyOgMFloet+L0Exxpp1 19 | bzVgdVKmJ0kCgYEAzRgnh+8p6l4OOur5Ko8KdXKcdd/Eu0DixrWpzmlgWx8Ah5D5 20 | WQ3/9m44+oK4Sg0MVAO4W5OPvA18E7RklFo4nPDN615EcSQevVNPdCfWWutaqZi7 21 | /L7aGOOGWMAuAdVVvPh/yi590dkF1o9I6V44Wm0sfZLm+IuGF9aPIr8jkWkCgYEA 22 | jPHy2/IchkKpjE7BIOy8dNBJ/e9aS+PQ+ls8B2wZJ/lZo90jcWMx8Vf63dq1v36V 23 | Qg/JBgjYQJovwLGXmLz37eV5ONu9idDcaAFethZ+pLVW2kn7w598+paiederh1De 24 | 9fTSnOLJBEr3Y/tJMxY8J3IwD1ORZpxBOcNP97eFORkCgYBpGjQqAZdoLsa/UOe6 25 | UaShdHfH4EoCAxkSzTvj+zts8GZnoYr0vTUb/mSRGyUMzFPLG39LM9r8gVBHuSTY 26 | 2RZcCYrLIbzXTc9XQYUORDjqN3qxIbrUPayVBgBNA6+oBVFLd0cKCi5Wbdi5d4EV 27 | fD5EzYX1SkTyGTvBXQJZZ/+49w== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /docker/nginx/privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDvEQVEn69KiiQi 3 | bs8UeH9TinfUgqqhEYez7vYpnh7W7YjnVDKy2tjaFNcHXxj/Kt/9Z2Od+dI0Gebo 4 | Lv25QnnJU9J+2sBWteb27c3ze96y/f5G2r9a6FiP2ZCemBZ/ipZ3kdOmlb8154vf 5 | Y4p6TwgOFiMWqP4f+SKJFIGuIMc5l2ItyfVi8E6GMRgUY3lQGEtZBYwyBJVKiuZ7 6 | 7BCKQv3qx9BO2CEodt0KkEsL61tDc75QzhtweILAix/tDjd+yBgTcedEjmIIAzRH 7 | HwWjcZIdgbJwnMfeGR8djYB7TLl6tVGpmvVRGVPoMoV7BGfEJ+1GsjbSjvQBZRYz 8 | tupMLXmnAgMBAAECggEBAOFRYW20MzpFyJjLZ1Eb4KWUNCyOmtMD+qqT5l6DMP3R 9 | Et80dDQuH4QrcB76ekzE1Ce5ciJKetuwLflXkLsy9CXUYug8tFsFRpIkv59keBir 10 | WyTcts2vfwjVPYC8RzgeHoLDZn/zUywy95mr77AnHKhqJNgOnrTz0qDwOukq65pS 11 | SUtGE3aagCHsFfodMvQlIpK2YCqGUhx+RnlUWM9S0q1SK5EwyDvQWcUWFzXBvTic 12 | Ra3CNCZAQi/RjyPRpO5iK2yZrzUK+QYbW+TCwb6IG6jKrA5SxpZX/Ex9peEVK7MB 13 | h//J8BWdAuM4mexXgPLtqP7/NyQBEep5miBQisEOc4ECgYEA+1BW2KYeaTnN60Bo 14 | Qb+AlhcFw+bua1vfLpWINFJl6oPk/1ZLhWy8CLjLJELLWjjRO0uNMp8UgOCBbpuy 15 | KAJcDK5u1iXepR32eOWosSxCGtnK1hsZWzSgZzkvaBbasbp1wiZ3wFnLWbFsdagx 16 | voROdoom10/hHXBv+zxctfRZ6W8CgYEA84Y3zQKn01etHTgIsM/awWTGtVt42dke 17 | GGtvSlCuv4QLIXXlMjX5ibpx+kYe1M0fpp87ZchBIAOQ4BQ/zuW68valhGBkrhbC 18 | a5so6oaYbgKaKQ28GfcpqaZB+Al8KALnayreCxdpdkA1chyOgMFloet+L0Exxpp1 19 | bzVgdVKmJ0kCgYEAzRgnh+8p6l4OOur5Ko8KdXKcdd/Eu0DixrWpzmlgWx8Ah5D5 20 | WQ3/9m44+oK4Sg0MVAO4W5OPvA18E7RklFo4nPDN615EcSQevVNPdCfWWutaqZi7 21 | /L7aGOOGWMAuAdVVvPh/yi590dkF1o9I6V44Wm0sfZLm+IuGF9aPIr8jkWkCgYEA 22 | jPHy2/IchkKpjE7BIOy8dNBJ/e9aS+PQ+ls8B2wZJ/lZo90jcWMx8Vf63dq1v36V 23 | Qg/JBgjYQJovwLGXmLz37eV5ONu9idDcaAFethZ+pLVW2kn7w598+paiederh1De 24 | 9fTSnOLJBEr3Y/tJMxY8J3IwD1ORZpxBOcNP97eFORkCgYBpGjQqAZdoLsa/UOe6 25 | UaShdHfH4EoCAxkSzTvj+zts8GZnoYr0vTUb/mSRGyUMzFPLG39LM9r8gVBHuSTY 26 | 2RZcCYrLIbzXTc9XQYUORDjqN3qxIbrUPayVBgBNA6+oBVFLd0cKCi5Wbdi5d4EV 27 | fD5EzYX1SkTyGTvBXQJZZ/+49w== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /cluster/README.md: -------------------------------------------------------------------------------- 1 | This is the compute cluster for ECS/Docker, you can use it to deploy an cluster on spot instances and save upto 90% in costs or balance the spot fleet request in order to have both on-demand and spot prices. 2 | 3 | This cluster eventually needs to acepts input from the awslabs ecs spot lambda function that tracks the spot price status. 4 | 5 | # Looking around 6 | ```bash 7 | aws cloudformation list-stacks 8 | 9 | aws cloudformation list-stacks --output text 10 | ``` 11 | 12 | # Create stack 13 | ```bash 14 | aws cloudformation create-stack --stack-name janus --template-body file://janus-ecs-ec2-spot-fleet.yaml --capabilities CAPABILITY_NAMED_IAM --parameters ParameterKey=keyName,ParameterValue=ecs22 15 | ``` 16 | # Update stack 17 | ```bash 18 | aws cloudformation update-stack --stack-name janus --template-body file://janus-ecs-ec2-spot-fleet.yaml --parameters ParameterKey=keyName,ParameterValue=ecs22 --capabilities CAPABILITY_NAMED_IAM 19 | ``` 20 | 21 | # Delete when done for testing 22 | ```bash 23 | aws cloudformation delete-stack --stack-name janus 24 | ``` 25 | # Deploy locally with docker + swarm local 26 | 27 | ```bash 28 | docker-compose up -d --scale janus=3 29 | 30 | docker-compose ps 31 | ``` 32 | 33 | Take it down: 34 | 35 | ```bash 36 | docker-compose down 37 | ``` 38 | 39 | # Deploy remotelly with ecs-cli 40 | 41 | Required once and or if your ecs cluster name changes 42 | ```bash 43 | ecs-cli configure -c janus-ecsCluster-XXXXXXXXXX -r us-east-1 44 | 45 | ecs-cli compose --verbose up --cluster janus-ecsCluster-XXXXXXXXX 46 | 47 | ecs-cli compose down --cluster janus-ecsCluster-XXXXXXXX 48 | ``` 49 | # Service discovery 50 | Janus micro service gets register on consul automatically, it can be visited via UI port 8500 51 | ```bash 52 | curl -s http://localhost:8500/v1/catalog/service/janus-gateway-8088 53 | curl -s http://localhost:8500/v1/catalog/service/janus-gateway-8088 | grep port -i 54 | ``` 55 | # Load balancer 56 | 57 | UI It is avalaible on port 8080 58 | 59 | Traefik automatically discovers and registers backends to load balancer 60 | -------------------------------------------------------------------------------- /docker/janus/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | RUN set -x \ 4 | && apt-get update && apt-get install -y cmake build-essential aptitude git wget golang\ 5 | && aptitude install -y libmicrohttpd-dev libjansson-dev libnice-dev libconfig-dev \ 6 | libssl-dev libsofia-sip-ua-dev libglib2.0-dev libopus-dev libogg-dev \ 7 | libcurl4-openssl-dev liblua5.3-dev pkg-config gengetopt libtool automake curl jq httpie vim screen meson 8 | RUN set -x \ 9 | && cd \ 10 | && wget https://github.com/cisco/libsrtp/archive/v2.2.0.tar.gz \ 11 | && tar xfv v2.2.0.tar.gz \ 12 | && cd libsrtp-2.2.0/ \ 13 | && ./configure --prefix=/usr --enable-openssl \ 14 | && make shared_library && make install 15 | RUN set -x \ 16 | && git clone https://boringssl.googlesource.com/boringssl \ 17 | && cd boringssl \ 18 | && sed -i s/" -Werror"//g CMakeLists.txt \ 19 | && mkdir -p build \ 20 | && cd build \ 21 | && cmake -DCMAKE_CXX_FLAGS="-lrt" .. \ 22 | && make \ 23 | && cd .. \ 24 | && mkdir -p /opt/boringssl \ 25 | && cp -R include /opt/boringssl/ \ 26 | && mkdir -p /opt/boringssl/lib \ 27 | && cp build/ssl/libssl.a /opt/boringssl/lib/ \ 28 | && cp build/crypto/libcrypto.a /opt/boringssl/lib/ 29 | 30 | RUN set -x \ 31 | && git clone https://github.com/sctplab/usrsctp \ 32 | && cd usrsctp \ 33 | && ./bootstrap \ 34 | && ./configure --prefix=/usr && make && make install 35 | 36 | RUN set -x \ 37 | && git clone https://libwebsockets.org/repo/libwebsockets \ 38 | && cd libwebsockets \ 39 | && mkdir build \ 40 | && cd build \ 41 | && cmake -DLWS_MAX_SMP=1 -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_C_FLAGS="-fpic" .. \ 42 | && make && make install 43 | 44 | RUN set -x \ 45 | && apt-get -y remove libnice* \ 46 | && echo "deb-src http://deb.debian.org/debian bullseye main" >> /etc/apt/sources.list \ 47 | && apt-get update \ 48 | && apt-get build-dep libnice -y \ 49 | && git clone https://gitlab.freedesktop.org/libnice/libnice \ 50 | && cd libnice \ 51 | && meson --prefix=/usr build && ninja -C build && ninja -C build install 52 | 53 | RUN set -x \ 54 | && git clone https://github.com/meetecho/janus-gateway.git \ 55 | && cd janus-gateway \ 56 | && sh autogen.sh \ 57 | && ./configure --prefix=/opt/janus \ 58 | && make \ 59 | && make install \ 60 | && make configs 61 | 62 | RUN set -x \ 63 | && rm -rf /libwebsockets \ 64 | && rm -rf /janus-gateway \ 65 | && rm -rf /boringssl 66 | 67 | COPY run.sh /run.sh 68 | 69 | EXPOSE 80 7088 70 | 71 | CMD /bin/bash /run.sh 72 | -------------------------------------------------------------------------------- /docker/demo/fullchain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGFzCCBP+gAwIBAgISA2h80CEHY+aMx+b+3FuZcMl6MA0GCSqGSIb3DQEBCwUA 3 | MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD 4 | ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMDMwMzQxNDNaFw0x 5 | OTAyMDEwMzQxNDNaMCExHzAdBgNVBAMMFioud2ViY2FsbC5uaW5qYXBieC5jb20w 6 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvEQVEn69KiiQibs8UeH9T 7 | infUgqqhEYez7vYpnh7W7YjnVDKy2tjaFNcHXxj/Kt/9Z2Od+dI0GeboLv25QnnJ 8 | U9J+2sBWteb27c3ze96y/f5G2r9a6FiP2ZCemBZ/ipZ3kdOmlb8154vfY4p6TwgO 9 | FiMWqP4f+SKJFIGuIMc5l2ItyfVi8E6GMRgUY3lQGEtZBYwyBJVKiuZ77BCKQv3q 10 | x9BO2CEodt0KkEsL61tDc75QzhtweILAix/tDjd+yBgTcedEjmIIAzRHHwWjcZId 11 | gbJwnMfeGR8djYB7TLl6tVGpmvVRGVPoMoV7BGfEJ+1GsjbSjvQBZRYztupMLXmn 12 | AgMBAAGjggMeMIIDGjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH 13 | AwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFz6osqMFxHN4QmV 14 | 5eKNeZJbHiAaMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsG 15 | AQUFBwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNl 16 | bmNyeXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNl 17 | bmNyeXB0Lm9yZy8wIQYDVR0RBBowGIIWKi53ZWJjYWxsLm5pbmphcGJ4LmNvbTCB 18 | /gYDVR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYB 19 | BQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCB 20 | ngyBm1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkg 21 | UmVseWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUg 22 | Q2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQu 23 | b3JnL3JlcG9zaXRvcnkvMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAKTxRllTI 24 | OWW6qlD8WAfUt2+/WHopctykwwz05UVH9HgAAAFm1+B3kQAABAMASDBGAiEAzn7W 25 | llkg4S8htNUBeyoytAAmrXaUFsokMaTVuZyZAC8CIQDSvVhXIxk/ezoXH8GHyXVI 26 | KRVBPwoFPz3CXLlNPBLbDwB1AHR+2oMxrTMQkSGcziVPQnDCv/1eQiAIxjc1eeYQ 27 | e8xWAAABZtfgeV4AAAQDAEYwRAIgbo9wO6iDwyvtta3DcWCW8yLS/+ilR3oPvqgg 28 | Mw8v3q8CIDysoy6FoBGmCc2B2jVIdxyWPGIfRt1Z2IUCxHT6m4PeMA0GCSqGSIb3 29 | DQEBCwUAA4IBAQAkzhZpy1QyMmvIIhfNyi+tqDD/4b3wwIn7zOfkZkDPleTGO9/v 30 | cPBJst2BjV7UgZ6m+naxXIeq7JtaI0m/mx0ISnt8IcwhmU1ZOSKLJoUllIsEeIwW 31 | sIe2iYOHTxiTj0Yw2DciuHqokKYBANdNJSI3RNtlVqIBi80/ykM8F4Vrb3CukZFF 32 | NWAJ8GeN6eVo811Lgl3RagNKZAllBkS50Yg+AhPur88o35QAidt4NK+Inhl0abXd 33 | Lb+ylH4hwDb/KE707h3JHcMTrFLomjCDr4zLdmTRtypeKR9xRSLt8jBw7zXnZYgI 34 | hKmIEYFib9vOrNVoOkmIiBuARPMiVvNhq1UK 35 | -----END CERTIFICATE----- 36 | -----BEGIN CERTIFICATE----- 37 | MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ 38 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 39 | DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow 40 | SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT 41 | GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC 42 | AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF 43 | q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 44 | SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 45 | Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA 46 | a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj 47 | /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T 48 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG 49 | CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv 50 | bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k 51 | c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw 52 | VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC 53 | ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz 54 | MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu 55 | Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF 56 | AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo 57 | uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ 58 | wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu 59 | X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG 60 | PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 61 | KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== 62 | -----END CERTIFICATE----- 63 | -------------------------------------------------------------------------------- /docker/nginx/fullchain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGFzCCBP+gAwIBAgISA2h80CEHY+aMx+b+3FuZcMl6MA0GCSqGSIb3DQEBCwUA 3 | MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD 4 | ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMDMwMzQxNDNaFw0x 5 | OTAyMDEwMzQxNDNaMCExHzAdBgNVBAMMFioud2ViY2FsbC5uaW5qYXBieC5jb20w 6 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvEQVEn69KiiQibs8UeH9T 7 | infUgqqhEYez7vYpnh7W7YjnVDKy2tjaFNcHXxj/Kt/9Z2Od+dI0GeboLv25QnnJ 8 | U9J+2sBWteb27c3ze96y/f5G2r9a6FiP2ZCemBZ/ipZ3kdOmlb8154vfY4p6TwgO 9 | FiMWqP4f+SKJFIGuIMc5l2ItyfVi8E6GMRgUY3lQGEtZBYwyBJVKiuZ77BCKQv3q 10 | x9BO2CEodt0KkEsL61tDc75QzhtweILAix/tDjd+yBgTcedEjmIIAzRHHwWjcZId 11 | gbJwnMfeGR8djYB7TLl6tVGpmvVRGVPoMoV7BGfEJ+1GsjbSjvQBZRYztupMLXmn 12 | AgMBAAGjggMeMIIDGjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH 13 | AwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFz6osqMFxHN4QmV 14 | 5eKNeZJbHiAaMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsG 15 | AQUFBwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNl 16 | bmNyeXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNl 17 | bmNyeXB0Lm9yZy8wIQYDVR0RBBowGIIWKi53ZWJjYWxsLm5pbmphcGJ4LmNvbTCB 18 | /gYDVR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYB 19 | BQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCB 20 | ngyBm1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkg 21 | UmVseWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUg 22 | Q2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQu 23 | b3JnL3JlcG9zaXRvcnkvMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAKTxRllTI 24 | OWW6qlD8WAfUt2+/WHopctykwwz05UVH9HgAAAFm1+B3kQAABAMASDBGAiEAzn7W 25 | llkg4S8htNUBeyoytAAmrXaUFsokMaTVuZyZAC8CIQDSvVhXIxk/ezoXH8GHyXVI 26 | KRVBPwoFPz3CXLlNPBLbDwB1AHR+2oMxrTMQkSGcziVPQnDCv/1eQiAIxjc1eeYQ 27 | e8xWAAABZtfgeV4AAAQDAEYwRAIgbo9wO6iDwyvtta3DcWCW8yLS/+ilR3oPvqgg 28 | Mw8v3q8CIDysoy6FoBGmCc2B2jVIdxyWPGIfRt1Z2IUCxHT6m4PeMA0GCSqGSIb3 29 | DQEBCwUAA4IBAQAkzhZpy1QyMmvIIhfNyi+tqDD/4b3wwIn7zOfkZkDPleTGO9/v 30 | cPBJst2BjV7UgZ6m+naxXIeq7JtaI0m/mx0ISnt8IcwhmU1ZOSKLJoUllIsEeIwW 31 | sIe2iYOHTxiTj0Yw2DciuHqokKYBANdNJSI3RNtlVqIBi80/ykM8F4Vrb3CukZFF 32 | NWAJ8GeN6eVo811Lgl3RagNKZAllBkS50Yg+AhPur88o35QAidt4NK+Inhl0abXd 33 | Lb+ylH4hwDb/KE707h3JHcMTrFLomjCDr4zLdmTRtypeKR9xRSLt8jBw7zXnZYgI 34 | hKmIEYFib9vOrNVoOkmIiBuARPMiVvNhq1UK 35 | -----END CERTIFICATE----- 36 | -----BEGIN CERTIFICATE----- 37 | MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ 38 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 39 | DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow 40 | SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT 41 | GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC 42 | AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF 43 | q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 44 | SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 45 | Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA 46 | a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj 47 | /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T 48 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG 49 | CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv 50 | bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k 51 | c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw 52 | VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC 53 | ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz 54 | MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu 55 | Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF 56 | AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo 57 | uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ 58 | wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu 59 | X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG 60 | PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 61 | KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== 62 | -----END CERTIFICATE----- 63 | -------------------------------------------------------------------------------- /cluster/janus-ecs-ec2-spot-fleet.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: 2010-09-09 3 | Description: Example CloudFormation template for running an ECS cluster on EC2 Spot Instances. 4 | Includes EC2 Spot Instance termination notice handler script. 5 | Mappings: 6 | CidrMappings: 7 | public-subnet-1: 8 | CIDR: 10.0.1.0/24 9 | public-subnet-2: 10 | CIDR: 10.0.2.0/24 11 | vpc: 12 | CIDR: 10.0.0.0/16 13 | ecsOptimizedAmi: 14 | ap-northeast-1: 15 | AMI: ami-a99d8ad5 16 | ap-southeast-1: 17 | AMI: ami-846144f8 18 | ap-southeast-2: 19 | AMI: ami-efda148d 20 | ca-central-1: 21 | AMI: ami-897ff9ed 22 | eu-central-1: 23 | AMI: ami-9fc39c74 24 | eu-west-1: 25 | AMI: ami-2d386654 26 | eu-west-2: 27 | AMI: ami-2218f945 28 | us-east-1: 29 | AMI: ami-aff65ad2 30 | us-east-2: 31 | AMI: ami-64300001 32 | us-west-1: 33 | AMI: ami-69677709 34 | us-west-2: 35 | AMI: ami-40ddb938 36 | Metadata: 37 | Authors: 38 | Description: Shawn OConnor (shawo@amazon.com), Chad Schmutzer (schmutze@amazon.com) 39 | License: 40 | Description: 'Copyright 2017 Amazon.com, Inc. and its affiliates. All Rights Reserved. 41 | 42 | Licensed under the Amazon Software License (the "License"). You may not use this file 43 | except in compliance with the License. A copy of the License is located at 44 | 45 | http://aws.amazon.com/asl/ 46 | 47 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 48 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 49 | License for the specific language governing permissions and limitations under the License.' 50 | Outputs: 51 | awsRegionName: 52 | Description: The name of the AWS Region your template was launched in 53 | Value: 54 | Ref: AWS::Region 55 | cloudWatchLogsGroupName: 56 | Description: Name of the CloudWatch Logs Group 57 | Value: 58 | Ref: cloudWatchLogsGroup 59 | ecsClusterName: 60 | Description: The name of the ECS cluster 61 | Value: 62 | Ref: ecsCluster 63 | snsTopic: 64 | Description: SNS Topic ARN 65 | Value: 66 | Ref: snsTopic 67 | spotFleetRequestId: 68 | Description: The Spot fleet Request Id 69 | Value: 70 | Ref: spotFleet 71 | Parameters: 72 | ecsClusterTargetCapacity: 73 | Default: 1 74 | Description: Number of EC2 Spot instances to initially launch in the ECS cluster 75 | Type: Number 76 | instanceType: 77 | AllowedValues: 78 | - t3.nano 79 | - t3.medium 80 | - c5.large 81 | - c3.large 82 | - c5d.large 83 | 84 | Default: c3.large 85 | Description: EC2 instance type to use for ECS cluster 86 | Type: String 87 | keyName: 88 | Description: Name of an existing EC2 KeyPair to enable SSH access to the EC2 instances 89 | Type: AWS::EC2::KeyPair::KeyName 90 | sourceCidr: 91 | Default: 0.0.0.0/0 92 | Description: Optional - CIDR/IP range for instance ssh access - defaults to 0.0.0.0/0 93 | Type: String 94 | Resources: 95 | attachGateway: 96 | DependsOn: 97 | - vpc 98 | - internetGateway 99 | Properties: 100 | InternetGatewayId: 101 | Ref: internetGateway 102 | VpcId: 103 | Ref: vpc 104 | Type: AWS::EC2::VPCGatewayAttachment 105 | cloudWatchLogsGroup: 106 | Properties: 107 | RetentionInDays: 7 108 | Type: AWS::Logs::LogGroup 109 | ecsCluster: 110 | Type: AWS::ECS::Cluster 111 | internetGateway: 112 | DependsOn: 113 | - vpc 114 | Type: AWS::EC2::InternetGateway 115 | publicRoute: 116 | DependsOn: 117 | - publicRouteTable 118 | - internetGateway 119 | - attachGateway 120 | Properties: 121 | DestinationCidrBlock: 0.0.0.0/0 122 | GatewayId: 123 | Ref: internetGateway 124 | RouteTableId: 125 | Ref: publicRouteTable 126 | Type: AWS::EC2::Route 127 | publicRouteTable: 128 | DependsOn: 129 | - vpc 130 | - attachGateway 131 | Properties: 132 | Tags: 133 | - Key: Name 134 | Value: Public Route Table 135 | VpcId: 136 | Ref: vpc 137 | Type: AWS::EC2::RouteTable 138 | publicSubnet1: 139 | DependsOn: attachGateway 140 | Properties: 141 | AvailabilityZone: 142 | Fn::Select: 143 | - 0 144 | - Fn::GetAZs: 145 | Ref: AWS::Region 146 | CidrBlock: 147 | Fn::FindInMap: 148 | - CidrMappings 149 | - public-subnet-1 150 | - CIDR 151 | MapPublicIpOnLaunch: true 152 | Tags: 153 | - Key: Name 154 | Value: Public Subnet 1 155 | VpcId: 156 | Ref: vpc 157 | Type: AWS::EC2::Subnet 158 | publicSubnet1RouteTableAssociation: 159 | DependsOn: 160 | - publicRouteTable 161 | - publicSubnet1 162 | - attachGateway 163 | Properties: 164 | RouteTableId: 165 | Ref: publicRouteTable 166 | SubnetId: 167 | Ref: publicSubnet1 168 | Type: AWS::EC2::SubnetRouteTableAssociation 169 | publicSubnet2: 170 | DependsOn: attachGateway 171 | Properties: 172 | AvailabilityZone: 173 | Fn::Select: 174 | - 1 175 | - Fn::GetAZs: 176 | Ref: AWS::Region 177 | CidrBlock: 178 | Fn::FindInMap: 179 | - CidrMappings 180 | - public-subnet-2 181 | - CIDR 182 | MapPublicIpOnLaunch: true 183 | Tags: 184 | - Key: Name 185 | Value: Public Subnet 2 186 | VpcId: 187 | Ref: vpc 188 | Type: AWS::EC2::Subnet 189 | publicSubnet2RouteTableAssociation: 190 | DependsOn: 191 | - publicRouteTable 192 | - publicSubnet2 193 | - attachGateway 194 | Properties: 195 | RouteTableId: 196 | Ref: publicRouteTable 197 | SubnetId: 198 | Ref: publicSubnet2 199 | Type: AWS::EC2::SubnetRouteTableAssociation 200 | securityGroup: 201 | DependsOn: 202 | - vpc 203 | Properties: 204 | GroupDescription: Spot fleet instance Security Group 205 | SecurityGroupIngress: 206 | - CidrIp: 207 | Ref: sourceCidr 208 | FromPort: 22 209 | IpProtocol: tcp 210 | ToPort: 22 211 | VpcId: 212 | Ref: vpc 213 | Type: AWS::EC2::SecurityGroup 214 | snsTopic: 215 | Type: AWS::SNS::Topic 216 | spotFleet: 217 | DependsOn: 218 | - spotFleetRole 219 | - spotFleetInstanceProfile 220 | - ecsCluster 221 | - securityGroup 222 | Properties: 223 | SpotFleetRequestConfigData: 224 | AllocationStrategy: diversified 225 | IamFleetRole: 226 | Fn::GetAtt: 227 | - spotFleetRole 228 | - Arn 229 | LaunchSpecifications: 230 | - IamInstanceProfile: 231 | Arn: 232 | Fn::GetAtt: 233 | - spotFleetInstanceProfile 234 | - Arn 235 | ImageId: 236 | Fn::FindInMap: 237 | - ecsOptimizedAmi 238 | - Ref: AWS::Region 239 | - AMI 240 | InstanceType: 241 | Ref: instanceType 242 | KeyName: 243 | Ref: keyName 244 | Monitoring: 245 | Enabled: true 246 | SecurityGroups: 247 | - GroupId: 248 | Ref: securityGroup 249 | SubnetId: 250 | Fn::Join: 251 | - ',' 252 | - - Ref: publicSubnet1 253 | - Ref: publicSubnet2 254 | UserData: 255 | Fn::Base64: 256 | Fn::Sub: '#!/bin/bash -xe 257 | 258 | export PATH=/usr/local/bin:$PATH 259 | 260 | yum -y --security update 261 | 262 | yum -y install jq 263 | 264 | easy_install pip 265 | 266 | pip install awscli 267 | 268 | aws configure set default.region ${AWS::Region} 269 | 270 | echo ECS_CLUSTER=${ecsCluster} >> /etc/ecs/ecs.config 271 | 272 | 273 | 274 | cat < /tmp/awslogs.conf 275 | 276 | [general] 277 | 278 | state_file = /var/awslogs/state/agent-state 279 | 280 | 281 | 282 | [/var/log/dmesg] 283 | 284 | file = /var/log/dmesg 285 | 286 | log_group_name = ${cloudWatchLogsGroup} 287 | 288 | log_stream_name = %ECS_CLUSTER/%CONTAINER_INSTANCE/var/log/dmesg 289 | 290 | initial_position = start_of_file 291 | 292 | 293 | 294 | [/var/log/messages] 295 | 296 | file = /var/log/messages 297 | 298 | log_group_name = ${cloudWatchLogsGroup} 299 | 300 | log_stream_name = %ECS_CLUSTER/%CONTAINER_INSTANCE/var/log/messages 301 | 302 | datetime_format = %b %d %H:%M:%S 303 | 304 | initial_position = start_of_file 305 | 306 | 307 | 308 | [/var/log/docker] 309 | 310 | file = /var/log/docker 311 | 312 | log_group_name = ${cloudWatchLogsGroup} 313 | 314 | log_stream_name = %ECS_CLUSTER/%CONTAINER_INSTANCE/var/log/docker 315 | 316 | datetime_format = %Y-%m-%dT%H:%M:%S.%f 317 | 318 | initial_position = start_of_file 319 | 320 | 321 | 322 | [/var/log/ecs/ecs-init.log] 323 | 324 | file = /var/log/ecs/ecs-init.log.* 325 | 326 | log_group_name = ${cloudWatchLogsGroup} 327 | 328 | log_stream_name = %ECS_CLUSTER/%CONTAINER_INSTANCE/var/log/ecs/ecs-init.log 329 | 330 | datetime_format = %Y-%m-%dT%H:%M:%SZ 331 | 332 | initial_position = start_of_file 333 | 334 | 335 | 336 | [/var/log/ecs/ecs-agent.log] 337 | 338 | file = /var/log/ecs/ecs-agent.log.* 339 | 340 | log_group_name = ${cloudWatchLogsGroup} 341 | 342 | log_stream_name = %ECS_CLUSTER/%CONTAINER_INSTANCE/var/log/ecs/ecs-agent.log 343 | 344 | datetime_format = %Y-%m-%dT%H:%M:%SZ 345 | 346 | initial_position = start_of_file 347 | 348 | 349 | 350 | [/var/log/ecs/audit.log] 351 | 352 | file = /var/log/ecs/audit.log.* 353 | 354 | log_group_name = ${cloudWatchLogsGroup} 355 | 356 | log_stream_name = %ECS_CLUSTER/%CONTAINER_INSTANCE/var/log/ecs/audit.log 357 | 358 | datetime_format = %Y-%m-%dT%H:%M:%SZ 359 | 360 | initial_position = start_of_file 361 | 362 | EOF 363 | 364 | 365 | 366 | cd /tmp && curl -sO https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py 367 | 368 | python /tmp/awslogs-agent-setup.py -n -r ${AWS::Region} -c /tmp/awslogs.conf 369 | 370 | 371 | 372 | cat < /etc/init/cloudwatch-logs-start.conf 373 | 374 | description "Configure and start CloudWatch Logs agent on Amazon ECS container 375 | instance" 376 | 377 | author "Amazon Web Services" 378 | 379 | start on started ecs 380 | 381 | script 382 | 383 | exec 2>>/var/log/cloudwatch-logs-start.log 384 | 385 | set -x 386 | 387 | until curl -s http://localhost:51678/v1/metadata; do sleep 1; done 388 | 389 | ECS_CLUSTER=\$(curl -s http://localhost:51678/v1/metadata | jq .Cluster | tr 390 | -d \") 391 | 392 | CONTAINER_INSTANCE=\$(curl -s http://localhost:51678/v1/metadata | jq .ContainerInstanceArn 393 | | tr -d \") 394 | 395 | sed -i "s|%ECS_CLUSTER|\$ECS_CLUSTER|g" /var/awslogs/etc/awslogs.conf 396 | 397 | sed -i "s|%CONTAINER_INSTANCE|\$CONTAINER_INSTANCE|g" /var/awslogs/etc/awslogs.conf 398 | 399 | chkconfig awslogs on 400 | 401 | service awslogs start 402 | 403 | end script 404 | 405 | EOF 406 | 407 | 408 | 409 | cat < /etc/init/spot-instance-termination-notice-handler.conf 410 | 411 | description "Start spot instance termination handler monitoring script" 412 | 413 | author "Amazon Web Services" 414 | 415 | start on started ecs 416 | 417 | script 418 | 419 | echo \$\$ > /var/run/spot-instance-termination-notice-handler.pid 420 | 421 | exec /usr/local/bin/spot-instance-termination-notice-handler.sh 422 | 423 | end script 424 | 425 | pre-start script 426 | 427 | logger "[spot-instance-termination-notice-handler.sh]: spot instance termination 428 | notice handler started" 429 | 430 | end script 431 | 432 | EOF 433 | 434 | 435 | 436 | cat < /usr/local/bin/spot-instance-termination-notice-handler.sh 437 | 438 | #!/bin/bash 439 | 440 | while sleep 5; do 441 | 442 | if [ -z \$(curl -Isf http://169.254.169.254/latest/meta-data/spot/termination-time)]; 443 | then 444 | 445 | /bin/false 446 | 447 | else 448 | 449 | logger "[spot-instance-termination-notice-handler.sh]: spot instance termination 450 | notice detected" 451 | 452 | STATUS=DRAINING 453 | 454 | ECS_CLUSTER=\$(curl -s http://localhost:51678/v1/metadata | jq .Cluster | tr 455 | -d \") 456 | 457 | CONTAINER_INSTANCE=\$(curl -s http://localhost:51678/v1/metadata | jq .ContainerInstanceArn 458 | | tr -d \") 459 | 460 | logger "[spot-instance-termination-notice-handler.sh]: putting instance in state 461 | \$STATUS" 462 | 463 | logger "[spot-instance-termination-notice-handler.sh]: running: /usr/local/bin/aws 464 | ecs update-container-instances-state --cluster \$ECS_CLUSTER --container-instances 465 | \$CONTAINER_INSTANCE --status \$STATUS" 466 | 467 | /usr/local/bin/aws ecs update-container-instances-state --cluster \$ECS_CLUSTER 468 | --container-instances \$CONTAINER_INSTANCE --status \$STATUS 469 | 470 | logger "[spot-instance-termination-notice-handler.sh]: running: \"/usr/local/bin/aws 471 | sns publish --topic-arn ${snsTopic} --message \"Spot instance termination notice 472 | detected. Details: cluster: \$ECS_CLUSTER, container_instance: \$CONTAINER_INSTANCE. 473 | Putting instance in state \$STATUS.\"" 474 | 475 | /usr/local/bin/aws sns publish --topic-arn ${snsTopic} --message "Spot instance 476 | termination notice detected. Details: cluster: \$ECS_CLUSTER, container_instance: 477 | \$CONTAINER_INSTANCE. Putting instance in state \$STATUS." 478 | 479 | logger "[spot-instance-termination-notice-handler.sh]: putting myself to sleep..." 480 | 481 | sleep 120 482 | 483 | fi 484 | 485 | done 486 | 487 | EOF 488 | 489 | 490 | 491 | chmod +x /usr/local/bin/spot-instance-termination-notice-handler.sh 492 | 493 | ' 494 | TargetCapacity: 495 | Ref: ecsClusterTargetCapacity 496 | TerminateInstancesWithExpiration: true 497 | SpotPrice: "0.03" 498 | Type: AWS::EC2::SpotFleet 499 | spotFleetInstanceProfile: 500 | DependsOn: 501 | - spotFleetInstanceRole 502 | Properties: 503 | Path: / 504 | Roles: 505 | - Ref: spotFleetInstanceRole 506 | Type: AWS::IAM::InstanceProfile 507 | spotFleetInstanceRole: 508 | Properties: 509 | AssumeRolePolicyDocument: 510 | Statement: 511 | - Action: 512 | - sts:AssumeRole 513 | Effect: Allow 514 | Principal: 515 | Service: 516 | - ec2.amazonaws.com 517 | Version: 2012-10-17 518 | ManagedPolicyArns: 519 | - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role 520 | Path: / 521 | Policies: 522 | - PolicyDocument: 523 | Statement: 524 | - Action: 525 | - ecs:UpdateContainerInstancesState 526 | Effect: Allow 527 | Resource: '*' 528 | Version: 2012-10-17 529 | PolicyName: ecsUpdateContainerInstancesStatePolicy 530 | - PolicyDocument: 531 | Statement: 532 | - Action: 533 | - logs:CreateLogGroup 534 | - logs:CreateLogStream 535 | - logs:PutLogEvents 536 | - logs:DescribeLogStreams 537 | Effect: Allow 538 | Resource: arn:aws:logs:*:*:* 539 | Version: 2012-10-17 540 | PolicyName: cloudWatchLogsPolicy 541 | - PolicyDocument: 542 | Statement: 543 | - Action: 544 | - sns:Publish 545 | Effect: Allow 546 | Resource: 547 | Ref: snsTopic 548 | Version: 2012-10-17 549 | PolicyName: snsPublishPolicy 550 | Type: AWS::IAM::Role 551 | spotFleetRole: 552 | Properties: 553 | AssumeRolePolicyDocument: 554 | Statement: 555 | - Action: 556 | - sts:AssumeRole 557 | Effect: Allow 558 | Principal: 559 | Service: 560 | - spotfleet.amazonaws.com 561 | Version: 2012-10-17 562 | ManagedPolicyArns: 563 | - arn:aws:iam::aws:policy/service-role/AmazonEC2SpotFleetRole 564 | Path: / 565 | Type: AWS::IAM::Role 566 | vpc: 567 | Properties: 568 | CidrBlock: 569 | Fn::FindInMap: 570 | - CidrMappings 571 | - vpc 572 | - CIDR 573 | EnableDnsHostnames: true 574 | EnableDnsSupport: true 575 | Tags: 576 | - Key: Name 577 | Value: VPC for ECS on EC2 Spot fleet 578 | Type: AWS::EC2::VPC 579 | ... 580 | --------------------------------------------------------------------------------