├── k8s-config ├── consul │ ├── .helmignore │ ├── .gitignore │ ├── test │ │ ├── unit │ │ │ ├── _helpers.bash │ │ │ ├── dns-service.bats │ │ │ ├── connect-inject-service.bats │ │ │ ├── client-configmap.bats │ │ │ ├── server-configmap.bats │ │ │ ├── sync-catalog-cluster-role.bats │ │ │ ├── sync-service-account.bats │ │ │ ├── sync-catalog-cluster-role-binding.bats │ │ │ ├── connect-inject-clusterrole.bats │ │ │ ├── connect-inject-serviceaccount.bats │ │ │ ├── connect-inject-mutatingwebhook.bats │ │ │ ├── connect-inject-clusterrolebinding.bats │ │ │ ├── server-service.bats │ │ │ └── ui-service.bats │ │ ├── terraform │ │ │ ├── outputs.tf │ │ │ ├── service-account.yaml │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── acceptance │ │ │ ├── server.bats │ │ │ └── _helpers.bash │ │ └── docker │ │ │ └── Test.dockerfile │ ├── Makefile │ ├── Chart.yaml │ ├── templates │ │ ├── sync-catalog-service-account.yaml │ │ ├── connect-inject-serviceaccount.yaml │ │ ├── server-config-configmap.yaml │ │ ├── client-config-configmap.yaml │ │ ├── connect-inject-service.yaml │ │ ├── sync-catalog-cluster-role-binding.yaml │ │ ├── dns-service.yaml │ │ ├── connect-inject-clusterrole.yaml │ │ ├── sync-catalog-cluster-role.yaml │ │ ├── server-disruptionbudget.yaml │ │ ├── connect-inject-clusterrolebinding.yaml │ │ ├── tests │ │ │ └── test-runner.yaml │ │ ├── connect-inject-mutatingwebhook.yaml │ │ ├── ui-service.yaml │ │ ├── _helpers.tpl │ │ ├── server-service.yaml │ │ └── sync-catalog-deployment.yaml │ └── CHANGELOG.md ├── app │ ├── secret.yml │ └── templates │ │ ├── envoy_init.dockerfile │ │ ├── init.sh │ │ ├── envoy_consul_config.hcl │ │ └── envoy_bootstrap.yml ├── monitoring │ ├── metrics-server │ │ ├── metrics-server-service.yaml │ │ ├── auth-delegator.yaml │ │ ├── metrics-apiservice.yaml │ │ ├── auth-reader.yaml │ │ ├── aggregated-metrics-reader.yaml │ │ ├── resource-reader.yaml │ │ └── metrics-server-deployment.yaml │ └── prometheus │ │ ├── statsd.yml │ │ └── statefulset.yml └── load-test.yml ├── exercises ├── lab-01 │ ├── 02-install-consul │ │ ├── files │ │ │ └── consul │ │ │ │ ├── .helmignore │ │ │ │ ├── .gitignore │ │ │ │ ├── test │ │ │ │ ├── unit │ │ │ │ │ ├── _helpers.bash │ │ │ │ │ ├── dns-service.bats │ │ │ │ │ ├── connect-inject-service.bats │ │ │ │ │ ├── client-configmap.bats │ │ │ │ │ ├── server-configmap.bats │ │ │ │ │ ├── sync-catalog-cluster-role.bats │ │ │ │ │ ├── sync-service-account.bats │ │ │ │ │ ├── sync-catalog-cluster-role-binding.bats │ │ │ │ │ ├── connect-inject-clusterrole.bats │ │ │ │ │ ├── connect-inject-serviceaccount.bats │ │ │ │ │ ├── connect-inject-mutatingwebhook.bats │ │ │ │ │ ├── connect-inject-clusterrolebinding.bats │ │ │ │ │ ├── server-service.bats │ │ │ │ │ └── ui-service.bats │ │ │ │ ├── terraform │ │ │ │ │ ├── outputs.tf │ │ │ │ │ ├── service-account.yaml │ │ │ │ │ ├── variables.tf │ │ │ │ │ └── main.tf │ │ │ │ ├── acceptance │ │ │ │ │ ├── server.bats │ │ │ │ │ └── _helpers.bash │ │ │ │ └── docker │ │ │ │ │ └── Test.dockerfile │ │ │ │ ├── Makefile │ │ │ │ ├── Chart.yaml │ │ │ │ ├── templates │ │ │ │ ├── sync-catalog-service-account.yaml │ │ │ │ ├── connect-inject-serviceaccount.yaml │ │ │ │ ├── server-config-configmap.yaml │ │ │ │ ├── client-config-configmap.yaml │ │ │ │ ├── connect-inject-service.yaml │ │ │ │ ├── sync-catalog-cluster-role-binding.yaml │ │ │ │ ├── dns-service.yaml │ │ │ │ ├── connect-inject-clusterrole.yaml │ │ │ │ ├── sync-catalog-cluster-role.yaml │ │ │ │ ├── server-disruptionbudget.yaml │ │ │ │ ├── connect-inject-clusterrolebinding.yaml │ │ │ │ ├── tests │ │ │ │ │ └── test-runner.yaml │ │ │ │ ├── connect-inject-mutatingwebhook.yaml │ │ │ │ ├── ui-service.yaml │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── server-service.yaml │ │ │ │ └── sync-catalog-deployment.yaml │ │ │ │ └── CHANGELOG.md │ │ └── README.md │ ├── 03-install-emojify-app │ │ ├── files │ │ │ └── app │ │ │ │ ├── secret.yml │ │ │ │ ├── load-test.yml │ │ │ │ ├── cache.yml │ │ │ │ ├── facebox.yml │ │ │ │ ├── api.yml │ │ │ │ ├── website.yml │ │ │ │ └── ingress.yml │ │ └── index.md │ ├── 04-install-prometheus-and-grafana │ │ ├── files │ │ │ ├── metrics-server │ │ │ │ ├── metrics-server-service.yaml │ │ │ │ ├── auth-delegator.yaml │ │ │ │ ├── metrics-apiservice.yaml │ │ │ │ ├── auth-reader.yaml │ │ │ │ ├── aggregated-metrics-reader.yaml │ │ │ │ ├── resource-reader.yaml │ │ │ │ └── metrics-server-deployment.yaml │ │ │ └── prometheus │ │ │ │ ├── grafana-config.yml │ │ │ │ └── statsd.yml │ │ └── index.md │ ├── 05-configure-grafana │ │ └── index.md │ └── 01-get-familiar-with-environment │ │ └── index.md ├── images │ ├── lab01-grafana.png │ ├── lab01-consul-ui.png │ ├── lab01-emojify-app.png │ ├── lab01-prometheus.png │ ├── lab01-grafana-home.png │ ├── emojify-architecture.png │ ├── lab03-envoy-statistics.png │ ├── lab03-intentions-deny.png │ ├── lab03-query-prometheus.png │ ├── lab01-configure-grafana.png │ ├── lab03-envoy-architecture.png │ ├── lab03-envoy-connections.png │ ├── lab03-intentions-list-01.png │ ├── lab03-intentions-list-02.png │ ├── lab01-grafana-create-import.png │ ├── lab01-instruqt-environment.png │ ├── lab02-consul-sidecar-inject.png │ ├── lab01-grafana-add-data-source.png │ ├── lab03-envoy-connections-edit.png │ ├── lab01-grafana-dashboard-import-01.png │ └── lab01-grafana-dashboard-import-02.png ├── lab-04 │ ├── 03-retries │ │ ├── files │ │ │ └── app │ │ │ │ └── secret.yml │ │ └── index.md │ ├── 01-load-balancing │ │ ├── files │ │ │ └── app │ │ │ │ └── secret.yml │ │ └── index.md │ ├── 02-timeouts │ │ ├── part1 │ │ │ └── files │ │ │ │ └── app │ │ │ │ └── secret.yml │ │ ├── part2 │ │ │ └── files │ │ │ │ └── app │ │ │ │ └── secret.yml │ │ └── index.md │ └── 04-outlier-detection │ │ ├── files │ │ └── app │ │ │ └── secret.yml │ │ └── index.md ├── lab-02 │ ├── 01-enable-connect-inject │ │ ├── files │ │ │ └── app │ │ │ │ ├── secret.yml │ │ │ │ ├── cache.yml │ │ │ │ ├── facebox.yml │ │ │ │ ├── api.yml │ │ │ │ ├── website.yml │ │ │ │ └── ingress.yml │ │ └── index.md │ └── 02-configure-intentions │ │ └── index.md ├── lab-03 │ ├── 01-configure-envoy-statistics │ │ ├── files │ │ │ └── app │ │ │ │ └── secret.yml │ │ └── index.md │ ├── 03-requests │ │ └── index.md │ ├── 04-authorizations │ │ └── index.md │ └── 02-connections │ │ └── index.md └── index.md ├── slides ├── 2-security │ └── images │ │ ├── bypass.png │ │ ├── firewall.png │ │ ├── segment_1.png │ │ ├── segment_2.png │ │ ├── data_plane_1.png │ │ ├── data_plane_2.png │ │ ├── data_plane_3.png │ │ ├── data_plane_4.png │ │ ├── data_plane_5.png │ │ ├── data_plane_6.png │ │ ├── network_isolation.png │ │ ├── dynamic_environments.png │ │ ├── network_segmentation.png │ │ ├── service_segmentation.png │ │ ├── vulnerable_service_1.png │ │ ├── vulnerable_service_2.png │ │ ├── application_deployment_1.png │ │ ├── application_deployment_2.png │ │ ├── application_deployment_3.png │ │ └── application_deployment_4.png ├── 1-overview │ └── images │ │ ├── overview.png │ │ ├── architecture_1.png │ │ ├── architecture_2.png │ │ ├── architecture_3.png │ │ ├── architecture_4.png │ │ ├── architecture_5.png │ │ ├── service_registry.png │ │ └── raw.graffle │ │ ├── data.plist │ │ └── image3.png ├── 4-reliability │ └── images │ │ ├── layer.png │ │ ├── monolith.png │ │ ├── raw.graffle │ │ ├── retries.png │ │ ├── timeouts.png │ │ ├── fat_client.png │ │ ├── rate_limit.png │ │ ├── microservices.png │ │ ├── circuit_breaking.png │ │ ├── load_balancing_1.png │ │ ├── load_balancing_2.png │ │ ├── load_balancing_3.png │ │ ├── load_balancing_4.png │ │ ├── outlier_detection.png │ │ └── service_discovery.png ├── 3-observability │ └── images │ │ ├── raw.graffle │ │ ├── statistics.png │ │ ├── architecture.png │ │ ├── observability.png │ │ └── internal_external.png ├── Dockerfile ├── README-OLD.md ├── Makefile └── README.md ├── .gitignore ├── SETUP.md ├── LICENSE └── README.md /k8s-config/consul/.helmignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .terraform/ 3 | bin/ 4 | test/ 5 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/.helmignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .terraform/ 3 | bin/ 4 | test/ 5 | -------------------------------------------------------------------------------- /exercises/images/lab01-grafana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-grafana.png -------------------------------------------------------------------------------- /slides/2-security/images/bypass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/bypass.png -------------------------------------------------------------------------------- /exercises/images/lab01-consul-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-consul-ui.png -------------------------------------------------------------------------------- /exercises/images/lab01-emojify-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-emojify-app.png -------------------------------------------------------------------------------- /exercises/images/lab01-prometheus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-prometheus.png -------------------------------------------------------------------------------- /slides/1-overview/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/overview.png -------------------------------------------------------------------------------- /slides/2-security/images/firewall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/firewall.png -------------------------------------------------------------------------------- /slides/2-security/images/segment_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/segment_1.png -------------------------------------------------------------------------------- /slides/2-security/images/segment_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/segment_2.png -------------------------------------------------------------------------------- /slides/4-reliability/images/layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/layer.png -------------------------------------------------------------------------------- /exercises/images/lab01-grafana-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-grafana-home.png -------------------------------------------------------------------------------- /k8s-config/consul/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .terraform/ 3 | .terraform.tfstate* 4 | terraform.tfstate* 5 | terraform.tfvars 6 | values.dev.yaml 7 | -------------------------------------------------------------------------------- /slides/4-reliability/images/monolith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/monolith.png -------------------------------------------------------------------------------- /slides/4-reliability/images/raw.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/raw.graffle -------------------------------------------------------------------------------- /slides/4-reliability/images/retries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/retries.png -------------------------------------------------------------------------------- /slides/4-reliability/images/timeouts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/timeouts.png -------------------------------------------------------------------------------- /exercises/images/emojify-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/emojify-architecture.png -------------------------------------------------------------------------------- /exercises/images/lab03-envoy-statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-envoy-statistics.png -------------------------------------------------------------------------------- /exercises/images/lab03-intentions-deny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-intentions-deny.png -------------------------------------------------------------------------------- /exercises/images/lab03-query-prometheus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-query-prometheus.png -------------------------------------------------------------------------------- /slides/1-overview/images/architecture_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/architecture_1.png -------------------------------------------------------------------------------- /slides/1-overview/images/architecture_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/architecture_2.png -------------------------------------------------------------------------------- /slides/1-overview/images/architecture_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/architecture_3.png -------------------------------------------------------------------------------- /slides/1-overview/images/architecture_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/architecture_4.png -------------------------------------------------------------------------------- /slides/1-overview/images/architecture_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/architecture_5.png -------------------------------------------------------------------------------- /slides/2-security/images/data_plane_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/data_plane_1.png -------------------------------------------------------------------------------- /slides/2-security/images/data_plane_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/data_plane_2.png -------------------------------------------------------------------------------- /slides/2-security/images/data_plane_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/data_plane_3.png -------------------------------------------------------------------------------- /slides/2-security/images/data_plane_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/data_plane_4.png -------------------------------------------------------------------------------- /slides/2-security/images/data_plane_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/data_plane_5.png -------------------------------------------------------------------------------- /slides/2-security/images/data_plane_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/data_plane_6.png -------------------------------------------------------------------------------- /slides/3-observability/images/raw.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/3-observability/images/raw.graffle -------------------------------------------------------------------------------- /slides/4-reliability/images/fat_client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/fat_client.png -------------------------------------------------------------------------------- /slides/4-reliability/images/rate_limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/rate_limit.png -------------------------------------------------------------------------------- /exercises/images/lab01-configure-grafana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-configure-grafana.png -------------------------------------------------------------------------------- /exercises/images/lab03-envoy-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-envoy-architecture.png -------------------------------------------------------------------------------- /exercises/images/lab03-envoy-connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-envoy-connections.png -------------------------------------------------------------------------------- /exercises/images/lab03-intentions-list-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-intentions-list-01.png -------------------------------------------------------------------------------- /exercises/images/lab03-intentions-list-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-intentions-list-02.png -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/_helpers.bash: -------------------------------------------------------------------------------- 1 | # chart_dir returns the directory for the chart 2 | chart_dir() { 3 | echo ${BATS_TEST_DIRNAME}/../.. 4 | } 5 | -------------------------------------------------------------------------------- /slides/1-overview/images/service_registry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/service_registry.png -------------------------------------------------------------------------------- /slides/3-observability/images/statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/3-observability/images/statistics.png -------------------------------------------------------------------------------- /slides/4-reliability/images/microservices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/microservices.png -------------------------------------------------------------------------------- /exercises/images/lab01-grafana-create-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-grafana-create-import.png -------------------------------------------------------------------------------- /exercises/images/lab01-instruqt-environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-instruqt-environment.png -------------------------------------------------------------------------------- /exercises/images/lab02-consul-sidecar-inject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab02-consul-sidecar-inject.png -------------------------------------------------------------------------------- /slides/1-overview/images/raw.graffle/data.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/raw.graffle/data.plist -------------------------------------------------------------------------------- /slides/1-overview/images/raw.graffle/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/1-overview/images/raw.graffle/image3.png -------------------------------------------------------------------------------- /slides/2-security/images/network_isolation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/network_isolation.png -------------------------------------------------------------------------------- /slides/3-observability/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/3-observability/images/architecture.png -------------------------------------------------------------------------------- /slides/3-observability/images/observability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/3-observability/images/observability.png -------------------------------------------------------------------------------- /slides/4-reliability/images/circuit_breaking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/circuit_breaking.png -------------------------------------------------------------------------------- /slides/4-reliability/images/load_balancing_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/load_balancing_1.png -------------------------------------------------------------------------------- /slides/4-reliability/images/load_balancing_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/load_balancing_2.png -------------------------------------------------------------------------------- /slides/4-reliability/images/load_balancing_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/load_balancing_3.png -------------------------------------------------------------------------------- /slides/4-reliability/images/load_balancing_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/load_balancing_4.png -------------------------------------------------------------------------------- /exercises/images/lab01-grafana-add-data-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-grafana-add-data-source.png -------------------------------------------------------------------------------- /exercises/images/lab03-envoy-connections-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab03-envoy-connections-edit.png -------------------------------------------------------------------------------- /slides/2-security/images/dynamic_environments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/dynamic_environments.png -------------------------------------------------------------------------------- /slides/2-security/images/network_segmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/network_segmentation.png -------------------------------------------------------------------------------- /slides/2-security/images/service_segmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/service_segmentation.png -------------------------------------------------------------------------------- /slides/2-security/images/vulnerable_service_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/vulnerable_service_1.png -------------------------------------------------------------------------------- /slides/2-security/images/vulnerable_service_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/vulnerable_service_2.png -------------------------------------------------------------------------------- /slides/4-reliability/images/outlier_detection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/outlier_detection.png -------------------------------------------------------------------------------- /slides/4-reliability/images/service_discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/4-reliability/images/service_discovery.png -------------------------------------------------------------------------------- /slides/2-security/images/application_deployment_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/application_deployment_1.png -------------------------------------------------------------------------------- /slides/2-security/images/application_deployment_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/application_deployment_2.png -------------------------------------------------------------------------------- /slides/2-security/images/application_deployment_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/application_deployment_3.png -------------------------------------------------------------------------------- /slides/2-security/images/application_deployment_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/2-security/images/application_deployment_4.png -------------------------------------------------------------------------------- /slides/3-observability/images/internal_external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/slides/3-observability/images/internal_external.png -------------------------------------------------------------------------------- /exercises/images/lab01-grafana-dashboard-import-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-grafana-dashboard-import-01.png -------------------------------------------------------------------------------- /exercises/images/lab01-grafana-dashboard-import-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp/service-mesh-training/HEAD/exercises/images/lab01-grafana-dashboard-import-02.png -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .terraform/ 3 | .terraform.tfstate* 4 | terraform.tfstate* 5 | terraform.tfvars 6 | values.dev.yaml 7 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/_helpers.bash: -------------------------------------------------------------------------------- 1 | # chart_dir returns the directory for the chart 2 | chart_dir() { 3 | echo ${BATS_TEST_DIRNAME}/../.. 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # .tfvars files 9 | *.tfvars 10 | 11 | .vscode 12 | -------------------------------------------------------------------------------- /k8s-config/consul/Makefile: -------------------------------------------------------------------------------- 1 | TEST_IMAGE?=consul-helm-test 2 | 3 | test-docker: 4 | @docker build --rm -t '$(TEST_IMAGE)' -f $(CURDIR)/test/docker/Test.dockerfile $(CURDIR) 5 | 6 | .PHONY: test-docker 7 | -------------------------------------------------------------------------------- /k8s-config/consul/test/terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cluster_id" { 2 | value = "${google_container_cluster.cluster.id}" 3 | } 4 | 5 | output "cluster_name" { 6 | value = "${google_container_cluster.cluster.name}" 7 | } 8 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/README.md: -------------------------------------------------------------------------------- 1 | # Lab 01-B: Install Consul via Helm Chart 2 | 3 | Here you'll install Consul into your Kubernetes cluster using Helm. 4 | 5 | ``` 6 | $ helm install -f values.yaml /path/to/chart 7 | ``` 8 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/Makefile: -------------------------------------------------------------------------------- 1 | TEST_IMAGE?=consul-helm-test 2 | 3 | test-docker: 4 | @docker build --rm -t '$(TEST_IMAGE)' -f $(CURDIR)/test/docker/Test.dockerfile $(CURDIR) 5 | 6 | .PHONY: test-docker 7 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cluster_id" { 2 | value = "${google_container_cluster.cluster.id}" 3 | } 4 | 5 | output "cluster_name" { 6 | value = "${google_container_cluster.cluster.name}" 7 | } 8 | -------------------------------------------------------------------------------- /k8s-config/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-04/03-retries/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-04/01-load-balancing/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-04/02-timeouts/part1/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-04/02-timeouts/part2/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-01/03-install-emojify-app/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-04/04-outlier-detection/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-02/01-enable-connect-inject/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /k8s-config/consul/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: consul 3 | version: 0.5.0 4 | description: Install and configure Consul on Kubernetes. 5 | home: https://www.consul.io 6 | sources: 7 | - https://github.com/hashicorp/consul 8 | - https://github.com/hashicorp/consul-helm 9 | - https://github.com/hashicorp/consul-k8s 10 | -------------------------------------------------------------------------------- /exercises/lab-03/01-configure-envoy-statistics/files/app/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: emojify 6 | type: Opaque 7 | data: 8 | mb_key: YW1GamEzTnZiaTV1YVdOQVoyMWhhV3d1WTI5dC40OW90b0MxRzNPcDRQS1NRbFlZQzMyVExmMXkxWGRpbjhBODIzenNOM3ZSblBzcDY1MFVSXzJYUVNKWklVbnltSV9CSTl5d0FwV01Jdnlwd0pwNU5XZwo= 9 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: consul 3 | version: 0.5.0 4 | description: Install and configure Consul on Kubernetes. 5 | home: https://www.consul.io 6 | sources: 7 | - https://github.com/hashicorp/consul 8 | - https://github.com/hashicorp/consul-helm 9 | - https://github.com/hashicorp/consul-k8s 10 | -------------------------------------------------------------------------------- /k8s-config/monitoring/metrics-server/metrics-server-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: metrics-server 6 | namespace: kube-system 7 | labels: 8 | kubernetes.io/name: "Metrics-server" 9 | spec: 10 | selector: 11 | k8s-app: metrics-server 12 | ports: 13 | - port: 443 14 | protocol: TCP 15 | targetPort: 443 16 | -------------------------------------------------------------------------------- /exercises/lab-01/04-install-prometheus-and-grafana/files/metrics-server/metrics-server-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: metrics-server 6 | namespace: kube-system 7 | labels: 8 | kubernetes.io/name: "Metrics-server" 9 | spec: 10 | selector: 11 | k8s-app: metrics-server 12 | ports: 13 | - port: 443 14 | protocol: TCP 15 | targetPort: 443 16 | -------------------------------------------------------------------------------- /k8s-config/monitoring/metrics-server/auth-delegator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: metrics-server:system:auth-delegator 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: system:auth-delegator 10 | subjects: 11 | - kind: ServiceAccount 12 | name: metrics-server 13 | namespace: kube-system 14 | -------------------------------------------------------------------------------- /k8s-config/monitoring/metrics-server/metrics-apiservice.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiregistration.k8s.io/v1beta1 3 | kind: APIService 4 | metadata: 5 | name: v1beta1.metrics.k8s.io 6 | spec: 7 | service: 8 | name: metrics-server 9 | namespace: kube-system 10 | group: metrics.k8s.io 11 | version: v1beta1 12 | insecureSkipTLSVerify: true 13 | groupPriorityMinimum: 100 14 | versionPriority: 100 15 | -------------------------------------------------------------------------------- /k8s-config/app/templates/envoy_init.dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk update && apk add gettext 4 | 5 | # Add Consul 6 | RUN wget https://releases.hashicorp.com/consul/1.4.2/consul_1.4.2_linux_amd64.zip -O ./consul.zip && unzip ./consul.zip && mv ./consul /bin && rm ./consul.zip 7 | 8 | RUN mkdir /app 9 | COPY ./init.sh /app 10 | RUN chmod +x /app/init.sh 11 | 12 | WORKDIR /app 13 | 14 | ENTRYPOINT "/app/init.sh" 15 | -------------------------------------------------------------------------------- /k8s-config/monitoring/metrics-server/auth-reader.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: RoleBinding 4 | metadata: 5 | name: metrics-server-auth-reader 6 | namespace: kube-system 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: Role 10 | name: extension-apiserver-authentication-reader 11 | subjects: 12 | - kind: ServiceAccount 13 | name: metrics-server 14 | namespace: kube-system 15 | -------------------------------------------------------------------------------- /exercises/lab-01/04-install-prometheus-and-grafana/files/metrics-server/auth-delegator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: metrics-server:system:auth-delegator 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: system:auth-delegator 10 | subjects: 11 | - kind: ServiceAccount 12 | name: metrics-server 13 | namespace: kube-system 14 | -------------------------------------------------------------------------------- /exercises/lab-01/04-install-prometheus-and-grafana/files/metrics-server/metrics-apiservice.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiregistration.k8s.io/v1beta1 3 | kind: APIService 4 | metadata: 5 | name: v1beta1.metrics.k8s.io 6 | spec: 7 | service: 8 | name: metrics-server 9 | namespace: kube-system 10 | group: metrics.k8s.io 11 | version: v1beta1 12 | insecureSkipTLSVerify: true 13 | groupPriorityMinimum: 100 14 | versionPriority: 100 15 | -------------------------------------------------------------------------------- /k8s-config/consul/test/acceptance/server.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "server: default, comes up healthy" { 6 | helm_install 7 | wait_for_ready $(name_prefix)-server-0 8 | 9 | # Verify there are three servers 10 | local server_count=$(kubectl exec "$(name_prefix)-server-0" consul members | 11 | grep server | 12 | wc -l) 13 | [ "${server_count}" -eq "3" ] 14 | 15 | # Clean up 16 | helm_delete 17 | } 18 | -------------------------------------------------------------------------------- /exercises/lab-01/04-install-prometheus-and-grafana/files/metrics-server/auth-reader.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: RoleBinding 4 | metadata: 5 | name: metrics-server-auth-reader 6 | namespace: kube-system 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: Role 10 | name: extension-apiserver-authentication-reader 11 | subjects: 12 | - kind: ServiceAccount 13 | name: metrics-server 14 | namespace: kube-system 15 | -------------------------------------------------------------------------------- /k8s-config/consul/test/terraform/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: helm 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1beta1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: helm 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: helm 18 | namespace: kube-system 19 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/acceptance/server.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "server: default, comes up healthy" { 6 | helm_install 7 | wait_for_ready $(name_prefix)-server-0 8 | 9 | # Verify there are three servers 10 | local server_count=$(kubectl exec "$(name_prefix)-server-0" consul members | 11 | grep server | 12 | wc -l) 13 | [ "${server_count}" -eq "3" ] 14 | 15 | # Clean up 16 | helm_delete 17 | } 18 | -------------------------------------------------------------------------------- /k8s-config/app/templates/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Process the config 4 | envsubst < /init/envoy_bootstrap.yaml | tee /consul-init/bootstrap.yaml 5 | envsubst < /init/envoy_consul_config.hcl | tee /consul-init/envoy_consul_config.hcl 6 | 7 | # Add the consul binary to the shared volume to allow deregistration 8 | cp /bin/consul /consul-init 9 | 10 | # Register the service with consul 11 | /bin/consul services register -http-addr=http://${HOST_IP}:8500 /consul-init/envoy_consul_config.hcl 12 | -------------------------------------------------------------------------------- /k8s-config/monitoring/metrics-server/aggregated-metrics-reader.yaml: -------------------------------------------------------------------------------- 1 | kind: ClusterRole 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: system:aggregated-metrics-reader 5 | labels: 6 | rbac.authorization.k8s.io/aggregate-to-view: "true" 7 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 8 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 9 | rules: 10 | - apiGroups: ["metrics.k8s.io"] 11 | resources: ["pods"] 12 | verbs: ["get", "list", "watch"] 13 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/terraform/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: helm 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1beta1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: helm 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: helm 18 | namespace: kube-system 19 | -------------------------------------------------------------------------------- /exercises/lab-01/04-install-prometheus-and-grafana/files/metrics-server/aggregated-metrics-reader.yaml: -------------------------------------------------------------------------------- 1 | kind: ClusterRole 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: system:aggregated-metrics-reader 5 | labels: 6 | rbac.authorization.k8s.io/aggregate-to-view: "true" 7 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 8 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 9 | rules: 10 | - apiGroups: ["metrics.k8s.io"] 11 | resources: ["pods"] 12 | verbs: ["get", "list", "watch"] 13 | -------------------------------------------------------------------------------- /slides/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | RUN apk update && apk add yarn git 4 | RUN yarn global add babel-cli 5 | 6 | RUN mkdir /home/md2gslides 7 | RUN adduser -h /home/md2gslides -D md2gslides 8 | RUN chown md2gslides /home/md2gslides 9 | 10 | RUN mkdir /md2gslides 11 | RUN git clone --single-branch --branch merge_nic https://github.com/nicholasjackson/md2googleslides.git /md2gslides 12 | WORKDIR /md2gslides 13 | RUN yarn install && yarn compile 14 | 15 | WORKDIR /slides 16 | USER md2gslides 17 | 18 | ENTRYPOINT ["node", "/md2gslides/bin/md2gslides.js"] 19 | -------------------------------------------------------------------------------- /exercises/lab-03/03-requests/index.md: -------------------------------------------------------------------------------- 1 | # Lab 03, Exercise 03: Downstream Requests 2 | 3 | **Objective:** Create a visualization of downstream requests. 4 | 5 | As with the previous exercise, you'll use the **lab03 - API** dashboard. 6 | 7 | Open the **Envoy Inbound Requests (downstream)** panel. 8 | 9 | ## Step 1 10 | 11 | In the query with legend `{{envoy_response_code_class}}xx-{{name}}` put the following: 12 | 13 | ``` 14 | sum(increase(envoy_http_downstream_rq_xx{envoy_http_conn_manager_prefix="ingress_api", name=~"^$pod_name$"}[30s])) by (envoy_response_code_class,name) 15 | ``` 16 | -------------------------------------------------------------------------------- /k8s-config/consul/test/terraform/variables.tf: -------------------------------------------------------------------------------- 1 | variable "project" { 2 | description = < 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "dns/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/dns-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'dns.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "dns/Service: disable with dns.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/dns-service.yaml \ 29 | --set 'dns.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "dns/Service: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/dns-service.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/dns-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "dns/Service: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/dns-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "dns/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/dns-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'dns.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "dns/Service: disable with dns.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/dns-service.yaml \ 29 | --set 'dns.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "dns/Service: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/dns-service.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | -------------------------------------------------------------------------------- /exercises/lab-04/01-load-balancing/index.md: -------------------------------------------------------------------------------- 1 | # Lab 04, Exercise 01: Load Balancing 2 | 3 | **Objective:** Delpoy 2nd API service, enable round-robin load balancing with updated Envoy config, and use Grafana to verify visually traffic is being balanced between the new services. 4 | 5 | ## Step 1: Deploy second API service to the cluster 6 | 7 | First, navigate to this exercise's directory: 8 | 9 | ``` 10 | cd ~/service-mesh-training/exercises/lab-04/01-load-balancing/ 11 | ``` 12 | 13 | Take a look at the updated Kubernetes config files in `files/app` and see where we are adding second service. 14 | 15 | Now apply the updated config files: 16 | 17 | ``` 18 | kubectl apply -f files/app 19 | 20 | deployment.apps/emojify-api-2 created 21 | configmap/emojify-api-configmap unchanged 22 | deployment.apps/emojify-api configured 23 | configmap/emojify-cache-configmap unchanged 24 | deployment.apps/emojify-cache configured 25 | configmap/emojify-facebox-configmap unchanged 26 | deployment.apps/emojify-facebox configured 27 | service/emojify-ingress unchanged 28 | configmap/emojify-ingress-configmap unchanged 29 | deployment.apps/emojify-ingress configured 30 | secret/emojify unchanged 31 | configmap/emojify-website-configmap unchanged 32 | deployment.apps/emojify-website configured 33 | ``` 34 | 35 | ## Step 2: Verify round robin load balancing 36 | 37 | Look at dashboards. 38 | 39 | -------------------------------------------------------------------------------- /k8s-config/consul/templates/connect-inject-mutatingwebhook.yaml: -------------------------------------------------------------------------------- 1 | # The MutatingWebhookConfiguration to enable the Connect injector. 2 | {{- if (or (and (ne (.Values.connectInject.enabled | toString) "-") .Values.connectInject.enabled) (and (eq (.Values.connectInject.enabled | toString) "-") .Values.global.enabled)) }} 3 | apiVersion: admissionregistration.k8s.io/v1beta1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: {{ template "consul.fullname" . }}-connect-injector-cfg 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | app: {{ template "consul.name" . }} 10 | chart: {{ template "consul.chart" . }} 11 | heritage: {{ .Release.Service }} 12 | release: {{ .Release.Name }} 13 | webhooks: 14 | - name: {{ template "consul.fullname" . }}-connect-injector.consul.hashicorp.com 15 | clientConfig: 16 | service: 17 | name: {{ template "consul.fullname" . }}-connect-injector-svc 18 | namespace: {{ .Release.Namespace }} 19 | path: "/mutate" 20 | caBundle: {{ .Values.connectInject.certs.caBundle }} 21 | rules: 22 | - operations: [ "CREATE" ] 23 | apiGroups: [""] 24 | apiVersions: ["v1"] 25 | resources: ["pods"] 26 | {{- if .Values.connectInject.namespaceSelector }} 27 | namespaceSelector: 28 | {{ tpl .Values.connectInject.namespaceSelector . | indent 6 }} 29 | {{- end }} 30 | {{- end }} 31 | -------------------------------------------------------------------------------- /exercises/lab-02/01-enable-connect-inject/files/app/api.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: emojify-api 6 | labels: 7 | app: emojify-api 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: emojify-api 13 | template: 14 | metadata: 15 | labels: 16 | app: emojify-api 17 | annotations: 18 | "consul.hashicorp.com/connect-inject": "true" 19 | "consul.hashicorp.com/connect-service-upstreams": "emojify-facebox:8000,emojify-cache:8001" 20 | spec: 21 | containers: 22 | - name: emojify-api 23 | image: "nicholasjackson/emojify-api:v0.8.0" 24 | imagePullPolicy: Always 25 | command: ["/service/emojify-api"] 26 | args: [ 27 | "-allow-origin=*", 28 | "-authn-disable=true", 29 | "-bind-address=0.0.0.0:9090", 30 | "-cache-address=localhost:8001", 31 | "-facebox-address=localhost:8000", 32 | "-path=/", 33 | ] 34 | ports: 35 | - containerPort: 9090 36 | livenessProbe: 37 | httpGet: 38 | path: /health 39 | port: 9090 40 | initialDelaySeconds: 10 41 | periodSeconds: 30 42 | resources: 43 | limits: 44 | cpu: 300m 45 | requests: 46 | cpu: 100m 47 | memory: 100Mi 48 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/templates/connect-inject-mutatingwebhook.yaml: -------------------------------------------------------------------------------- 1 | # The MutatingWebhookConfiguration to enable the Connect injector. 2 | {{- if (or (and (ne (.Values.connectInject.enabled | toString) "-") .Values.connectInject.enabled) (and (eq (.Values.connectInject.enabled | toString) "-") .Values.global.enabled)) }} 3 | apiVersion: admissionregistration.k8s.io/v1beta1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: {{ template "consul.fullname" . }}-connect-injector-cfg 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | app: {{ template "consul.name" . }} 10 | chart: {{ template "consul.chart" . }} 11 | heritage: {{ .Release.Service }} 12 | release: {{ .Release.Name }} 13 | webhooks: 14 | - name: {{ template "consul.fullname" . }}-connect-injector.consul.hashicorp.com 15 | clientConfig: 16 | service: 17 | name: {{ template "consul.fullname" . }}-connect-injector-svc 18 | namespace: {{ .Release.Namespace }} 19 | path: "/mutate" 20 | caBundle: {{ .Values.connectInject.certs.caBundle }} 21 | rules: 22 | - operations: [ "CREATE" ] 23 | apiGroups: [""] 24 | apiVersions: ["v1"] 25 | resources: ["pods"] 26 | {{- if .Values.connectInject.namespaceSelector }} 27 | namespaceSelector: 28 | {{ tpl .Values.connectInject.namespaceSelector . | indent 6 }} 29 | {{- end }} 30 | {{- end }} 31 | -------------------------------------------------------------------------------- /exercises/lab-02/01-enable-connect-inject/files/app/website.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: emojify-website-configmap 6 | data: 7 | config: | 8 | window.env = {}; 9 | window.env.config = { 10 | AUTH_URL: '/auth', 11 | API_URL: '/api/', 12 | HOME_URL: '/', 13 | PAYMENT_URL: '/api/payments', 14 | PAYMENT_ENABLED: false, 15 | OAUTH_ENABLED: false, 16 | AUTH_DISABLED: true 17 | }; 18 | 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: emojify-website 24 | labels: 25 | app: emojify-website 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app: emojify-website 31 | template: 32 | metadata: 33 | labels: 34 | app: emojify-website 35 | annotations: 36 | "consul.hashicorp.com/connect-inject": "true" 37 | spec: 38 | volumes: 39 | - name: config 40 | configMap: 41 | name: emojify-website-configmap 42 | items: 43 | - key: config 44 | path: env.js 45 | containers: 46 | - name: emojify-website 47 | image: "nicholasjackson/emojify-website:v0.6.2" 48 | imagePullPolicy: Always 49 | ports: 50 | - containerPort: 80 51 | volumeMounts: 52 | - name: config 53 | mountPath: /usr/share/nginx/html/config 54 | readOnly: true 55 | 56 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/connect-inject-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "connectInject/Service: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/connect-inject-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "connectInject/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/connect-inject-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'connectInject.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "connectInject/Service: disable with connectInject.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/connect-inject-service.yaml \ 29 | --set 'connectInject.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "connectInject/Service: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/connect-inject-service.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | -------------------------------------------------------------------------------- /exercises/lab-03/02-connections/index.md: -------------------------------------------------------------------------------- 1 | # Lab 03, Exercise 02: Downstream Connections 2 | 3 | **Objective:** Create a visualization of downstream connections. 4 | 5 | Go to **Grafana** tab in Instruqt. Open **lab03 - API** dashboard. 6 | 7 | ![Envoy connections](../../images/lab03-envoy-connections.png "Envoy connections") 8 | 9 | Edit **Envoy Connections** panel. You'll notice there are empty queries with pre-populated legends. You'll complete these queries in each of the next steps. 10 | 11 | ![Envoy connections edit](../../images/lab03-envoy-connections-edit.png) 12 | 13 | ## Step 1: Total connections 14 | 15 | In query with legend `total`: 16 | ``` 17 | sum(increase(envoy_http_downstream_cx_total{envoy_http_conn_manager_prefix="ingress_api", name=~"^$pod_name$"}[1m])) 18 | ``` 19 | 20 | ## Step 2: Active connections 21 | 22 | In query with legend `active`: 23 | ``` 24 | sum(increase(envoy_http_downstream_cx_active{envoy_http_conn_manager_prefix="ingress_api", name=~"^$pod_name$"}[1m])) 25 | ``` 26 | 27 | ## Step 3: Remote connections destroyed 28 | 29 | In query with legend `destroy-remote`: 30 | ``` 31 | sum(increase(envoy_http_downstream_cx_destroy_remote{envoy_http_conn_manager_prefix="ingress_api", name=~"^$pod_name$"}[1m])) 32 | ``` 33 | 34 | ## Step 4: Local connections destroyed 35 | 36 | In query with legend `destroy-local`: 37 | ``` 38 | sum(increase(envoy_http_downstream_cx_destroy_local{envoy_http_conn_manager_prefix="ingress_api", name=~"^$pod_name$"}[1m])) 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/connect-inject-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "connectInject/Service: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/connect-inject-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "connectInject/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/connect-inject-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'connectInject.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "connectInject/Service: disable with connectInject.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/connect-inject-service.yaml \ 29 | --set 'connectInject.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "connectInject/Service: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/connect-inject-service.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | -------------------------------------------------------------------------------- /k8s-config/consul/templates/ui-service.yaml: -------------------------------------------------------------------------------- 1 | # Headless service for Consul server DNS entries. This service should only 2 | # point to Consul servers. For access to an agent, one should assume that 3 | # the agent is installed locally on the node and the NODE_IP should be used. 4 | # If the node can't run a Consul agent, then this service can be used to 5 | # communicate directly to a server agent. 6 | {{- if (and (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) (or (and (ne (.Values.ui.enabled | toString) "-") .Values.ui.enabled) (and (eq (.Values.ui.enabled | toString) "-") .Values.global.enabled)) (or (and (ne (.Values.ui.service.enabled | toString) "-") .Values.ui.service.enabled) (and (eq (.Values.ui.service.enabled | toString) "-") .Values.global.enabled))) }} 7 | apiVersion: v1 8 | kind: Service 9 | metadata: 10 | name: {{ template "consul.fullname" . }}-ui 11 | namespace: {{ .Release.Namespace }} 12 | labels: 13 | app: {{ template "consul.name" . }} 14 | chart: {{ template "consul.chart" . }} 15 | heritage: {{ .Release.Service }} 16 | release: {{ .Release.Name }} 17 | spec: 18 | selector: 19 | app: {{ template "consul.name" . }} 20 | release: "{{ .Release.Name }}" 21 | component: server 22 | ports: 23 | - name: http 24 | port: 80 25 | targetPort: 8500 26 | {{- if .Values.ui.service.type }} 27 | type: {{ .Values.ui.service.type }} 28 | {{- end }} 29 | {{- end }} 30 | -------------------------------------------------------------------------------- /exercises/lab-01/03-install-emojify-app/files/app/facebox.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: emojify-facebox 6 | spec: 7 | selector: 8 | app: emojify-facebox 9 | ports: 10 | - protocol: TCP 11 | port: 80 12 | targetPort: 8080 13 | 14 | --- 15 | apiVersion: apps/v1 16 | kind: Deployment 17 | metadata: 18 | name: emojify-facebox 19 | labels: 20 | app: emojify-facebox 21 | spec: 22 | replicas: 1 23 | selector: 24 | matchLabels: 25 | app: emojify-facebox 26 | template: 27 | metadata: 28 | labels: 29 | app: emojify-facebox 30 | annotations: 31 | "prometheus_io_scrape": "true" 32 | spec: 33 | containers: 34 | - name: emojify-facebox 35 | image: "machinebox/facebox" 36 | ports: 37 | - containerPort: 8080 38 | env: 39 | - name: MB_KEY 40 | valueFrom: 41 | secretKeyRef: 42 | name: emojify 43 | key: mb_key 44 | - name: MB_ADDRESS 45 | value: "0.0.0.0" 46 | - name: MB_PORT 47 | value: "8080" 48 | 49 | - name: prometheus-statsd 50 | image: prom/statsd-exporter:latest 51 | ports: 52 | - name: metrics 53 | containerPort: 9102 54 | resources: 55 | limits: 56 | memory: 100Mi 57 | requests: 58 | cpu: 100m 59 | memory: 100Mi -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/templates/ui-service.yaml: -------------------------------------------------------------------------------- 1 | # Headless service for Consul server DNS entries. This service should only 2 | # point to Consul servers. For access to an agent, one should assume that 3 | # the agent is installed locally on the node and the NODE_IP should be used. 4 | # If the node can't run a Consul agent, then this service can be used to 5 | # communicate directly to a server agent. 6 | {{- if (and (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) (or (and (ne (.Values.ui.enabled | toString) "-") .Values.ui.enabled) (and (eq (.Values.ui.enabled | toString) "-") .Values.global.enabled)) (or (and (ne (.Values.ui.service.enabled | toString) "-") .Values.ui.service.enabled) (and (eq (.Values.ui.service.enabled | toString) "-") .Values.global.enabled))) }} 7 | apiVersion: v1 8 | kind: Service 9 | metadata: 10 | name: {{ template "consul.fullname" . }}-ui 11 | namespace: {{ .Release.Namespace }} 12 | labels: 13 | app: {{ template "consul.name" . }} 14 | chart: {{ template "consul.chart" . }} 15 | heritage: {{ .Release.Service }} 16 | release: {{ .Release.Name }} 17 | spec: 18 | selector: 19 | app: {{ template "consul.name" . }} 20 | release: "{{ .Release.Name }}" 21 | component: server 22 | ports: 23 | - name: http 24 | port: 80 25 | targetPort: 8500 26 | {{- if .Values.ui.service.type }} 27 | type: {{ .Values.ui.service.type }} 28 | {{- end }} 29 | {{- end }} 30 | -------------------------------------------------------------------------------- /k8s-config/consul/test/docker/Test.dockerfile: -------------------------------------------------------------------------------- 1 | # This Dockerfile installs all the dependencies necessary to run the unit and 2 | # acceptance tests. This image also contains gcloud so you can run tests 3 | # against a GKE cluster easily. 4 | # 5 | # This image has no automatic entrypoint. It is expected that you'll run 6 | # a script to configure kubectl, potentially install Helm, and run the tests 7 | # manually. This image only has the dependencies pre-installed. 8 | 9 | FROM alpine:latest 10 | WORKDIR /root 11 | 12 | ENV BATS_VERSION "1.1.0" 13 | 14 | # base packages 15 | RUN apk update && apk add --no-cache --virtual .build-deps \ 16 | ca-certificates \ 17 | curl \ 18 | tar \ 19 | bash \ 20 | openssl \ 21 | python \ 22 | py-pip \ 23 | git \ 24 | jq 25 | 26 | # yq 27 | RUN pip install yq 28 | 29 | # gcloud 30 | RUN curl -OL https://dl.google.com/dl/cloudsdk/channels/rapid/install_google_cloud_sdk.bash && \ 31 | bash install_google_cloud_sdk.bash --disable-prompts --install-dir='/root/' && \ 32 | ln -s /root/google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud 33 | 34 | # kubectl 35 | RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \ 36 | chmod +x ./kubectl && \ 37 | mv ./kubectl /usr/local/bin/kubectl 38 | 39 | # helm 40 | RUN curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash 41 | 42 | # bats 43 | RUN curl -sSL https://github.com/bats-core/bats-core/archive/v${BATS_VERSION}.tar.gz -o /tmp/bats.tgz \ 44 | && tar -zxf /tmp/bats.tgz -C /tmp \ 45 | && /bin/bash /tmp/bats-core-$BATS_VERSION/install.sh /usr/local 46 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/docker/Test.dockerfile: -------------------------------------------------------------------------------- 1 | # This Dockerfile installs all the dependencies necessary to run the unit and 2 | # acceptance tests. This image also contains gcloud so you can run tests 3 | # against a GKE cluster easily. 4 | # 5 | # This image has no automatic entrypoint. It is expected that you'll run 6 | # a script to configure kubectl, potentially install Helm, and run the tests 7 | # manually. This image only has the dependencies pre-installed. 8 | 9 | FROM alpine:latest 10 | WORKDIR /root 11 | 12 | ENV BATS_VERSION "1.1.0" 13 | 14 | # base packages 15 | RUN apk update && apk add --no-cache --virtual .build-deps \ 16 | ca-certificates \ 17 | curl \ 18 | tar \ 19 | bash \ 20 | openssl \ 21 | python \ 22 | py-pip \ 23 | git \ 24 | jq 25 | 26 | # yq 27 | RUN pip install yq 28 | 29 | # gcloud 30 | RUN curl -OL https://dl.google.com/dl/cloudsdk/channels/rapid/install_google_cloud_sdk.bash && \ 31 | bash install_google_cloud_sdk.bash --disable-prompts --install-dir='/root/' && \ 32 | ln -s /root/google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud 33 | 34 | # kubectl 35 | RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \ 36 | chmod +x ./kubectl && \ 37 | mv ./kubectl /usr/local/bin/kubectl 38 | 39 | # helm 40 | RUN curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash 41 | 42 | # bats 43 | RUN curl -sSL https://github.com/bats-core/bats-core/archive/v${BATS_VERSION}.tar.gz -o /tmp/bats.tgz \ 44 | && tar -zxf /tmp/bats.tgz -C /tmp \ 45 | && /bin/bash /tmp/bats-core-$BATS_VERSION/install.sh /usr/local 46 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/client-configmap.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "client/ConfigMap: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/client-config-configmap.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "client/ConfigMap: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/client-config-configmap.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'client.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "client/ConfigMap: disable with client.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/client-config-configmap.yaml \ 29 | --set 'client.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "client/ConfigMap: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/client-config-configmap.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "client/ConfigMap: extraConfig is set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/client-config-configmap.yaml \ 49 | --set 'client.extraConfig="{\"hello\": \"world\"}"' \ 50 | . | tee /dev/stderr | 51 | yq '.data["extra-from-values.json"] | match("world") | length' | tee /dev/stderr) 52 | [ ! -z "${actual}" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/server-configmap.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "server/ConfigMap: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/server-config-configmap.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "server/ConfigMap: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/server-config-configmap.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'server.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "server/ConfigMap: disable with server.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/server-config-configmap.yaml \ 29 | --set 'server.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "server/ConfigMap: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/server-config-configmap.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "server/ConfigMap: extraConfig is set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/server-config-configmap.yaml \ 49 | --set 'server.extraConfig="{\"hello\": \"world\"}"' \ 50 | . | tee /dev/stderr | 51 | yq '.data["extra-from-values.json"] | match("world") | length' | tee /dev/stderr) 52 | [ ! -z "${actual}" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/sync-catalog-cluster-role.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "sync/ClusterRole: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/sync-catalog-cluster-role.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "sync/ClusterRole: disabled with global.enabled=false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/sync-catalog-cluster-role.yaml \ 18 | --set 'global.enabled=false' \ 19 | . | tee /dev/stderr | 20 | yq 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "false" ] 22 | } 23 | 24 | @test "sync/ClusterRole: disabled with sync disabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/sync-catalog-cluster-role.yaml \ 28 | --set 'syncCatalog.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "sync/ClusterRole: enabled with sync enabled" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/sync-catalog-cluster-role.yaml \ 38 | --set 'syncCatalog.enabled=true' \ 39 | . | tee /dev/stderr | 40 | yq 'length > 0' | tee /dev/stderr) 41 | [ "${actual}" = "true" ] 42 | } 43 | 44 | @test "sync/ClusterRole: enabled with sync enabled and global.enabled=false" { 45 | cd `chart_dir` 46 | local actual=$(helm template \ 47 | -x templates/sync-catalog-cluster-role.yaml \ 48 | --set 'global.enabled=false' \ 49 | --set 'syncCatalog.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq -s 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/sync-service-account.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "sync/ServiceAccount: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/sync-catalog-service-account.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "sync/ServiceAccount: disabled with global.enabled=false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/sync-catalog-service-account.yaml \ 18 | --set 'global.enabled=false' \ 19 | . | tee /dev/stderr | 20 | yq 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "false" ] 22 | } 23 | 24 | @test "sync/ServiceAccount: disabled with sync disabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/sync-catalog-service-account.yaml \ 28 | --set 'syncCatalog.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "sync/ServiceAccount: enabled with sync enabled" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/sync-catalog-service-account.yaml \ 38 | --set 'syncCatalog.enabled=true' \ 39 | . | tee /dev/stderr | 40 | yq 'length > 0' | tee /dev/stderr) 41 | [ "${actual}" = "true" ] 42 | } 43 | 44 | @test "sync/ServiceAccount: enabled with sync enabled and global.enabled=false" { 45 | cd `chart_dir` 46 | local actual=$(helm template \ 47 | -x templates/sync-catalog-service-account.yaml \ 48 | --set 'global.enabled=false' \ 49 | --set 'syncCatalog.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq -s 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/client-configmap.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "client/ConfigMap: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/client-config-configmap.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "client/ConfigMap: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/client-config-configmap.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'client.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "client/ConfigMap: disable with client.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/client-config-configmap.yaml \ 29 | --set 'client.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "client/ConfigMap: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/client-config-configmap.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "client/ConfigMap: extraConfig is set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/client-config-configmap.yaml \ 49 | --set 'client.extraConfig="{\"hello\": \"world\"}"' \ 50 | . | tee /dev/stderr | 51 | yq '.data["extra-from-values.json"] | match("world") | length' | tee /dev/stderr) 52 | [ ! -z "${actual}" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/server-configmap.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "server/ConfigMap: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/server-config-configmap.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "server/ConfigMap: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/server-config-configmap.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'server.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "server/ConfigMap: disable with server.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/server-config-configmap.yaml \ 29 | --set 'server.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "server/ConfigMap: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/server-config-configmap.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "server/ConfigMap: extraConfig is set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/server-config-configmap.yaml \ 49 | --set 'server.extraConfig="{\"hello\": \"world\"}"' \ 50 | . | tee /dev/stderr | 51 | yq '.data["extra-from-values.json"] | match("world") | length' | tee /dev/stderr) 52 | [ ! -z "${actual}" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/sync-catalog-cluster-role.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "sync/ClusterRole: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/sync-catalog-cluster-role.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "sync/ClusterRole: disabled with global.enabled=false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/sync-catalog-cluster-role.yaml \ 18 | --set 'global.enabled=false' \ 19 | . | tee /dev/stderr | 20 | yq 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "false" ] 22 | } 23 | 24 | @test "sync/ClusterRole: disabled with sync disabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/sync-catalog-cluster-role.yaml \ 28 | --set 'syncCatalog.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "sync/ClusterRole: enabled with sync enabled" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/sync-catalog-cluster-role.yaml \ 38 | --set 'syncCatalog.enabled=true' \ 39 | . | tee /dev/stderr | 40 | yq 'length > 0' | tee /dev/stderr) 41 | [ "${actual}" = "true" ] 42 | } 43 | 44 | @test "sync/ClusterRole: enabled with sync enabled and global.enabled=false" { 45 | cd `chart_dir` 46 | local actual=$(helm template \ 47 | -x templates/sync-catalog-cluster-role.yaml \ 48 | --set 'global.enabled=false' \ 49 | --set 'syncCatalog.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq -s 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/index.md: -------------------------------------------------------------------------------- 1 | # Labs for Service Mesh Workshop 2 | 3 | ## Lab 01: Setup 4 | 5 | In this set of exercises you'll get set up with the workshop environment and install the components you'll need for the rest of this workshop. 6 | 7 | * [01: Get Familiar with Environment](lab-01/01-get-familiar-with-environment/index.md) 8 | * [02: Install Consul via Helm Chart](lab-01/02-install-consul/index.md) 9 | * [03: Install emojify app](lab-01/03-install-emojify-app/index.md) 10 | * [04: Install Prometheus and Grafana](lab-01/04-install-prometheus-and-grafana/index.md) 11 | * [05: Configure Grafana](lab-01/05-configure-grafana/index.md) 12 | 13 | ## Lab 02: Security 14 | 15 | In this set of exercises you'll enable security features in the service mesh by congiuring Consul Connect sidecar injection and then Consul intentions. 16 | 17 | * [01: Enable Connect Sidecar Injection](lab-02/01-enable-connect-inject/index.md) 18 | * [02: Configure Intentions](lab-02/02-configure-intentions/index.md) 19 | 20 | ## Lab 03: Observability 21 | 22 | In this set of exercises you'll enable observability features of the service mesh and build a Grafana dashboard. 23 | 24 | * [01: Configure Envoy Statistics](lab-03/01-configure-envoy-statistics/index.md) 25 | * [02: Observing Envoy Connections](lab-03/02-connections/index.md) 26 | * [03: Observing Envoy Requests](lab-03/03-requests/index.md) 27 | * [04: Observing Envoy Authorizations](lab-03/04-authorizations/index.md) 28 | 29 | ## Lab 04: Reliability 30 | 31 | In this set of exercises you'll implement four reliability patterns: load balancing, timeouts, retries, and outlier detection (circuit breaking). 32 | 33 | * [01: Load Balancing](lab-04/01-load-balancing/index.md) 34 | * [02: Timeouts](lab-04/02-timeouts/index.md) 35 | * [03: Retries](lab-04/03-retries/index.md) 36 | * [04: Outlier Detection](lab-04/04-outlier-detection/index.md) 37 | 38 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/sync-service-account.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "sync/ServiceAccount: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/sync-catalog-service-account.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "sync/ServiceAccount: disabled with global.enabled=false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/sync-catalog-service-account.yaml \ 18 | --set 'global.enabled=false' \ 19 | . | tee /dev/stderr | 20 | yq 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "false" ] 22 | } 23 | 24 | @test "sync/ServiceAccount: disabled with sync disabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/sync-catalog-service-account.yaml \ 28 | --set 'syncCatalog.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "sync/ServiceAccount: enabled with sync enabled" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/sync-catalog-service-account.yaml \ 38 | --set 'syncCatalog.enabled=true' \ 39 | . | tee /dev/stderr | 40 | yq 'length > 0' | tee /dev/stderr) 41 | [ "${actual}" = "true" ] 42 | } 43 | 44 | @test "sync/ServiceAccount: enabled with sync enabled and global.enabled=false" { 45 | cd `chart_dir` 46 | local actual=$(helm template \ 47 | -x templates/sync-catalog-service-account.yaml \ 48 | --set 'global.enabled=false' \ 49 | --set 'syncCatalog.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq -s 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/sync-catalog-cluster-role-binding.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "sync/ClusterRoleBinding: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/sync-catalog-cluster-role-binding.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "sync/ClusterRoleBinding: disabled with global.enabled=false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/sync-catalog-cluster-role-binding.yaml \ 18 | --set 'global.enabled=false' \ 19 | . | tee /dev/stderr | 20 | yq 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "false" ] 22 | } 23 | 24 | @test "sync/ClusterRoleBinding: disabled with sync disabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/sync-catalog-cluster-role-binding.yaml \ 28 | --set 'syncCatalog.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "sync/ClusterRoleBinding: enabled with sync enabled" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/sync-catalog-cluster-role-binding.yaml \ 38 | --set 'syncCatalog.enabled=true' \ 39 | . | tee /dev/stderr | 40 | yq -s 'length > 0' | tee /dev/stderr) 41 | [ "${actual}" = "true" ] 42 | } 43 | 44 | @test "sync/ClusterRoleBinding: enabled with sync enabled and global.enabled=false" { 45 | cd `chart_dir` 46 | local actual=$(helm template \ 47 | -x templates/sync-catalog-cluster-role-binding.yaml \ 48 | --set 'global.enabled=false' \ 49 | --set 'syncCatalog.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq -s 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/03-install-emojify-app/files/app/api.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: emojify-api 6 | spec: 7 | selector: 8 | app: emojify-api 9 | ports: 10 | - name: http 11 | protocol: TCP 12 | port: 80 13 | targetPort: 9090 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: emojify-api-cache 20 | labels: 21 | app: emojify-api 22 | spec: 23 | replicas: 1 24 | selector: 25 | matchLabels: 26 | app: emojify-api 27 | template: 28 | metadata: 29 | labels: 30 | app: emojify-api 31 | annotations: 32 | "prometheus_io_scrape": "true" 33 | spec: 34 | containers: 35 | - name: emojify-api 36 | image: "nicholasjackson/emojify-api:v0.8.0" 37 | imagePullPolicy: Always 38 | command: ["/service/emojify-api"] 39 | args: [ 40 | "-allow-origin=*", 41 | "-authn-disable=true", 42 | "-bind-address=0.0.0.0:9090", 43 | "-statsd-server=127.0.0.1:9125", 44 | "-cache-address=emojify-cache:80", 45 | "-facebox-address=emojify-facebox:80", 46 | "-path=/", 47 | ] 48 | ports: 49 | - containerPort: 9090 50 | livenessProbe: 51 | httpGet: 52 | path: /health 53 | port: 9090 54 | initialDelaySeconds: 10 55 | periodSeconds: 30 56 | resources: 57 | limits: 58 | cpu: 300m 59 | requests: 60 | cpu: 100m 61 | memory: 100Mi 62 | 63 | - name: prometheus-statsd 64 | image: prom/statsd-exporter:latest 65 | ports: 66 | - name: metrics 67 | containerPort: 9102 68 | resources: 69 | limits: 70 | memory: 100Mi 71 | requests: 72 | cpu: 100m 73 | memory: 100Mi 74 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/sync-catalog-cluster-role-binding.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "sync/ClusterRoleBinding: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/sync-catalog-cluster-role-binding.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "sync/ClusterRoleBinding: disabled with global.enabled=false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/sync-catalog-cluster-role-binding.yaml \ 18 | --set 'global.enabled=false' \ 19 | . | tee /dev/stderr | 20 | yq 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "false" ] 22 | } 23 | 24 | @test "sync/ClusterRoleBinding: disabled with sync disabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/sync-catalog-cluster-role-binding.yaml \ 28 | --set 'syncCatalog.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "sync/ClusterRoleBinding: enabled with sync enabled" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/sync-catalog-cluster-role-binding.yaml \ 38 | --set 'syncCatalog.enabled=true' \ 39 | . | tee /dev/stderr | 40 | yq -s 'length > 0' | tee /dev/stderr) 41 | [ "${actual}" = "true" ] 42 | } 43 | 44 | @test "sync/ClusterRoleBinding: enabled with sync enabled and global.enabled=false" { 45 | cd `chart_dir` 46 | local actual=$(helm template \ 47 | -x templates/sync-catalog-cluster-role-binding.yaml \ 48 | --set 'global.enabled=false' \ 49 | --set 'syncCatalog.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq -s 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/acceptance/_helpers.bash: -------------------------------------------------------------------------------- 1 | # name_prefix returns the prefix of the resources within Kubernetes. 2 | name_prefix() { 3 | printf "consul" 4 | } 5 | 6 | # helm_install installs the Consul chart. This will source overridable 7 | # values from the "values.yaml" file in this directory. This can be set 8 | # by CI or other environments to do test-specific overrides. Note that its 9 | # easily possible to break tests this way so be careful. 10 | helm_install() { 11 | local values="${BATS_TEST_DIRNAME}/values.yaml" 12 | if [ ! -f "${values}" ]; then 13 | touch $values 14 | fi 15 | 16 | helm install -f ${values} \ 17 | --name consul \ 18 | --wait \ 19 | ${BATS_TEST_DIRNAME}/../.. 20 | } 21 | 22 | # helm_delete deletes the Consul chart and all resources. 23 | helm_delete() { 24 | helm delete --purge consul 25 | kubectl delete --all pvc 26 | } 27 | 28 | # wait for a pod to be ready 29 | wait_for_ready() { 30 | POD_NAME=$1 31 | 32 | check() { 33 | # This requests the pod and checks whether the status is running 34 | # and the ready state is true. If so, it outputs the name. Otherwise 35 | # it outputs empty. Therefore, to check for success, check for nonzero 36 | # string length. 37 | kubectl get pods $1 -o json | \ 38 | jq -r 'select( 39 | .status.phase == "Running" and 40 | ([ .status.conditions[] | select(.type == "Ready" and .status == "True") ] | length) == 1 41 | ) | .metadata.namespace + "/" + .metadata.name' 42 | } 43 | 44 | for i in $(seq 30); do 45 | if [ -n "$(check ${POD_NAME})" ]; then 46 | echo "${POD_NAME} is ready." 47 | return 48 | fi 49 | 50 | echo "Waiting for ${POD_NAME} to be ready..." 51 | sleep 2 52 | done 53 | 54 | echo "${POD_NAME} never became ready." 55 | exit 1 56 | } 57 | -------------------------------------------------------------------------------- /exercises/lab-03/01-configure-envoy-statistics/index.md: -------------------------------------------------------------------------------- 1 | # Lab 03, Exercise 01: Configure Envoy and Statistics 2 | 3 | **Objective:** Configure Envoy to manage service-to-service communication and enable stats collection. 4 | 5 | ## Background 6 | 7 | TODO: add diagram 8 | 9 | ## Steps 10 | 11 | First, navigate to this exercise's directory: 12 | 13 | ``` 14 | cd ~/service-mesh-training/exercises/lab-03/01-configure-envoy-statistics/ 15 | ``` 16 | 17 | In `files/app` you'll find an updated set of Kubernetes configurations. If you compare these files with their counterparts from exercise 2, you'll notice a number of changes. 18 | 19 | Briefly, what we're doing is: 20 | 21 | - Replacing use of Kubernetes services to facilitate service-to-service communication and configuring Envoy proxies instead. 22 | - Using Kubernetes configmaps to configure Envoy statistics. 23 | 24 | Once you apply this change, the different components of the Emojify architecture will talk to each other though localhost, with Envoy proxying the requests. 25 | 26 | Apply the updated configs with `kubectl apply`: 27 | 28 | ``` 29 | kubectl apply -f files/app 30 | 31 | configmap/emojify-api-configmap created 32 | deployment.apps/emojify-api configured 33 | configmap/emojify-cache-configmap created 34 | deployment.apps/emojify-cache configured 35 | configmap/emojify-facebox-configmap created 36 | deployment.apps/emojify-facebox configured 37 | configmap/emojify-ingress-configmap configured 38 | deployment.apps/emojify-ingress configured 39 | secret/emojify unchanged 40 | configmap/emojify-website-configmap configured 41 | deployment.apps/emojify-website configured 42 | ``` 43 | 44 | To verify that Envoy has been configured properly and is collecting statistics by going to the **Prometheus** tab and running a query. Try `api_service_health_called_count` and you should see the following: 45 | 46 | ![Prometheus query](../../images/lab03-query-prometheus.png "Prometheus query") 47 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/connect-inject-clusterrole.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | @test "connectInject/ClusterRole: disabled by default" { 5 | cd `chart_dir` 6 | local actual=$(helm template \ 7 | -x templates/connect-inject-clusterrole.yaml \ 8 | . | tee /dev/stderr | 9 | yq 'length > 0' | tee /dev/stderr) 10 | [ "${actual}" = "false" ] 11 | } 12 | 13 | @test "connectInject/ClusterRole: enabled with global.enabled false" { 14 | cd `chart_dir` 15 | local actual=$(helm template \ 16 | -x templates/connect-inject-clusterrole.yaml \ 17 | --set 'global.enabled=false' \ 18 | --set 'connectInject.enabled=true' \ 19 | . | tee /dev/stderr | 20 | yq -s 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "true" ] 22 | } 23 | 24 | @test "connectInject/ClusterRole: disabled with connectInject.enabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/connect-inject-clusterrole.yaml \ 28 | --set 'connectInject.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "connectInject/ClusterRole: disabled with connectInject.certs.secretName set" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/connect-inject-clusterrole.yaml \ 38 | --set 'connectInject.enabled=true' \ 39 | --set 'connectInject.certs.secretName=foo' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/ClusterRole: enabled with connectInject.certs.secretName not set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-clusterrole.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/acceptance/_helpers.bash: -------------------------------------------------------------------------------- 1 | # name_prefix returns the prefix of the resources within Kubernetes. 2 | name_prefix() { 3 | printf "consul" 4 | } 5 | 6 | # helm_install installs the Consul chart. This will source overridable 7 | # values from the "values.yaml" file in this directory. This can be set 8 | # by CI or other environments to do test-specific overrides. Note that its 9 | # easily possible to break tests this way so be careful. 10 | helm_install() { 11 | local values="${BATS_TEST_DIRNAME}/values.yaml" 12 | if [ ! -f "${values}" ]; then 13 | touch $values 14 | fi 15 | 16 | helm install -f ${values} \ 17 | --name consul \ 18 | --wait \ 19 | ${BATS_TEST_DIRNAME}/../.. 20 | } 21 | 22 | # helm_delete deletes the Consul chart and all resources. 23 | helm_delete() { 24 | helm delete --purge consul 25 | kubectl delete --all pvc 26 | } 27 | 28 | # wait for a pod to be ready 29 | wait_for_ready() { 30 | POD_NAME=$1 31 | 32 | check() { 33 | # This requests the pod and checks whether the status is running 34 | # and the ready state is true. If so, it outputs the name. Otherwise 35 | # it outputs empty. Therefore, to check for success, check for nonzero 36 | # string length. 37 | kubectl get pods $1 -o json | \ 38 | jq -r 'select( 39 | .status.phase == "Running" and 40 | ([ .status.conditions[] | select(.type == "Ready" and .status == "True") ] | length) == 1 41 | ) | .metadata.namespace + "/" + .metadata.name' 42 | } 43 | 44 | for i in $(seq 30); do 45 | if [ -n "$(check ${POD_NAME})" ]; then 46 | echo "${POD_NAME} is ready." 47 | return 48 | fi 49 | 50 | echo "Waiting for ${POD_NAME} to be ready..." 51 | sleep 2 52 | done 53 | 54 | echo "${POD_NAME} never became ready." 55 | exit 1 56 | } 57 | -------------------------------------------------------------------------------- /k8s-config/consul/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Create a default fully qualified app name. 3 | We truncate at 63 chars because some Kubernetes name fields are limited to 4 | this (by the DNS naming spec). If release name contains chart name it will 5 | be used as a full name. 6 | */}} 7 | {{- define "consul.fullname" -}} 8 | {{- if .Values.fullnameOverride -}} 9 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 10 | {{- else -}} 11 | {{- $name := default .Chart.Name .Values.nameOverride -}} 12 | {{- if contains $name .Release.Name -}} 13 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 14 | {{- else -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | {{- end -}} 18 | {{- end -}} 19 | 20 | {{/* 21 | Create chart name and version as used by the chart label. 22 | */}} 23 | {{- define "consul.chart" -}} 24 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Expand the name of the chart. 29 | */}} 30 | {{- define "consul.name" -}} 31 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{/* 35 | Compute the maximum number of unavailable replicas for the PodDisruptionBudget. 36 | This defaults to (n/2)-1 where n is the number of members of the server cluster. 37 | Special case of replica equaling 3 and allowing a minor disruption of 1 otherwise 38 | use the integer value 39 | Add a special case for replicas=1, where it should default to 0 as well. 40 | */}} 41 | {{- define "consul.pdb.maxUnavailable" -}} 42 | {{- if eq (int .Values.server.replicas) 1 -}} 43 | {{ 0 }} 44 | {{- else if .Values.server.disruptionBudget.maxUnavailable -}} 45 | {{ .Values.server.disruptionBudget.maxUnavailable -}} 46 | {{- else -}} 47 | {{- if eq (int .Values.server.replicas) 3 -}} 48 | {{- 1 -}} 49 | {{- else -}} 50 | {{- sub (div (int .Values.server.replicas) 2) 1 -}} 51 | {{- end -}} 52 | {{- end -}} 53 | {{- end -}} 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/connect-inject-clusterrole.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | @test "connectInject/ClusterRole: disabled by default" { 5 | cd `chart_dir` 6 | local actual=$(helm template \ 7 | -x templates/connect-inject-clusterrole.yaml \ 8 | . | tee /dev/stderr | 9 | yq 'length > 0' | tee /dev/stderr) 10 | [ "${actual}" = "false" ] 11 | } 12 | 13 | @test "connectInject/ClusterRole: enabled with global.enabled false" { 14 | cd `chart_dir` 15 | local actual=$(helm template \ 16 | -x templates/connect-inject-clusterrole.yaml \ 17 | --set 'global.enabled=false' \ 18 | --set 'connectInject.enabled=true' \ 19 | . | tee /dev/stderr | 20 | yq -s 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "true" ] 22 | } 23 | 24 | @test "connectInject/ClusterRole: disabled with connectInject.enabled" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/connect-inject-clusterrole.yaml \ 28 | --set 'connectInject.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "connectInject/ClusterRole: disabled with connectInject.certs.secretName set" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/connect-inject-clusterrole.yaml \ 38 | --set 'connectInject.enabled=true' \ 39 | --set 'connectInject.certs.secretName=foo' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/ClusterRole: enabled with connectInject.certs.secretName not set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-clusterrole.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-04/02-timeouts/index.md: -------------------------------------------------------------------------------- 1 | # Lab 04, Exercise 02: Timeouts 2 | 3 | **Objective:** Configure timeouts in Envoy and verify affect upon response time and users in Grafana. 4 | 5 | ## Step 1: Deploy a faulty API service 6 | 7 | First, navigate to this exercise's directory: 8 | 9 | ``` 10 | cd ~/service-mesh-training/exercises/lab-04/02-timeouts/ 11 | ``` 12 | 13 | Now apply the updated config files: 14 | 15 | ``` 16 | kubectl apply -f part1/files/app 17 | 18 | deployment.apps/emojify-api-2 configured 19 | configmap/emojify-api-configmap unchanged 20 | deployment.apps/emojify-api configured 21 | configmap/emojify-cache-configmap unchanged 22 | deployment.apps/emojify-cache configured 23 | configmap/emojify-facebox-configmap unchanged 24 | deployment.apps/emojify-facebox configured 25 | service/emojify-ingress unchanged 26 | configmap/emojify-ingress-configmap unchanged 27 | deployment.apps/emojify-ingress configured 28 | secret/emojify unchanged 29 | configmap/emojify-website-configmap unchanged 30 | deployment.apps/emojify-website configured 31 | ``` 32 | 33 | ## Step 2: Use Grafana to verify affect upon response times and users 34 | 35 | ## Step 3: Configure timeouts in Envoy (set to 1s) 36 | 37 | Now apply the updated config files: 38 | 39 | ``` 40 | kubectl apply -f part2/files/app 41 | 42 | deployment.apps/emojify-api-2 configured 43 | configmap/emojify-api-configmap unchanged 44 | deployment.apps/emojify-api configured 45 | configmap/emojify-cache-configmap unchanged 46 | deployment.apps/emojify-cache configured 47 | configmap/emojify-facebox-configmap unchanged 48 | deployment.apps/emojify-facebox configured 49 | service/emojify-ingress unchanged 50 | configmap/emojify-ingress-configmap configured 51 | deployment.apps/emojify-ingress configured 52 | secret/emojify unchanged 53 | configmap/emojify-website-configmap unchanged 54 | deployment.apps/emojify-website configured 55 | ``` 56 | 57 | ## Step 4: Use Grafana to verify affect timeouts are having on response times and users 58 | -------------------------------------------------------------------------------- /exercises/lab-01/03-install-emojify-app/files/app/website.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: emojify-website-configmap 6 | data: 7 | config: | 8 | window.env = {}; 9 | window.env.config = { 10 | AUTH_URL: '/auth', 11 | API_URL: '/api/', 12 | HOME_URL: '/', 13 | PAYMENT_URL: '/api/payments', 14 | PAYMENT_ENABLED: false, 15 | OAUTH_ENABLED: false, 16 | AUTH_DISABLED: true 17 | }; 18 | 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | name: emojify-website 24 | spec: 25 | selector: 26 | app: emojify-website 27 | ports: 28 | - protocol: TCP 29 | port: 80 30 | targetPort: 80 31 | 32 | --- 33 | apiVersion: apps/v1 34 | kind: Deployment 35 | metadata: 36 | name: emojify-website 37 | labels: 38 | app: emojify-website 39 | 40 | spec: 41 | replicas: 1 42 | selector: 43 | matchLabels: 44 | app: emojify-website 45 | template: 46 | metadata: 47 | labels: 48 | app: emojify-website 49 | annotations: 50 | "prometheus_io_scrape": "true" 51 | spec: 52 | volumes: 53 | - name: config 54 | configMap: 55 | name: emojify-website-configmap 56 | items: 57 | - key: config 58 | path: env.js 59 | containers: 60 | - name: emojify-website 61 | image: "nicholasjackson/emojify-website:v0.6.2" 62 | imagePullPolicy: Always 63 | ports: 64 | - containerPort: 80 65 | volumeMounts: 66 | - name: config 67 | mountPath: /usr/share/nginx/html/config 68 | readOnly: true 69 | 70 | - name: prometheus-statsd 71 | image: prom/statsd-exporter:latest 72 | ports: 73 | - name: metrics 74 | containerPort: 9102 75 | resources: 76 | limits: 77 | memory: 100Mi 78 | requests: 79 | cpu: 100m 80 | memory: 100Mi 81 | 82 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/connect-inject-serviceaccount.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | @test "connectInject/ServiceAccount: disabled by default" { 5 | cd `chart_dir` 6 | local actual=$(helm template \ 7 | -x templates/connect-inject-serviceaccount.yaml \ 8 | . | tee /dev/stderr | 9 | yq 'length > 0' | tee /dev/stderr) 10 | [ "${actual}" = "false" ] 11 | } 12 | 13 | @test "connectInject/ServiceAccount: enabled with global.enabled false" { 14 | cd `chart_dir` 15 | local actual=$(helm template \ 16 | -x templates/connect-inject-serviceaccount.yaml \ 17 | --set 'global.enabled=false' \ 18 | --set 'connectInject.enabled=true' \ 19 | . | tee /dev/stderr | 20 | yq -s 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "true" ] 22 | } 23 | 24 | @test "connectInject/ServiceAccount: disabled with connectInject.enabled false" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/connect-inject-serviceaccount.yaml \ 28 | --set 'connectInject.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "connectInject/ServiceAccount: disabled with connectInject.certs.secretName set" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/connect-inject-serviceaccount.yaml \ 38 | --set 'connectInject.enabled=true' \ 39 | --set 'connectInject.certs.secretName=foo' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/ServiceAccount: enabled with connectInject.certs.secretName not set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-serviceaccount.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Create a default fully qualified app name. 3 | We truncate at 63 chars because some Kubernetes name fields are limited to 4 | this (by the DNS naming spec). If release name contains chart name it will 5 | be used as a full name. 6 | */}} 7 | {{- define "consul.fullname" -}} 8 | {{- if .Values.fullnameOverride -}} 9 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 10 | {{- else -}} 11 | {{- $name := default .Chart.Name .Values.nameOverride -}} 12 | {{- if contains $name .Release.Name -}} 13 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 14 | {{- else -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | {{- end -}} 18 | {{- end -}} 19 | 20 | {{/* 21 | Create chart name and version as used by the chart label. 22 | */}} 23 | {{- define "consul.chart" -}} 24 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Expand the name of the chart. 29 | */}} 30 | {{- define "consul.name" -}} 31 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{/* 35 | Compute the maximum number of unavailable replicas for the PodDisruptionBudget. 36 | This defaults to (n/2)-1 where n is the number of members of the server cluster. 37 | Special case of replica equaling 3 and allowing a minor disruption of 1 otherwise 38 | use the integer value 39 | Add a special case for replicas=1, where it should default to 0 as well. 40 | */}} 41 | {{- define "consul.pdb.maxUnavailable" -}} 42 | {{- if eq (int .Values.server.replicas) 1 -}} 43 | {{ 0 }} 44 | {{- else if .Values.server.disruptionBudget.maxUnavailable -}} 45 | {{ .Values.server.disruptionBudget.maxUnavailable -}} 46 | {{- else -}} 47 | {{- if eq (int .Values.server.replicas) 3 -}} 48 | {{- 1 -}} 49 | {{- else -}} 50 | {{- sub (div (int .Values.server.replicas) 2) 1 -}} 51 | {{- end -}} 52 | {{- end -}} 53 | {{- end -}} 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/connect-inject-mutatingwebhook.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "connectInject/MutatingWebhookConfiguration: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/connect-inject-mutatingwebhook.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "connectInject/MutatingWebhookConfiguration: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/connect-inject-mutatingwebhook.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'connectInject.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "connectInject/MutatingWebhookConfiguration: disable with connectInject.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/connect-inject-mutatingwebhook.yaml \ 29 | --set 'connectInject.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "connectInject/MutatingWebhookConfiguration: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/connect-inject-mutatingwebhook.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/MutatingWebhookConfiguration: namespace is set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-mutatingwebhook.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | --namespace foo \ 51 | . | tee /dev/stderr | 52 | yq '.webhooks[0].clientConfig.service.namespace' | tee /dev/stderr) 53 | [ "${actual}" = "\"foo\"" ] 54 | } 55 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/connect-inject-serviceaccount.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | @test "connectInject/ServiceAccount: disabled by default" { 5 | cd `chart_dir` 6 | local actual=$(helm template \ 7 | -x templates/connect-inject-serviceaccount.yaml \ 8 | . | tee /dev/stderr | 9 | yq 'length > 0' | tee /dev/stderr) 10 | [ "${actual}" = "false" ] 11 | } 12 | 13 | @test "connectInject/ServiceAccount: enabled with global.enabled false" { 14 | cd `chart_dir` 15 | local actual=$(helm template \ 16 | -x templates/connect-inject-serviceaccount.yaml \ 17 | --set 'global.enabled=false' \ 18 | --set 'connectInject.enabled=true' \ 19 | . | tee /dev/stderr | 20 | yq -s 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "true" ] 22 | } 23 | 24 | @test "connectInject/ServiceAccount: disabled with connectInject.enabled false" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/connect-inject-serviceaccount.yaml \ 28 | --set 'connectInject.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "connectInject/ServiceAccount: disabled with connectInject.certs.secretName set" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/connect-inject-serviceaccount.yaml \ 38 | --set 'connectInject.enabled=true' \ 39 | --set 'connectInject.certs.secretName=foo' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/ServiceAccount: enabled with connectInject.certs.secretName not set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-serviceaccount.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/connect-inject-clusterrolebinding.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | @test "connectInject/ClusterRoleBinding: disabled by default" { 5 | cd `chart_dir` 6 | local actual=$(helm template \ 7 | -x templates/connect-inject-clusterrolebinding.yaml \ 8 | . | tee /dev/stderr | 9 | yq 'length > 0' | tee /dev/stderr) 10 | [ "${actual}" = "false" ] 11 | } 12 | 13 | @test "connectInject/ClusterRoleBinding: enabled with global.enabled false" { 14 | cd `chart_dir` 15 | local actual=$(helm template \ 16 | -x templates/connect-inject-clusterrolebinding.yaml \ 17 | --set 'global.enabled=false' \ 18 | --set 'connectInject.enabled=true' \ 19 | . | tee /dev/stderr | 20 | yq -s 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "true" ] 22 | } 23 | 24 | @test "connectInject/ClusterRoleBinding: disabled with connectInject.enabled false" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/connect-inject-clusterrolebinding.yaml \ 28 | --set 'connectInject.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "connectInject/ClusterRoleBinding: disabled with connectInject.certs.secretName set" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/connect-inject-clusterrolebinding.yaml \ 38 | --set 'connectInject.enabled=true' \ 39 | --set 'connectInject.certs.secretName=foo' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/ClusterRoleBinding: enabled with connectInject.certs.secretName not set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-clusterrolebinding.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/connect-inject-mutatingwebhook.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "connectInject/MutatingWebhookConfiguration: disabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/connect-inject-mutatingwebhook.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "false" ] 12 | } 13 | 14 | @test "connectInject/MutatingWebhookConfiguration: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/connect-inject-mutatingwebhook.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'connectInject.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "connectInject/MutatingWebhookConfiguration: disable with connectInject.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/connect-inject-mutatingwebhook.yaml \ 29 | --set 'connectInject.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "connectInject/MutatingWebhookConfiguration: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/connect-inject-mutatingwebhook.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/MutatingWebhookConfiguration: namespace is set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-mutatingwebhook.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | --namespace foo \ 51 | . | tee /dev/stderr | 52 | yq '.webhooks[0].clientConfig.service.namespace' | tee /dev/stderr) 53 | [ "${actual}" = "\"foo\"" ] 54 | } 55 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/connect-inject-clusterrolebinding.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | @test "connectInject/ClusterRoleBinding: disabled by default" { 5 | cd `chart_dir` 6 | local actual=$(helm template \ 7 | -x templates/connect-inject-clusterrolebinding.yaml \ 8 | . | tee /dev/stderr | 9 | yq 'length > 0' | tee /dev/stderr) 10 | [ "${actual}" = "false" ] 11 | } 12 | 13 | @test "connectInject/ClusterRoleBinding: enabled with global.enabled false" { 14 | cd `chart_dir` 15 | local actual=$(helm template \ 16 | -x templates/connect-inject-clusterrolebinding.yaml \ 17 | --set 'global.enabled=false' \ 18 | --set 'connectInject.enabled=true' \ 19 | . | tee /dev/stderr | 20 | yq -s 'length > 0' | tee /dev/stderr) 21 | [ "${actual}" = "true" ] 22 | } 23 | 24 | @test "connectInject/ClusterRoleBinding: disabled with connectInject.enabled false" { 25 | cd `chart_dir` 26 | local actual=$(helm template \ 27 | -x templates/connect-inject-clusterrolebinding.yaml \ 28 | --set 'connectInject.enabled=false' \ 29 | . | tee /dev/stderr | 30 | yq 'length > 0' | tee /dev/stderr) 31 | [ "${actual}" = "false" ] 32 | } 33 | 34 | @test "connectInject/ClusterRoleBinding: disabled with connectInject.certs.secretName set" { 35 | cd `chart_dir` 36 | local actual=$(helm template \ 37 | -x templates/connect-inject-clusterrolebinding.yaml \ 38 | --set 'connectInject.enabled=true' \ 39 | --set 'connectInject.certs.secretName=foo' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | @test "connectInject/ClusterRoleBinding: enabled with connectInject.certs.secretName not set" { 46 | cd `chart_dir` 47 | local actual=$(helm template \ 48 | -x templates/connect-inject-clusterrolebinding.yaml \ 49 | --set 'connectInject.enabled=true' \ 50 | . | tee /dev/stderr | 51 | yq 'length > 0' | tee /dev/stderr) 52 | [ "${actual}" = "true" ] 53 | } 54 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/server-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "server/Service: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/server-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "server/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/server-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'server.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "server/Service: disable with server.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/server-service.yaml \ 29 | --set 'server.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "server/Service: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/server-service.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | # This can be seen as testing just what we put into the YAML raw, but 46 | # this is such an important part of making everything work we verify it here. 47 | @test "server/Service: tolerates unready endpoints" { 48 | cd `chart_dir` 49 | local actual=$(helm template \ 50 | -x templates/server-service.yaml \ 51 | . | tee /dev/stderr | 52 | yq -r '.metadata.annotations["service.alpha.kubernetes.io/tolerate-unready-endpoints"]' | tee /dev/stderr) 53 | [ "${actual}" = "true" ] 54 | 55 | local actual=$(helm template \ 56 | -x templates/server-service.yaml \ 57 | . | tee /dev/stderr | 58 | yq -r '.spec.publishNotReadyAddresses' | tee /dev/stderr) 59 | [ "${actual}" = "true" ] 60 | } 61 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/server-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "server/Service: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/server-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "server/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/server-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'server.enabled=true' \ 20 | . | tee /dev/stderr | 21 | yq 'length > 0' | tee /dev/stderr) 22 | [ "${actual}" = "true" ] 23 | } 24 | 25 | @test "server/Service: disable with server.enabled" { 26 | cd `chart_dir` 27 | local actual=$(helm template \ 28 | -x templates/server-service.yaml \ 29 | --set 'server.enabled=false' \ 30 | . | tee /dev/stderr | 31 | yq 'length > 0' | tee /dev/stderr) 32 | [ "${actual}" = "false" ] 33 | } 34 | 35 | @test "server/Service: disable with global.enabled" { 36 | cd `chart_dir` 37 | local actual=$(helm template \ 38 | -x templates/server-service.yaml \ 39 | --set 'global.enabled=false' \ 40 | . | tee /dev/stderr | 41 | yq 'length > 0' | tee /dev/stderr) 42 | [ "${actual}" = "false" ] 43 | } 44 | 45 | # This can be seen as testing just what we put into the YAML raw, but 46 | # this is such an important part of making everything work we verify it here. 47 | @test "server/Service: tolerates unready endpoints" { 48 | cd `chart_dir` 49 | local actual=$(helm template \ 50 | -x templates/server-service.yaml \ 51 | . | tee /dev/stderr | 52 | yq -r '.metadata.annotations["service.alpha.kubernetes.io/tolerate-unready-endpoints"]' | tee /dev/stderr) 53 | [ "${actual}" = "true" ] 54 | 55 | local actual=$(helm template \ 56 | -x templates/server-service.yaml \ 57 | . | tee /dev/stderr | 58 | yq -r '.spec.publishNotReadyAddresses' | tee /dev/stderr) 59 | [ "${actual}" = "true" ] 60 | } 61 | -------------------------------------------------------------------------------- /exercises/lab-02/01-enable-connect-inject/files/app/ingress.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: emojify-ingress 6 | spec: 7 | type: NodePort 8 | selector: 9 | app: emojify-ingress 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 80 14 | targetPort: 80 15 | nodePort: 30000 16 | 17 | --- 18 | apiVersion: v1 19 | kind: ConfigMap 20 | metadata: 21 | name: emojify-ingress-configmap 22 | data: 23 | config: | 24 | events { 25 | worker_connections 1024; 26 | } 27 | 28 | http { 29 | upstream emojify-website { 30 | keepalive 100; 31 | server localhost:8000; 32 | } 33 | upstream emojify-api { 34 | keepalive 100; 35 | server localhost:8001; 36 | } 37 | 38 | server { 39 | location / { 40 | proxy_http_version 1.1; 41 | proxy_pass http://emojify-website; 42 | proxy_set_header Host $host; 43 | } 44 | 45 | location ~ ^/api(/.*)?$ { 46 | proxy_http_version 1.1; 47 | proxy_pass http://emojify-api$1$is_args$args; 48 | proxy_pass_request_headers on; 49 | } 50 | } 51 | } 52 | 53 | --- 54 | apiVersion: apps/v1 55 | kind: Deployment 56 | metadata: 57 | name: emojify-ingress 58 | labels: 59 | app: emojify-ingress 60 | spec: 61 | replicas: 1 62 | selector: 63 | matchLabels: 64 | app: emojify-ingress 65 | template: 66 | metadata: 67 | name: emojify-ingress 68 | labels: 69 | app: emojify-ingress 70 | annotations: 71 | "consul.hashicorp.com/connect-inject": "true" 72 | "consul.hashicorp.com/connect-service-upstreams": "emojify-website:8000,emojify-api:8001" 73 | spec: 74 | volumes: 75 | - name: config 76 | configMap: 77 | name: emojify-ingress-configmap 78 | items: 79 | - key: config 80 | path: nginx.conf 81 | containers: 82 | - name: emojify-ingress 83 | image: nginx:latest 84 | imagePullPolicy: IfNotPresent 85 | ports: 86 | - containerPort: 80 87 | volumeMounts: 88 | - name: config 89 | mountPath: /etc/nginx/ 90 | -------------------------------------------------------------------------------- /k8s-config/consul/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## UNRELEASED 2 | 3 | ## 0.5.0 (January 11, 2019) 4 | 5 | IMPROVEMENTS: 6 | 7 | * Supports new NodePort syncing style that uses the node ip address 8 | * Adds a configurable tab to the Kubernetes -> Consul sync 9 | 10 | ## 0.4.0 (December 7, 2018) 11 | 12 | IMPROVEMENTS: 13 | 14 | * RBAC support for `syncCatalog`. This will create the `ClusterRole`, `ClusterRoleBinding` 15 | and `ServiceAccount` that is necessary for the catalog sync. [GH-29] 16 | * client: agents now have the node name set to the actual K8S node name [GH-14] 17 | * RBAC support for `connectInject`. This will create a `ClusterRole`, `ClusterRoleBinding`, 18 | and `ServiceAccount` that is necessary for the connect injector to automatically generate 19 | TLS certificates to interact with the Kubernetes API. 20 | * Server affinity is now configurable. This makes it easier to run an entire 21 | Consul cluster on Minikube. [GH-13] 22 | * Liveness probes are now http calls, reducing errors in the logs. 23 | * All namespaced resources now specify the namespace metadata, making `helm template` usage in 24 | a non-default namespace easier. [GH-66] 25 | * Add support for ClusterIP service syncing. 26 | 27 | BUG FIXES: 28 | 29 | * Add catalog sync default behavior flag to the chart [GH-28] 30 | * Updated images to point to latest versions for 0.3.0. 31 | * Add missing continuation characters to long commands [GH-26]. 32 | * connectInject: set the correct namespace for the MutatingWebhookConfiguration 33 | so that deployments work in non-default namespaces. [GH-41] 34 | * Provide a valid `maxUnavailable` value when replicas=1. [GH-58] 35 | * Correctly sets server resource requirements. 36 | * Update the `maxUnavailable` default calculation to allow rolling updates on 3 server clusters. [GH-71] 37 | 38 | ## 0.3.0 (October 11, 2018) 39 | 40 | FEATURES: 41 | 42 | * `connectInject` can install the automatic Connect sidecar injector. 43 | 44 | ## 0.2.0 (September 26, 2018) 45 | 46 | FEATURES: 47 | 48 | * `syncCatalog` can install the [service catalog sync](https://www.hashicorp.com/blog/consul-and-kubernetes-service-catalog-sync) 49 | functionality. 50 | 51 | IMPROVEMENTS: 52 | 53 | * server: support `storageClass` [GH-7] 54 | 55 | ## 0.1.0 56 | 57 | Initial release 58 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## UNRELEASED 2 | 3 | ## 0.5.0 (January 11, 2019) 4 | 5 | IMPROVEMENTS: 6 | 7 | * Supports new NodePort syncing style that uses the node ip address 8 | * Adds a configurable tab to the Kubernetes -> Consul sync 9 | 10 | ## 0.4.0 (December 7, 2018) 11 | 12 | IMPROVEMENTS: 13 | 14 | * RBAC support for `syncCatalog`. This will create the `ClusterRole`, `ClusterRoleBinding` 15 | and `ServiceAccount` that is necessary for the catalog sync. [GH-29] 16 | * client: agents now have the node name set to the actual K8S node name [GH-14] 17 | * RBAC support for `connectInject`. This will create a `ClusterRole`, `ClusterRoleBinding`, 18 | and `ServiceAccount` that is necessary for the connect injector to automatically generate 19 | TLS certificates to interact with the Kubernetes API. 20 | * Server affinity is now configurable. This makes it easier to run an entire 21 | Consul cluster on Minikube. [GH-13] 22 | * Liveness probes are now http calls, reducing errors in the logs. 23 | * All namespaced resources now specify the namespace metadata, making `helm template` usage in 24 | a non-default namespace easier. [GH-66] 25 | * Add support for ClusterIP service syncing. 26 | 27 | BUG FIXES: 28 | 29 | * Add catalog sync default behavior flag to the chart [GH-28] 30 | * Updated images to point to latest versions for 0.3.0. 31 | * Add missing continuation characters to long commands [GH-26]. 32 | * connectInject: set the correct namespace for the MutatingWebhookConfiguration 33 | so that deployments work in non-default namespaces. [GH-41] 34 | * Provide a valid `maxUnavailable` value when replicas=1. [GH-58] 35 | * Correctly sets server resource requirements. 36 | * Update the `maxUnavailable` default calculation to allow rolling updates on 3 server clusters. [GH-71] 37 | 38 | ## 0.3.0 (October 11, 2018) 39 | 40 | FEATURES: 41 | 42 | * `connectInject` can install the automatic Connect sidecar injector. 43 | 44 | ## 0.2.0 (September 26, 2018) 45 | 46 | FEATURES: 47 | 48 | * `syncCatalog` can install the [service catalog sync](https://www.hashicorp.com/blog/consul-and-kubernetes-service-catalog-sync) 49 | functionality. 50 | 51 | IMPROVEMENTS: 52 | 53 | * server: support `storageClass` [GH-7] 54 | 55 | ## 0.1.0 56 | 57 | Initial release 58 | -------------------------------------------------------------------------------- /k8s-config/consul/test/terraform/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | service_account_path = "${path.module}/service-account.yaml" 3 | } 4 | 5 | provider "google" { 6 | project = "${var.project}" 7 | } 8 | 9 | resource "random_id" "suffix" { 10 | byte_length = 4 11 | } 12 | 13 | data "google_container_engine_versions" "main" { 14 | zone = "${var.zone}" 15 | } 16 | 17 | resource "google_container_cluster" "cluster" { 18 | name = "consul-k8s-${random_id.suffix.dec}" 19 | project = "${var.project}" 20 | enable_legacy_abac = true 21 | initial_node_count = 5 22 | zone = "${var.zone}" 23 | min_master_version = "${data.google_container_engine_versions.main.latest_master_version}" 24 | node_version = "${data.google_container_engine_versions.main.latest_node_version}" 25 | } 26 | 27 | resource "null_resource" "kubectl" { 28 | count = "${var.init_cli ? 1 : 0 }" 29 | 30 | triggers { 31 | cluster = "${google_container_cluster.cluster.id}" 32 | } 33 | 34 | # On creation, we want to setup the kubectl credentials. The easiest way 35 | # to do this is to shell out to gcloud. 36 | provisioner "local-exec" { 37 | command = "gcloud container clusters get-credentials --zone=${var.zone} ${google_container_cluster.cluster.name}" 38 | } 39 | 40 | # On destroy we want to try to clean up the kubectl credentials. This 41 | # might fail if the credentials are already cleaned up or something so we 42 | # want this to continue on failure. Generally, this works just fine since 43 | # it only operates on local data. 44 | provisioner "local-exec" { 45 | when = "destroy" 46 | on_failure = "continue" 47 | command = "kubectl config get-clusters | grep ${google_container_cluster.cluster.name} | xargs -n1 kubectl config delete-cluster" 48 | } 49 | 50 | provisioner "local-exec" { 51 | when = "destroy" 52 | on_failure = "continue" 53 | command = "kubectl config get-contexts | grep ${google_container_cluster.cluster.name} | xargs -n1 kubectl config delete-context" 54 | } 55 | } 56 | 57 | resource "null_resource" "helm" { 58 | count = "${var.init_cli ? 1 : 0 }" 59 | depends_on = ["null_resource.kubectl"] 60 | 61 | triggers { 62 | cluster = "${google_container_cluster.cluster.id}" 63 | } 64 | 65 | provisioner "local-exec" { 66 | command = < md2gslides@0.4.0 compile /home/jacksonnic/developer/go/src/github.com/gsuitedevs/md2googleslides 28 | > babel --source-maps both -d lib/ src/ 29 | 30 | src/api_client.js -> lib/api_client.js 31 | src/auth.js -> lib/auth.js 32 | src/extract_slides.js -> lib/extract_slides.js 33 | src/generic_layout.js -> lib/generic_layout.js 34 | src/match_layout.js -> lib/match_layout.js 35 | src/presentation.js -> lib/presentation.js 36 | src/slide_generator.js -> lib/slide_generator.js 37 | Done in 4.98s. 38 | ``` 39 | 40 | If you are not using Yarn then the same installation should be possible with npm: 41 | 42 | ``` 43 | $ sudo npm install -g https://github.com/nicholasjackson/md2googleslides/releases/download/v0.4.0/md2gslides-0.4.0.tar.gz 44 | /usr/bin/md2gslides -> /usr/lib/node_modules/md2gslides/bin/md2gslides.js 45 | + md2gslides@0.4.0 46 | updated 1 package in 4.009s 47 | ``` 48 | 49 | Slides can then be built with the following command: 50 | 51 | ``` 52 | $ md2gslides -c 1DMiG8T0W2uQoBe1X9cWMA98eA-4HXb5B-G2si52nbu4 -t "QCon - Security" ./slides/security/security.md 53 | Opening your presentation (https://docs.google.com/presentation/d/1BCr6TnVJeXRBGwavT9mR4AzBR-oyLPeJknihFOS6zQY) 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /exercises/lab-02/02-configure-intentions/index.md: -------------------------------------------------------------------------------- 1 | # Lab 02, Exercise 02: Configure Intentions 2 | 3 | **Objective:** Enable secure service to service communication by configuration Consul intentions. 4 | 5 | ## Background 6 | 7 | Intentions define access control for services via Connect and are used 8 | to control which services may establish connections. Intentions can be 9 | managed via the API, CLI, or UI. 10 | 11 | Intentions are enforced by the [proxy](/docs/connect/proxies.html) 12 | or [natively integrated application](/docs/connect/native.html) on 13 | inbound connections. After verifying the TLS client certificate, the 14 | [authorize API endpoint](#) is called which verifies the connection 15 | is allowed by testing the intentions. If authorize returns false the 16 | connection must be terminated. 17 | 18 | The default intention behavior is defined by the default 19 | [ACL policy](/docs/guides/acl.html). If the default ACL policy is "allow all", 20 | then all Connect connections are allowed by default. If the default ACL policy 21 | is "deny all", then all Connect connections are denied by default. 22 | 23 | ## Step 1: Add deny all rule 24 | 25 | Intentions are configured via the Consul API, command line client, or Consul UI. We'll use the UI for this exercise. 26 | 27 | Open the **Consul** tab in Instruqt. Click **Intentions** and then **Create**. 28 | 29 | For deny all rule you'll set the following values: 30 | 31 | - **Source Service:** * (All Services) 32 | - **Destination Service:** * (All Services) 33 | - **Allow/Deny:** Deny 34 | - **Description:** Deny by default. 35 | 36 | ![Create deny all intention](../../images/lab03-intentions-deny.png "Create deny all intention") 37 | 38 | Click **Save**. You should now see the intention listed: 39 | 40 | ![Intentions list](../../images/lab03-intentions-list-01.png "Intentions list") 41 | 42 | Now try to use Emojify and see what happens! What do you notice? 43 | 44 | ## Step 2: Add individual intentions 45 | 46 | Now you'll need to create intentions for each of the service to service communication routes that were previously defined via Annotations. 47 | 48 | Follow the same procedure as before to create four (4) allow intentions with the following values: 49 | 50 | | Source | Destination | Allow/Deny | 51 | | ------ | ----------- | ---------- | 52 | | emojify-api | emojify-cache | Allow | 53 | | emojify-api | emojify-facebox | Allow | 54 | | emojify-ingress | emojify-api | Allow | 55 | | emojify-ingress | emojify-website | Allow | 56 | 57 | When done, your list of intentions should look like this: 58 | 59 | ![Intentions list](../../images/lab03-intentions-list-02.png "Intentions list") 60 | 61 | Now if you try using the Emojify app again, everything should be working once again. 62 | -------------------------------------------------------------------------------- /k8s-config/load-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: emojify-loadtest-configmap 6 | data: 7 | EmojifySimulation.scala: | 8 | 9 | import scala.concurrent.duration._ 10 | 11 | import io.gatling.core.Predef._ 12 | import io.gatling.http.Predef._ 13 | import io.gatling.jdbc.Predef._ 14 | 15 | class EmojifySimulation extends Simulation { 16 | 17 | val httpProtocol = http 18 | .baseUrl("http://emojify-ingress:80") 19 | .inferHtmlResources() 20 | .acceptEncodingHeader("gzip, deflate") 21 | .userAgentHeader("Mozilla/5.0 (X11; CrOS x86_64 11316.98.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.74 Safari/537.36") 22 | 23 | val headers_0 = Map( 24 | "Pragma" -> "no-cache", 25 | "Proxy-Connection" -> "keep-alive") 26 | 27 | 28 | 29 | val scn = scenario("RecordedSimulation") 30 | // Get the home page 31 | .exec(http("request_home_page") 32 | .get("/") 33 | .headers(headers_0) 34 | .check(status is 200) 35 | ) 36 | .pause(5 seconds) 37 | // Post an image 38 | .exec(http("request_post_image") 39 | .post("/api/") 40 | .body(StringBody("http://emojify-ingress/pictures/1.jpg")) 41 | .headers(headers_0) 42 | .check(bodyString.saveAs("image_id")) 43 | .check(status is 200) 44 | ) 45 | .pause(5 seconds) 46 | // Get the returned image 47 | .exec(http("request_get_image") 48 | .get("/api/cache/${image_id}") 49 | .headers(headers_0) 50 | .check(status is 200) 51 | ) 52 | 53 | setUp(scn.inject(constantUsersPerSec(3) during (60 minutes) randomized)).protocols(httpProtocol) 54 | } 55 | 56 | --- 57 | apiVersion: apps/v1 58 | kind: Deployment 59 | metadata: 60 | name: emojify-loadtest 61 | labels: 62 | app: emojify-loadtest 63 | spec: 64 | replicas: 1 65 | selector: 66 | matchLabels: 67 | app: emojify-loadtest 68 | template: 69 | metadata: 70 | labels: 71 | app: emojify-loadtest 72 | spec: 73 | volumes: 74 | - name: config 75 | configMap: 76 | name: emojify-loadtest-configmap 77 | containers: 78 | - name: emojify-loadtest 79 | image: "denvazh/gatling" 80 | args: ["-s", "EmojifySimulation"] 81 | volumeMounts: 82 | - name: config 83 | mountPath: /opt/gatling/user-files/simulations/EmojifySimulation.scala 84 | subPath: EmojifySimulation.scala 85 | readOnly: true 86 | resources: 87 | limits: 88 | cpu: 300m 89 | requests: 90 | cpu: 100m 91 | memory: 100Mi 92 | -------------------------------------------------------------------------------- /exercises/lab-01/03-install-emojify-app/index.md: -------------------------------------------------------------------------------- 1 | # [Lab 01](../index.md), Exercise 03: Install emojify app 2 | 3 | **Objective:** Install sample emojify app into Kubernetes cluster. 4 | 5 | * [Step 1: Inspect emojify app configs](#step-1-inspect-emojify-app-configs) 6 | * [Step 2: Apply emojify app configs](#step-2-apply-emojify-app-configs) 7 | * [Step 3: Verify emojify app is running](#step-3-verify-emojify-app-is-running) 8 | * [Step 4 (optional): Emojify an image of your choice](#step-4-optional-emojify-an-image-of-your-choice) 9 | 10 | ## Step 1: Inspect emojify app configs 11 | 12 | First, navigate to this exercise's directory: 13 | 14 | ``` 15 | cd ~/service-mesh-training/exercises/lab-01/03-install-emojify-app/ 16 | ``` 17 | 18 | Now take a look at the files in `files/apps`: 19 | 20 | * **api-external-cache.yml**: Emojify API service. 21 | * **cache.yml**: Emojify cache service. 22 | * **facebox.yml**: Face detection service. 23 | * **ingress.yml**: Application gateway ingress. 24 | * **website.yml**: React website serving user interface. 25 | 26 | TODO: Add brief explanation for each item above. 27 | TODO: Add architecture diagram. 28 | 29 | ## Step 2: Apply emojify app configs 30 | 31 | ``` 32 | kubectl apply -f files/app/ 33 | 34 | service/emojify-api-service created 35 | deployment.apps/emojify-api-external-cache created 36 | service/emojify-cache-service created 37 | deployment.apps/emojify-cache created 38 | service/emojify-facebox-service created 39 | deployment.apps/emojify-facebox created 40 | service/emojify-ingress-service created 41 | configmap/emojify-ingress-configmap created 42 | deployment.apps/emojify-ingress created 43 | secret/emojify created 44 | configmap/emojify-website-configmap created 45 | service/emojify-website-service created 46 | deployment.apps/emojify-website created 47 | ``` 48 | 49 | ## Step 3: Verify emojify app is running 50 | 51 | With `kubectl`: 52 | 53 | ``` 54 | kubectl get pods 55 | 56 | NAME READY STATUS RESTARTS AGE 57 | emojify-api-external-cache-788c9964-vs688 3/3 Running 0 65s 58 | emojify-cache-879fdccb7-4464c 3/3 Running 1 65s 59 | emojify-facebox-7b4fdc8b5b-j4b46 3/3 Running 0 65s 60 | emojify-ingress-7b697c574b-zhj76 3/3 Running 0 65s 61 | emojify-website-5dd8ff4b55-jfn8z 3/3 Running 0 65s 62 | jaunty-cheetah-consul-klfdj 1/1 Running 0 6m44s 63 | jaunty-cheetah-consul-server-0 1/1 Running 0 6m44s 64 | ``` 65 | 66 | Check emojify app tab: 67 | 68 | ![Emojify app](/service-mesh-training/exercises/images/lab01-emojify-app.png "Emojify app") 69 | 70 | ## Step 4 (optional): Emojify an image of your choice 71 | 72 | Use the application to generate an emojified image. 73 | -------------------------------------------------------------------------------- /k8s-config/consul/test/unit/ui-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "ui/Service: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/ui-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "ui/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/ui-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'server.enabled=true' \ 20 | --set 'ui.enabled=true' \ 21 | . | tee /dev/stderr | 22 | yq 'length > 0' | tee /dev/stderr) 23 | [ "${actual}" = "true" ] 24 | } 25 | 26 | @test "ui/Service: disable with server.enabled" { 27 | cd `chart_dir` 28 | local actual=$(helm template \ 29 | -x templates/ui-service.yaml \ 30 | --set 'server.enabled=false' \ 31 | . | tee /dev/stderr | 32 | yq 'length > 0' | tee /dev/stderr) 33 | [ "${actual}" = "false" ] 34 | } 35 | 36 | @test "ui/Service: disable with ui.enabled" { 37 | cd `chart_dir` 38 | local actual=$(helm template \ 39 | -x templates/ui-service.yaml \ 40 | --set 'ui.enabled=false' \ 41 | . | tee /dev/stderr | 42 | yq 'length > 0' | tee /dev/stderr) 43 | [ "${actual}" = "false" ] 44 | } 45 | 46 | @test "ui/Service: disable with ui.service.enabled" { 47 | cd `chart_dir` 48 | local actual=$(helm template \ 49 | -x templates/ui-service.yaml \ 50 | --set 'ui.service.enabled=false' \ 51 | . | tee /dev/stderr | 52 | yq 'length > 0' | tee /dev/stderr) 53 | [ "${actual}" = "false" ] 54 | } 55 | 56 | @test "ui/Service: disable with global.enabled" { 57 | cd `chart_dir` 58 | local actual=$(helm template \ 59 | -x templates/ui-service.yaml \ 60 | --set 'global.enabled=false' \ 61 | . | tee /dev/stderr | 62 | yq 'length > 0' | tee /dev/stderr) 63 | [ "${actual}" = "false" ] 64 | } 65 | 66 | @test "ui/Service: disable with global.enabled and server.enabled on" { 67 | cd `chart_dir` 68 | local actual=$(helm template \ 69 | -x templates/ui-service.yaml \ 70 | --set 'global.enabled=false' \ 71 | --set 'server.enabled=true' \ 72 | . | tee /dev/stderr | 73 | yq 'length > 0' | tee /dev/stderr) 74 | [ "${actual}" = "false" ] 75 | } 76 | 77 | @test "ui/Service: no type by default" { 78 | cd `chart_dir` 79 | local actual=$(helm template \ 80 | -x templates/ui-service.yaml \ 81 | . | tee /dev/stderr | 82 | yq -r '.spec.type' | tee /dev/stderr) 83 | [ "${actual}" = "null" ] 84 | } 85 | 86 | @test "ui/Service: specified type" { 87 | cd `chart_dir` 88 | local actual=$(helm template \ 89 | -x templates/ui-service.yaml \ 90 | --set 'ui.service.type=LoadBalancer' \ 91 | . | tee /dev/stderr | 92 | yq -r '.spec.type' | tee /dev/stderr) 93 | [ "${actual}" = "LoadBalancer" ] 94 | } 95 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/test/unit/ui-service.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load _helpers 4 | 5 | @test "ui/Service: enabled by default" { 6 | cd `chart_dir` 7 | local actual=$(helm template \ 8 | -x templates/ui-service.yaml \ 9 | . | tee /dev/stderr | 10 | yq 'length > 0' | tee /dev/stderr) 11 | [ "${actual}" = "true" ] 12 | } 13 | 14 | @test "ui/Service: enable with global.enabled false" { 15 | cd `chart_dir` 16 | local actual=$(helm template \ 17 | -x templates/ui-service.yaml \ 18 | --set 'global.enabled=false' \ 19 | --set 'server.enabled=true' \ 20 | --set 'ui.enabled=true' \ 21 | . | tee /dev/stderr | 22 | yq 'length > 0' | tee /dev/stderr) 23 | [ "${actual}" = "true" ] 24 | } 25 | 26 | @test "ui/Service: disable with server.enabled" { 27 | cd `chart_dir` 28 | local actual=$(helm template \ 29 | -x templates/ui-service.yaml \ 30 | --set 'server.enabled=false' \ 31 | . | tee /dev/stderr | 32 | yq 'length > 0' | tee /dev/stderr) 33 | [ "${actual}" = "false" ] 34 | } 35 | 36 | @test "ui/Service: disable with ui.enabled" { 37 | cd `chart_dir` 38 | local actual=$(helm template \ 39 | -x templates/ui-service.yaml \ 40 | --set 'ui.enabled=false' \ 41 | . | tee /dev/stderr | 42 | yq 'length > 0' | tee /dev/stderr) 43 | [ "${actual}" = "false" ] 44 | } 45 | 46 | @test "ui/Service: disable with ui.service.enabled" { 47 | cd `chart_dir` 48 | local actual=$(helm template \ 49 | -x templates/ui-service.yaml \ 50 | --set 'ui.service.enabled=false' \ 51 | . | tee /dev/stderr | 52 | yq 'length > 0' | tee /dev/stderr) 53 | [ "${actual}" = "false" ] 54 | } 55 | 56 | @test "ui/Service: disable with global.enabled" { 57 | cd `chart_dir` 58 | local actual=$(helm template \ 59 | -x templates/ui-service.yaml \ 60 | --set 'global.enabled=false' \ 61 | . | tee /dev/stderr | 62 | yq 'length > 0' | tee /dev/stderr) 63 | [ "${actual}" = "false" ] 64 | } 65 | 66 | @test "ui/Service: disable with global.enabled and server.enabled on" { 67 | cd `chart_dir` 68 | local actual=$(helm template \ 69 | -x templates/ui-service.yaml \ 70 | --set 'global.enabled=false' \ 71 | --set 'server.enabled=true' \ 72 | . | tee /dev/stderr | 73 | yq 'length > 0' | tee /dev/stderr) 74 | [ "${actual}" = "false" ] 75 | } 76 | 77 | @test "ui/Service: no type by default" { 78 | cd `chart_dir` 79 | local actual=$(helm template \ 80 | -x templates/ui-service.yaml \ 81 | . | tee /dev/stderr | 82 | yq -r '.spec.type' | tee /dev/stderr) 83 | [ "${actual}" = "null" ] 84 | } 85 | 86 | @test "ui/Service: specified type" { 87 | cd `chart_dir` 88 | local actual=$(helm template \ 89 | -x templates/ui-service.yaml \ 90 | --set 'ui.service.type=LoadBalancer' \ 91 | . | tee /dev/stderr | 92 | yq -r '.spec.type' | tee /dev/stderr) 93 | [ "${actual}" = "LoadBalancer" ] 94 | } 95 | -------------------------------------------------------------------------------- /exercises/lab-02/01-enable-connect-inject/index.md: -------------------------------------------------------------------------------- 1 | # Lab 02, Exercise 1: Enable Connect Sidecar Injection 2 | 3 | **Objective:** Enable Connect sidecar injector by applying updated helm chart. 4 | 5 | ## Background 6 | 7 | [Connect](/docs/connect/index.html) is a feature built into to Consul that 8 | enables automatic service-to-service authorization and connection encryption 9 | across your Consul services. Connect can be used with Kubernetes to secure pod 10 | communication with other pods and external Kubernetes services. 11 | 12 | The Connect sidecar running Envoy can be automatically injected into pods in 13 | your cluster, making configuration for Kubernetes automatic. This 14 | functionality is provided by the [consul-k8s 15 | project](https://github.com/hashicorp/consul-k8s) and can be automatically 16 | installed and configured using the [Consul Helm 17 | chart](/docs/platform/k8s/helm.html). 18 | 19 | ## Step 1: Inspect updated configs 20 | 21 | First, navigate to this exercise's directory: 22 | 23 | ``` 24 | cd ~/service-mesh-training/exercises/lab-02/01-enable-connect-inject/ 25 | ``` 26 | Take a look at the updated Kubernetes config files in `files/app`. 27 | 28 | Here we've added [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) which: 29 | 30 | * inject enjoy into every pod: `"consul.hashicorp.com/connect-inject": "true"` 31 | * configure upstream connections 32 | * api.yml: `"consul.hashicorp.com/connect-service-upstreams": "emojify-facebox:8000,emojify-cache:8001"` 33 | * ingress.yml: `"consul.hashicorp.com/connect-service-upstreams": "emojify-website:8000,emojify-api:8001"` 34 | 35 | Once applied, Envoy will be injected into every pod and will handle all traffic between pods via localhost proxies. The API service will be able to connect to upstream services `emojify-faceboox` and `emojify-cache`. The ingress will be able to connect to upstream services `emojify-website` and `emojify-api`. 36 | 37 | ![Emojify architecture](../../../slides/1-overview/images/overview.png "Emojify architecture") 38 | 39 | ## Step 2: Apply updated chart / configs 40 | 41 | Now apply the updated config files: 42 | 43 | ``` 44 | kubectl apply -f files/app 45 | 46 | service/emojify-api-service created 47 | deployment.apps/emojify-api created 48 | service/emojify-cache-service created 49 | deployment.apps/emojify-cache configured 50 | service/emojify-facebox-service created 51 | deployment.apps/emojify-facebox configured 52 | configmap/emojify-ingress-configmap configured 53 | deployment.apps/emojify-ingress configured 54 | secret/emojify unchanged 55 | configmap/emojify-website-configmap unchanged 56 | service/emojify-website-service created 57 | deployment.apps/emojify-website configured 58 | ``` 59 | 60 | ## Step 3: Verify connect sidecars injected and running 61 | 62 | Take a look at the **Consul** tab. You should see the Kubernetes pods listed under services: 63 | 64 | ![Consul sidecar injection](../../images/lab02-consul-sidecar-inject.png "Consul sidecar injection") 65 | -------------------------------------------------------------------------------- /k8s-config/consul/templates/sync-catalog-deployment.yaml: -------------------------------------------------------------------------------- 1 | # The deployment for running the sync-catalog pod 2 | {{- if (or (and (ne (.Values.syncCatalog.enabled | toString) "-") .Values.syncCatalog.enabled) (and (eq (.Values.syncCatalog.enabled | toString) "-") .Values.global.enabled)) }} 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: {{ template "consul.fullname" . }}-sync-catalog 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | app: {{ template "consul.name" . }} 10 | chart: {{ template "consul.chart" . }} 11 | heritage: {{ .Release.Service }} 12 | release: {{ .Release.Name }} 13 | spec: 14 | replicas: 1 15 | selector: 16 | matchLabels: 17 | app: {{ template "consul.name" . }} 18 | chart: {{ template "consul.chart" . }} 19 | release: {{ .Release.Name }} 20 | component: sync-catalog 21 | template: 22 | metadata: 23 | labels: 24 | app: {{ template "consul.name" . }} 25 | chart: {{ template "consul.chart" . }} 26 | release: {{ .Release.Name }} 27 | component: sync-catalog 28 | annotations: 29 | "consul.hashicorp.com/connect-inject": "false" 30 | spec: 31 | serviceAccountName: {{ template "consul.fullname" . }}-sync-catalog 32 | containers: 33 | - name: consul-sync-catalog 34 | image: "{{ default .Values.global.imageK8S .Values.syncCatalog.image }}" 35 | env: 36 | - name: HOST_IP 37 | valueFrom: 38 | fieldRef: 39 | fieldPath: status.hostIP 40 | - name: NAMESPACE 41 | valueFrom: 42 | fieldRef: 43 | fieldPath: metadata.namespace 44 | command: 45 | - "/bin/sh" 46 | - "-ec" 47 | - | 48 | consul-k8s sync-catalog \ 49 | -http-addr=${HOST_IP}:8500 \ 50 | -k8s-default-sync={{ .Values.syncCatalog.default }} \ 51 | {{- if (not .Values.syncCatalog.toConsul) }} 52 | -to-consul=false \ 53 | {{- end }} 54 | {{- if (not .Values.syncCatalog.toK8S) }} 55 | -to-k8s=false \ 56 | {{- end }} 57 | -consul-domain={{ .Values.global.domain }} \ 58 | {{- if .Values.syncCatalog.k8sPrefix }} 59 | -k8s-service-prefix="{{ .Values.syncCatalog.k8sPrefix}}" \ 60 | {{- end }} 61 | -k8s-write-namespace=${NAMESPACE} \ 62 | {{- if (not .Values.syncCatalog.syncClusterIPServices) }} 63 | -sync-clusterip-services=false \ 64 | {{- end }} 65 | {{- if .Values.syncCatalog.nodePortSyncType }} 66 | -node-port-sync-type={{ .Values.syncCatalog.nodePortSyncType }} \ 67 | {{- end }} 68 | {{- if .Values.syncCatalog.k8sTag }} 69 | -consul-k8s-tag={{ .Values.syncCatalog.k8sTag }} 70 | {{- end }} 71 | {{- end }} 72 | -------------------------------------------------------------------------------- /exercises/lab-01/02-install-consul/files/consul/templates/sync-catalog-deployment.yaml: -------------------------------------------------------------------------------- 1 | # The deployment for running the sync-catalog pod 2 | {{- if (or (and (ne (.Values.syncCatalog.enabled | toString) "-") .Values.syncCatalog.enabled) (and (eq (.Values.syncCatalog.enabled | toString) "-") .Values.global.enabled)) }} 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: {{ template "consul.fullname" . }}-sync-catalog 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | app: {{ template "consul.name" . }} 10 | chart: {{ template "consul.chart" . }} 11 | heritage: {{ .Release.Service }} 12 | release: {{ .Release.Name }} 13 | spec: 14 | replicas: 1 15 | selector: 16 | matchLabels: 17 | app: {{ template "consul.name" . }} 18 | chart: {{ template "consul.chart" . }} 19 | release: {{ .Release.Name }} 20 | component: sync-catalog 21 | template: 22 | metadata: 23 | labels: 24 | app: {{ template "consul.name" . }} 25 | chart: {{ template "consul.chart" . }} 26 | release: {{ .Release.Name }} 27 | component: sync-catalog 28 | annotations: 29 | "consul.hashicorp.com/connect-inject": "false" 30 | spec: 31 | serviceAccountName: {{ template "consul.fullname" . }}-sync-catalog 32 | containers: 33 | - name: consul-sync-catalog 34 | image: "{{ default .Values.global.imageK8S .Values.syncCatalog.image }}" 35 | env: 36 | - name: HOST_IP 37 | valueFrom: 38 | fieldRef: 39 | fieldPath: status.hostIP 40 | - name: NAMESPACE 41 | valueFrom: 42 | fieldRef: 43 | fieldPath: metadata.namespace 44 | command: 45 | - "/bin/sh" 46 | - "-ec" 47 | - | 48 | consul-k8s sync-catalog \ 49 | -http-addr=${HOST_IP}:8500 \ 50 | -k8s-default-sync={{ .Values.syncCatalog.default }} \ 51 | {{- if (not .Values.syncCatalog.toConsul) }} 52 | -to-consul=false \ 53 | {{- end }} 54 | {{- if (not .Values.syncCatalog.toK8S) }} 55 | -to-k8s=false \ 56 | {{- end }} 57 | -consul-domain={{ .Values.global.domain }} \ 58 | {{- if .Values.syncCatalog.k8sPrefix }} 59 | -k8s-service-prefix="{{ .Values.syncCatalog.k8sPrefix}}" \ 60 | {{- end }} 61 | -k8s-write-namespace=${NAMESPACE} \ 62 | {{- if (not .Values.syncCatalog.syncClusterIPServices) }} 63 | -sync-clusterip-services=false \ 64 | {{- end }} 65 | {{- if .Values.syncCatalog.nodePortSyncType }} 66 | -node-port-sync-type={{ .Values.syncCatalog.nodePortSyncType }} \ 67 | {{- end }} 68 | {{- if .Values.syncCatalog.k8sTag }} 69 | -consul-k8s-tag={{ .Values.syncCatalog.k8sTag }} 70 | {{- end }} 71 | {{- end }} 72 | -------------------------------------------------------------------------------- /exercises/lab-01/04-install-prometheus-and-grafana/index.md: -------------------------------------------------------------------------------- 1 | # Lab 01, Exercise 04: Install Prometheus and Grafana 2 | 3 | **Objective:** Install [Prometheus](https://prometheus.io) and [Grafana](https://grafana.com) into Kubernetes cluster. 4 | 5 | ## Step 1: Install Prometheus and Grafana 6 | 7 | First, navigate to this exercise's directory: 8 | 9 | ``` 10 | cd ~/service-mesh-training/exercises/lab-01/04-install-prometheus-and-grafana/ 11 | ``` 12 | 13 | Install Prometheus with `kubectl apply`: 14 | 15 | ``` 16 | kubectl apply -f files/prometheus 17 | 18 | configmap/prometheus-server-conf created 19 | clusterrole.rbac.authorization.k8s.io/prometheus created 20 | clusterrolebinding.rbac.authorization.k8s.io/prometheus created 21 | service/prometheus created 22 | service/grafana created 23 | statefulset.apps/prometheus-statefulset created 24 | daemonset.apps/prometheus-statsd created 25 | ``` 26 | 27 | Install Grafana with `kubectl apply`: 28 | 29 | ``` 30 | kubectl apply -f files/metrics-server 31 | 32 | clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created 33 | clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created 34 | rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created 35 | apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created 36 | serviceaccount/metrics-server created 37 | deployment.extensions/metrics-server created 38 | service/metrics-server created 39 | clusterrole.rbac.authorization.k8s.io/system:metrics-server created 40 | clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created 41 | 42 | ``` 43 | 44 | ## Step 2: Verify installation 45 | 46 | With `kubectl` to ensure the pods are running: 47 | 48 | ``` 49 | $ kubectl get pods 50 | NAME READY STATUS RESTARTS AGE 51 | emojify-api-external-cache-788c9964-vs688 3/3 Running 0 10m 52 | emojify-cache-879fdccb7-4464c 3/3 Running 1 10m 53 | emojify-facebox-7b4fdc8b5b-j4b46 3/3 Running 0 10m 54 | emojify-ingress-7b697c574b-zhj76 3/3 Running 0 10m 55 | emojify-loadtest-bf6d754d-8rdvn 1/1 Running 0 71s 56 | emojify-website-5dd8ff4b55-jfn8z 3/3 Running 0 10m 57 | jaunty-cheetah-consul-klfdj 1/1 Running 0 16m 58 | jaunty-cheetah-consul-server-0 1/1 Running 0 16m 59 | prometheus-statefulset-0 2/2 Running 0 2m29s 60 | prometheus-statsd-h4hg2 1/1 Running 0 2m29s 61 | ``` 62 | 63 | Click on the **Grafana** tab in Instruqt and you should see the Grafana user interface: 64 | 65 | ![Grafana dashboard](../../images/lab01-grafana.png "Grafana dashboard") 66 | 67 | The default credentials are username **admin** and password **admin**. 68 | 69 | We won't be using it much for this workshop, but you can also see the **Prometheus** dashboard on that tab: 70 | 71 | ![Prometheus dashboard](../../images/lab01-prometheus.png "Prometheus") 72 | -------------------------------------------------------------------------------- /k8s-config/monitoring/prometheus/statefulset.yml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRole 3 | metadata: 4 | name: prometheus 5 | rules: 6 | - apiGroups: [""] 7 | resources: 8 | - nodes 9 | - nodes/proxy 10 | - services 11 | - endpoints 12 | - pods 13 | verbs: ["get", "list", "watch"] 14 | - apiGroups: 15 | - extensions 16 | resources: 17 | - ingresses 18 | verbs: ["get", "list", "watch"] 19 | - nonResourceURLs: ["/metrics"] 20 | verbs: ["get"] 21 | 22 | --- 23 | apiVersion: rbac.authorization.k8s.io/v1beta1 24 | kind: ClusterRoleBinding 25 | metadata: 26 | name: prometheus 27 | roleRef: 28 | apiGroup: rbac.authorization.k8s.io 29 | kind: ClusterRole 30 | name: prometheus 31 | subjects: 32 | - kind: ServiceAccount 33 | name: default 34 | namespace: default 35 | 36 | --- 37 | kind: Service 38 | apiVersion: v1 39 | metadata: 40 | name: prometheus 41 | spec: 42 | type: NodePort 43 | selector: 44 | app: prometheus-server 45 | ports: 46 | - protocol: TCP 47 | port: 9090 48 | targetPort: 9090 49 | nodePort: 30001 50 | 51 | --- 52 | apiVersion: v1 53 | kind: Service 54 | metadata: 55 | name: grafana 56 | spec: 57 | type: NodePort 58 | ports: 59 | - port: 80 60 | protocol: TCP 61 | targetPort: 3000 62 | nodePort: 30002 63 | selector: 64 | app: prometheus-server 65 | 66 | --- 67 | apiVersion: apps/v1 68 | kind: StatefulSet 69 | metadata: 70 | name: prometheus-statefulset 71 | namespace: default 72 | spec: 73 | serviceName: prometheus 74 | replicas: 1 75 | selector: 76 | matchLabels: 77 | app: prometheus-server 78 | template: 79 | metadata: 80 | labels: 81 | app: prometheus-server 82 | spec: 83 | securityContext: 84 | fsGroup: 2000 85 | runAsUser: 1000 86 | runAsNonRoot: true 87 | volumes: 88 | - name: prometheus-storage-volume 89 | emptyDir: {} 90 | - name: prometheus-config-volume 91 | configMap: 92 | defaultMode: 420 93 | name: prometheus-server-conf 94 | containers: 95 | - name: prometheus 96 | image: prom/prometheus:v2.6.0 97 | args: 98 | - "--config.file=/etc/prometheus/prometheus.yml" 99 | - "--storage.tsdb.path=/prometheus/" 100 | - "--web.enable-lifecycle" 101 | - "--web.enable-admin-api" 102 | ports: 103 | - containerPort: 9090 104 | volumeMounts: 105 | - name: prometheus-config-volume 106 | mountPath: /etc/prometheus/ 107 | - name: prometheus-storage-volume 108 | mountPath: /prometheus/ 109 | 110 | - name: grafana 111 | image: grafana/grafana:6.0.0-beta3 112 | env: 113 | - name: GF_EXPLORE_ENABLED 114 | value: "true" 115 | ports: 116 | - containerPort: 3000 117 | protocol: TCP 118 | volumeMounts: 119 | - name: prometheus-storage-volume 120 | mountPath: /var/lib/grafana 121 | resources: 122 | limits: 123 | cpu: 500m 124 | memory: 2500Mi 125 | requests: 126 | cpu: 100m 127 | memory: 100Mi --------------------------------------------------------------------------------