Add week 6 materials
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
server1:
|
||||
build:
|
||||
context: ./kittens
|
||||
environment:
|
||||
APP_VERSION: 'v1'
|
||||
BIND_PORT: 5001
|
||||
ports:
|
||||
- 9001:5001
|
||||
|
||||
server2:
|
||||
build:
|
||||
context: ./kittens
|
||||
environment:
|
||||
APP_VERSION: 'v2'
|
||||
BIND_PORT: 5002
|
||||
FAILURE_PROBABILITY: '0.8'
|
||||
ports:
|
||||
- 9002:5002
|
||||
|
||||
envoy:
|
||||
image: docker.io/envoyproxy/envoy:v1.27-latest
|
||||
environment:
|
||||
loglevel: debug
|
||||
volumes:
|
||||
- ./envoy.yaml:/etc/envoy/envoy.yaml
|
||||
ports:
|
||||
- 8080:8080
|
||||
@@ -0,0 +1,59 @@
|
||||
admin:
|
||||
address:
|
||||
socket_address:
|
||||
address: 127.0.0.1
|
||||
port_value: 15000
|
||||
|
||||
static_resources:
|
||||
listeners:
|
||||
- address:
|
||||
socket_address:
|
||||
address: 0.0.0.0
|
||||
port_value: 8080
|
||||
filter_chains:
|
||||
- filters:
|
||||
- name: envoy.filters.network.http_connection_manager
|
||||
typed_config:
|
||||
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
|
||||
stat_prefix: http
|
||||
route_config:
|
||||
name: default
|
||||
virtual_hosts:
|
||||
- name: default
|
||||
domains:
|
||||
- "*"
|
||||
routes:
|
||||
- match:
|
||||
prefix: /
|
||||
route:
|
||||
cluster: kittens
|
||||
http_filters:
|
||||
- name: envoy.filters.http.router
|
||||
typed_config:
|
||||
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
|
||||
clusters:
|
||||
- name: kittens
|
||||
connect_timeout: 10s
|
||||
type: STRICT_DNS
|
||||
lb_policy: ROUND_ROBIN
|
||||
outlier_detection:
|
||||
consecutive_5xx: 2
|
||||
interval: "5s"
|
||||
base_ejection_time: "10s"
|
||||
max_ejection_percent: 100
|
||||
load_assignment:
|
||||
cluster_name: kittens
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: server1
|
||||
port_value: 5001
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: server2
|
||||
port_value: 5002
|
||||
|
||||
cluster_manager: {}
|
||||
@@ -0,0 +1,3 @@
|
||||
docker-compose.yaml
|
||||
Dockerfile
|
||||
__pycache__
|
||||
@@ -0,0 +1,12 @@
|
||||
FROM python:3.11.5-slim-bullseye
|
||||
|
||||
WORKDIR /application
|
||||
|
||||
# Copy the requirements file and download the dependencies.
|
||||
COPY requirements.txt requirements.txt
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
# Copy other data.
|
||||
COPY . .
|
||||
|
||||
CMD [ "python3", "app.py"]
|
||||
@@ -0,0 +1,41 @@
|
||||
from flask import Flask, render_template
|
||||
|
||||
import os
|
||||
import random
|
||||
import requests
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
APP_VERSION = os.getenv('APP_VERSION')
|
||||
BIND_HOST = os.getenv('BIND_HOST') or '0.0.0.0'
|
||||
BIND_PORT = os.getenv('BIND_PORT') or '8000'
|
||||
|
||||
FAILURE_PROBABILITY = float(os.getenv('FAILURE_PROBABILITY') or '0.0')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
if random.random() <= FAILURE_PROBABILITY:
|
||||
return f'[{APP_VERSION}] You are unlucky :( Server failed [x]', 500
|
||||
|
||||
return f'Hello from app {APP_VERSION}'
|
||||
|
||||
|
||||
@app.route('/kittens')
|
||||
def kittens():
|
||||
# Get a URL to a random kitten photo.
|
||||
response = requests.get('https://api.thecatapi.com/v1/images/search?api_')
|
||||
|
||||
try:
|
||||
# Response structure is as follows:
|
||||
# [{"id":"bL3lrUi1A","url":"ex.com/bL3lrUi1A.jpg","width":1280,"height":720}]
|
||||
data = response.json()
|
||||
kitten_url = data[0]['url']
|
||||
|
||||
return render_template('index.html', kitten_url=kitten_url)
|
||||
except Exception as e:
|
||||
return f'Failed to fetch a kitten image :(\n {e}'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host=BIND_HOST, port=BIND_PORT)
|
||||
@@ -0,0 +1,2 @@
|
||||
Flask==2.3.3
|
||||
requests==2.28.2
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>DistSys kittens</title>
|
||||
</head>
|
||||
<body>
|
||||
<img src="{{ kitten_url }}">
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,54 @@
|
||||
# Envoy: outlier detection
|
||||
|
||||
[К материалам семинара](../readme.md)
|
||||
|
||||
В стенде работают Envoy и два бэкенда. Первый возвращает успешный ответ на `/`, второй с вероятностью 0.8 возвращает HTTP 500. Envoy наблюдает результаты обычных запросов и временно исключает проблемный бэкенд из балансировки. Это пассивное обнаружение: отдельные запросы проверки здоровья здесь не настроены.
|
||||
|
||||
## Запуск и наблюдение
|
||||
|
||||
Нужны Docker и Docker Compose. Выполните из этой директории:
|
||||
|
||||
```shell
|
||||
docker compose up --build -d
|
||||
```
|
||||
|
||||
После запуска приложений несколько раз отправьте запрос через прокси и сравните с прямыми запросами:
|
||||
|
||||
```shell
|
||||
curl -i http://localhost:8080/
|
||||
curl -i http://localhost:9001/
|
||||
curl -i http://localhost:9002/
|
||||
```
|
||||
|
||||
В PowerShell вместо `curl` используйте `curl.exe`. Ответы содержат версию бэкенда (`v1` или `v2`). Для опыта достаточно пути `/`; путь `/kittens` дополнительно обращается к внешнему API.
|
||||
|
||||
При повторных запросах через Envoy проблемный бэкенд временно исключается, а затем снова допускается к трафику. Прямые запросы к порту 9002 позволяют видеть, что процесс продолжает работать и возвращать ответы, в том числе ошибки. Последовательность случайна: по одному успешному ответу или короткой серии нельзя заключить, что бэкенд исключён.
|
||||
|
||||
## Что означают настройки
|
||||
|
||||
В [конфигурации Envoy](envoy.yaml) задано:
|
||||
|
||||
```yaml
|
||||
outlier_detection:
|
||||
consecutive_5xx: 2
|
||||
interval: "5s"
|
||||
base_ejection_time: "10s"
|
||||
max_ejection_percent: 100
|
||||
```
|
||||
|
||||
- `consecutive_5xx`: исключение после двух последовательных ответов 5xx **от одного бэкенда**, наблюдаемых Envoy. Это не любые две ошибки во всём потоке запросов.
|
||||
- `interval`: период фонового анализа и проверки возврата исключённых бэкендов. Достижение порога последовательных ошибок обрабатывается при запросах, без ожидания следующего такого интервала.
|
||||
- `base_ejection_time`: базовая длительность исключения. При повторных исключениях срок может расти; возврат не гарантирован ровно через 10 секунд.
|
||||
- `max_ejection_percent`: разрешённая доля исключённых бэкендов. Значение 100 позволяет исключить все; это настройка данного учебного примера.
|
||||
|
||||
Исключение меняет маршрутизацию в данном прокси. Оно не останавливает бэкенд и не доказывает, что тот аварийно завершился. Возврат по таймеру тоже не подтверждает исправление приложения: новый запрос может снова завершиться ошибкой.
|
||||
|
||||
Адреса бэкендов заданы в конфигурации. Интеграция с Consul в этом стенде отсутствует.
|
||||
|
||||
После работы:
|
||||
|
||||
```shell
|
||||
docker compose down
|
||||
```
|
||||
|
||||
Подробнее: [outlier detection в документации Envoy](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/outlier), [справочник параметров](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/outlier_detection.proto).
|
||||
Reference in New Issue
Block a user