diff --git a/docs/reference/ssl/compose-example.yaml b/docs/reference/ssl/compose-example.yaml new file mode 100644 index 00000000..c4f9255f --- /dev/null +++ b/docs/reference/ssl/compose-example.yaml @@ -0,0 +1,265 @@ +version: "3.3" +services: + traefik: + image: traefik:v2.1.3 + container_name: "traefik" + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge=true" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge.entrypoint=web" + - "--certificatesresolvers.myhttpchallenge.acme.email=" + - "--certificatesresolvers.myhttpchallenge.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "./letsencrypt:/letsencrypt" + - "/var/run/docker.sock:/var/run/docker.sock" + networks: + - functions + placement: + constraints: [node.role == manager] + + gateway: + ports: + - 8080:8080 + image: openfaas/gateway:0.18.10 + networks: + - functions + labels: + - "traefik.enable=true" + - "traefik.http.routers.gateway.rule=Host(`gw.example.com`)" + - "traefik.http.routers.gateway.entrypoints=websecure" + - "traefik.http.routers.gateway.tls.certresolver=myhttpchallenge" + environment: + functions_provider_url: "http://faas-swarm:8080/" + read_timeout: "5m5s" # Maximum time to read HTTP request + write_timeout: "5m5s" # Maximum time to write HTTP response + upstream_timeout: "5m" # Maximum duration of upstream function call - should be more than read_timeout and write_timeout + dnsrr: "true" # Temporarily use dnsrr in place of VIP while issue persists on PWD + faas_nats_address: "nats" + faas_nats_port: 4222 + direct_functions: "true" # Functions are invoked directly over the overlay network + direct_functions_suffix: "" + basic_auth: "${BASIC_AUTH:-false}" + secret_mount_path: "/run/secrets/" + scale_from_zero: "true" # Enable if you want functions to scale from 0/0 to min replica count upon invoke + max_idle_conns: 1024 + max_idle_conns_per_host: 1024 + auth_proxy_url: "${AUTH_URL:-}" + auth_proxy_pass_body: "false" + deploy: + resources: + # limits: # Enable if you want to limit memory usage + # memory: 200M + reservations: + memory: 100M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + placement: + constraints: + - "node.platform.os == linux" + secrets: + - basic-auth-user + - basic-auth-password + + # auth service provide basic-auth plugin for system APIs + basic-auth-plugin: + image: openfaas/basic-auth-plugin:0.18.10 + networks: + - functions + environment: + secret_mount_path: "/run/secrets/" + user_filename: "basic-auth-user" + pass_filename: "basic-auth-password" + deploy: + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + resources: + # limits: # Enable if you want to limit memory usage + # memory: 100M + reservations: + memory: 50M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + secrets: + - basic-auth-user + - basic-auth-password + + # Docker Swarm provider + faas-swarm: + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + image: openfaas/faas-swarm:0.8.2 + networks: + - functions + environment: + read_timeout: "5m5s" # set both here, and on your functions + write_timeout: "5m5s" # set both here, and on your functions + DOCKER_API_VERSION: "1.30" + basic_auth: "${BASIC_AUTH:-false}" + secret_mount_path: "/run/secrets/" + deploy: + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + resources: + # limits: # Enable if you want to limit memory usage + # memory: 100M + reservations: + memory: 100M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + secrets: + - basic-auth-user + - basic-auth-password + + nats: + image: nats-streaming:0.11.2 + # Uncomment the following port mappings if you wish to expose the + # NATS client and/or management ports you must also add `-m 8222` to the command + # ports: + # - 4222:4222 + # - 8222:8222 + command: "--store memory --cluster_id faas-cluster" + networks: + - functions + deploy: + resources: + limits: + memory: 125M + reservations: + memory: 50M + placement: + constraints: + - "node.platform.os == linux" + + queue-worker: + image: openfaas/queue-worker:0.8.4 + networks: + - functions + environment: + max_inflight: "1" + ack_wait: "5m5s" # Max duration of any async task / request + basic_auth: "${BASIC_AUTH:-false}" + secret_mount_path: "/run/secrets/" + gateway_invoke: "true" + faas_gateway_address: "gateway" + deploy: + resources: + limits: + memory: 50M + reservations: + memory: 20M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + placement: + constraints: + - "node.platform.os == linux" + secrets: + - basic-auth-user + - basic-auth-password + + # End services + + # Start monitoring + + prometheus: + image: prom/prometheus:v2.11.0 + environment: + no_proxy: "gateway" + configs: + - source: prometheus_config + target: /etc/prometheus/prometheus.yml + - source: prometheus_rules + target: /etc/prometheus/alert.rules.yml + command: + - "--config.file=/etc/prometheus/prometheus.yml" + # - '-storage.local.path=/prometheus' + ports: + - 9090:9090 + networks: + - functions + deploy: + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + resources: + limits: + memory: 500M + reservations: + memory: 200M + + alertmanager: + image: prom/alertmanager:v0.18.0 + environment: + no_proxy: "gateway" + command: + - "--config.file=/alertmanager.yml" + - "--storage.path=/alertmanager" + networks: + - functions + # Uncomment the following port mapping if you wish to expose the Prometheus + # Alertmanager UI. + # ports: + # - 9093:9093 + deploy: + resources: + limits: + memory: 50M + reservations: + memory: 20M + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + configs: + - source: alertmanager_config + target: /alertmanager.yml + secrets: + - basic-auth-password + +configs: + prometheus_config: + file: ./prometheus/prometheus.yml + prometheus_rules: + file: ./prometheus/alert.rules.yml + alertmanager_config: + file: ./prometheus/alertmanager.yml + +networks: + functions: + driver: overlay + attachable: true + labels: + - "openfaas=true" + +secrets: + basic-auth-user: + external: true + basic-auth-password: + external: true + +volumes: + letsencrypt: diff --git a/docs/reference/ssl/swarm-with-traefik.md b/docs/reference/ssl/swarm-with-traefik.md index c8c5902a..33532a7f 100644 --- a/docs/reference/ssl/swarm-with-traefik.md +++ b/docs/reference/ssl/swarm-with-traefik.md @@ -1,14 +1,27 @@ -# SSL on Swarm with Traefik +# SSL on Docker Swarm with Traefik -To completely secure your OpenFaaS installation, you need SSL. On Swarm, you can do this easily with [Traefik][traefik] and [Let's Encrypt][letsencrypt]. Traefik is a reverse proxy that comes with SSL support via Let's Encrypt. In this tutorial we will show you how to deploy OpenFaaS with Traefik. +To help secure your OpenFaaS installation, you need TLS. On [Docker Swarm](docs/reference/ssl/kubernetes-with-cert-manager.md), you can do this easily with [Traefik](https://traefik.io/) and [Let's Encrypt](https://letsencrypt.org/). Traefik is a reverse proxy that comes with TLS support via Let's Encrypt. In this tutorial we will show you how to deploy OpenFaaS with Traefik. -## Create an A record +### Create a DNS record -If your domain is `.domain.com` then create an A record using your DNS administration panel such as `gateway.domain.com` or `openfaas.domain.com`. The required steps will vary depending on your domain provider and your cluster provider. For example; [on Google Cloud DNS](https://cloud.google.com/kubernetes-engine/docs/tutorials/configuring-domain-name-static-ip) or [with Route53 using AWS](https://kubernetes.io/docs/setup/custom-cloud/kops/#2-5-create-a-route53-domain-for-your-cluster). +Determine the public IP address that can be used to access your cluster. +If your domain is `.example.com` then create an A record using your DNS administration panel such as `gw.example.com`. + +> The required steps will vary depending on your domain provider and your cluster provider. For example; [on Google Cloud DNS](https://cloud.google.com/kubernetes-engine/docs/tutorials/configuring-domain-name-static-ip) or [with Route53 using AWS](https://kubernetes.io/docs/setup/custom-cloud/kops/#2-5-create-a-route53-domain-for-your-cluster). + +Once created, verify that what you entered into your DNS control-panel worked with `ping`: + +```sh +ping gw.example.com +``` + +You should now see the value you entered. Sometimes DNS can take 1-5 minutes to propagate. ## Update the Compose configuration +A complete example `docker-compose.yaml` can be found [here](./compose-example.yaml) + ### Configure Traefik To use Traefik with OpenFaaS, you need to modify the OpenFaaS deployment manifest to include Traefik and configuring OpenFaaS to communicate through Traefik instead of directly exposing its services publicly. @@ -27,35 +40,27 @@ To start, open `docker-compose.yaml` in your favorite editor and add a `traefik` version: "3.3" services: traefik: - image: traefik:v1.7.6 + image: traefik:v2.1.3 + container_name: "traefik" command: - - "--api=true" - - "--docker=true" - - "--docker.swarmmode=true" - - "--docker.domain=traefik" - - "--docker.watch=true" - - "--defaultEntryPoints=http,https" - - "--entryPoints=Name:https Address::443 TLS" - - "--entryPoints=Name:http Address::80" - - "--acme=true" - - "--acme.entrypoint=https" - - "--acme.httpchallenge=true" - - "--acme.httpchallenge.entrypoint=http" - - "--acme.domains=openfaas.mydomain.com" - - "--acme.email=" - - "--acme.ondemand=true" - - "--acme.onhostrule=true" - - "--acme.storage=/etc/traefik/acme/acme.json" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge=true" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge.entrypoint=web" + - "--certificatesresolvers.myhttpchallenge.acme.email=" + - "--certificatesresolvers.myhttpchallenge.acme.storage=/letsencrypt/acme.json" ports: - - 80:80 - - 8080:8080 - - 443:443 + - "80:80" + - "443:443" + - "8080:8080" volumes: + - "./letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock" - - "acme:/etc/traefik/acme" networks: - functions - deploy: placement: constraints: [node.role == manager] @@ -65,10 +70,10 @@ services: This configuration does a few important things: -* The `--api=true` flag enables Traefik's Web UI, -* The `--docker.*` flags tell Traefik to use Docker and specify that it's running in a Docker Swarm cluster. -* The `--defaultEntryPoints` and `--entryPoints` flags define entry points and protocols to be used. In our case this includes HTTP on port 80 and HTTPS on port 443. -* The `--acme.*` flags configure Traefik to use the ACME protocol to generate Let's Encrypt certificates to secure your OpenFaaS cluster with SSL. Make sure to replace the `openfaas.mydomain.com` domain placeholders in the `--acme.domains` flag with your own domain. You can specify multiple domains by separating them with a comma and space. We also setup a volume `acme` to store the resulting certificate files. +* The `--providers.docker.*` flags tell Traefik to use Docker and specify that it's running in a Docker Swarm cluster. +* The `--entryPoints` flags define entry points and protocols to be used. In our case this includes HTTP on port 80 and HTTPS on port 443. +* The `--certificatesresolvers.*` flags configure Traefik to use the ACME protocol to generate Let's Encrypt certificates to secure your OpenFaaS cluster with SSL. +Make sure to set your own email within the `certificatesresolvers.myhttpchallenge.acme.email` command line argument of the traefik service. * Expose the ports required for Traefik. Traefik uses port `8080` for its operations and UI, while in the last step we configured ports `80` and `443` and entrypoints for internet traffic. These will be used / proxied to OpenFaaS * Binds the docker socket to the traefik container so that it can communicate with the Docker API and dertermine the number of containers and their IP addressess. * Adds `traefik` to the `functions network so that it can communicate with the OpenFaaS components. @@ -80,7 +85,7 @@ By default, the original `docker-compose.yaml` file exposes the OpenFaaS `gatewa First, remove the `ports` section. -Next, add the following `labels` directive to the `deploy` section of the gateway service. +Next, add the following `labels` directive to the gateway service. ```yaml gateway: @@ -89,31 +94,34 @@ Next, add the following `labels` directive to the `deploy` section of the gatewa ... environment: ... + labels: + - "traefik.enable=true" + - "traefik.http.routers.gateway.rule=Host(`gw.example.com`)" + - "traefik.http.routers.gateway.entrypoints=websecure" + - "traefik.http.routers.gateway.tls.certresolver=myhttpchallenge" deploy: - labels: - - traefik.port=8080 - - traefik.frontend.rule=PathPrefix:/ui,/system,/function - resources: - ... + ... secrets: ... ... ``` -These labels expose the OpenFaaS gateway `/ui`, `/system`, and `/function` endpoints on port `8080` over Traefik. +Traefik uses reads these labels from the Docker API to detect and configure the routing for the gateway. ### Configure data volumes -Finally, while configuring Traefik, you mounted a volume called `acme`. You must now define the `acme` volume used for storing Let's Encrypt certificates. We can define an empty volume, meaning data will not persist if you destroy the container. If you destroy the container, the certificates will be regenerated the next time you start Traefik. +Finally, while configuring Traefik, you mounted a volume called `letsencrypt`. You must now define the `letsencrypt` volume used for storing Let's Encrypt certificates. We can define an empty volume, meaning data will not persist if you destroy the container. If you destroy the container, the certificates will be regenerated the next time you start Traefik. Add the following volumes directive on the last line of the file: ```yaml ... volumes: - acme: + letsencrypt: ``` +A complete example `docker-compose.yaml` can be found [here](./compose-example.yaml) + ## Install OpenFaaS With all of the modifications in place, you can now deploy using the standard deployment scripts. On Mac and Linux: `deploy_stack.sh` and on Windows use `deploy_stack.ps1`. This script will deploy all of the required resources (services, configuration files, networks, and secrets) for your OpenFaaS cluster as they are defined in the `docker-compose.yaml` file. @@ -158,13 +166,13 @@ In your projects containing OpenFaaS functions, you can now deploy using your do ### Deploy from the CLI ```sh -faas-cli login --gateway https://openfaas.mydomain.com --username admin --password -faas-cli deploy --gateway https://openfaas.mydomain.com +faas-cli login --gateway https://gw.example.com --username admin --password +faas-cli deploy --gateway https://gw.example.com ``` -Replace `openfaas.mydomain.com` with your domain as well as adding the username `admin` and secure random password that the deploy script created for you when you deployed OpenFaaS. +Replace `gw.example.com` with your domain as well as adding the username `admin` and secure random password that the deploy script created for you when you deployed OpenFaaS. ### Use the web UI -You can use the web UI to see the functions deployed to your cluster or to deploy functions from the Store. In your web browser, go to https://openfaas.mydomain.com/ui/. Note that the trailing slash is required. +You can use the web UI to see the functions deployed to your cluster or to deploy functions from the Store. In your web browser, go to https://gw.example.com/ui/. Note that the trailing slash is required. On your first visit, the HTTP authentication dialogue box will open, you can login with the username `admin` and secure random password that the deploy script created for you when you deployed OpenFaaS. @@ -176,5 +184,3 @@ $ docker service logs -f traefik ``` You can see internet traffic logs as well as logs related to the Let's Encrypt certificate process. -[traefik]: https://traefik.io/ -[letsencrypt]: https://letsencrypt.org/