Статичний сайт з HTML, NGINX і Docker

текст перекладу
pic

Зображення згенеровано ШІ

  1. Тримайте функції маленькими та зосередженими

Функції повинні виконувати одну задачу і робити це добре. Це робить код легким для читання, тестування та підтримки.

# Погано: Виконує кілька задач  
def process_data(data):  
 cleaned_data = [x.strip() for x in data]  
 return sum(cleaned_data) / len(cleaned_data)  

# Добре: Розділено на зосереджені функції  
def clean_data(data):  
 return [x.strip() for x in data]  

def calculate_average(cleaned_data):  
 return sum(cleaned_data) / len(cleaned_data)

2. Використовуйте описові імена

Імена функцій повинні чітко описувати їх призначення, щоб було зрозуміло, що вони роблять, без необхідності читати весь код функції.

# Неясно  
def proc(d):  
 pass  

# Ясно  
def calculate_montly_revenue(transactions):  
 pass

3. Використовуйте підказки типів

Підказки типів покращують читабельність коду та допомагають зі статичним аналізом (наприклад, IDE або лінтери можуть виявити невідповідність типів). Це також покращує співпрацю, чітко визначаючи очікувані типи.

# Без підказок  
def add(a, b):  
 return a + b  

# З підказками  
def add(a: int, b: int) -> int:  
 return a + b

Тут підказки типів int для обох параметрів та типу повернення чітко вказують, що функція очікує цілі числа і повертає ціле число.

4. Обмежуйте кількість параметрів

Уникайте функцій з надмірною кількістю параметрів, оскільки їх стає важче зрозуміти та підтримувати. Якщо функція потребує багатьох вхідних даних, розгляньте можливість використання словника або класу для їх групування.

# Погана практика  
def send_email(subject: str, body: str, to: str, cc: str, bcc: str, attachment: str):  
 pass  

# Добра практика  
def send_email(email_info: dict):  
 # email_info містить subject, body, to, cc, bcc, attachment  
 pass

У покращеній версії використовується словник для об'єднання всіх параметрів в один структурований вхід.

5. Пишіть docstrings

Завжди документуйте призначення, параметри, тип повернення та виключення вашої функції. Це допоможе поточним та майбутнім розробникам зрозуміти функцію, не риючись у коді.

def multiply(x: int, y: int) -> int:  
 """  
 Множить два числа.  

 Аргументи:  
 x (int): Перше число.  
 y (int): Друге число.  

 Повертає:  
 int: Результат множення x та y.  
 """  
 return x * y

6. Уникайте побічних ефектів

Функції не повинні змінювати глобальні змінні або зовнішній стан, якщо це не є явною частиною їхнього дизайну. Функції з побічними ефектами важче тестувати та підтримувати.

# Погано: Ця функція несподівано змінює зовнішній стан (список)  
external_list = []  

def add_to_list(value: int):  
 external_list.append(value)  

add_to_list(5)  
print(external_list) # external_list змінений, що може бути заплутаним  


# Добра практика  
def add_to_list(value: int, list_: list) -> list:  
 list_.append(value)  
 return list_  

my_list = []  
print(add_to_list(5, my_list)) # Output: [5]

7. Обережно з аргументами за замовчуванням

Уникайте використання змінних типів, які можна змінювати (наприклад, списків або словників) як значень за замовчуванням для аргументів, оскільки вони зберігають свій стан між викликами функції, що може призвести до непередбачуваного поведінки.

# Погана практика  
def append_item(item, list=[]):  
 list.append(item)  
 return list  

print(append_item(1)) # Output: [1]  
print(append_item(2)) # Output: [1, 2] - Список за замовчуванням змінюється між викликами!  



# Добра практика  
def append_item(item, list=None):  
 if list is None:  
 list = []  
 list.append(item)  
 return list  

print(append_item(1)) # Output: [1]  
print(append_item(2)) # Output: [2]

Покращена версія гарантує, що для кожного виклику функції створюється новий список.

8.
текст перекладу

![pic](https://drive.javascript.org.ua/41c2827b261_FNAjjNVfnJ9AMAlsrbGqPQ_png)
Щоб зберегти, просто натисніть CTRL + O та ENTER, потім CTRL + X, щоб вийти. Тепер ми додамо інформацію до нашого Dockerfile.
Примітка: за замовчуванням завжди пишіть 'D' з великої літери у назві Dockerfile, оскільки це просто синтаксична конвенція, визначена Docker.
nano Dockerfile
Будуть додані наступні рядки:

FROM nginx:alpine # Копіюємо HTML файл
COPY index.html /usr/share/nginx/html/index.html # Відкриваємо порт
EXPOSE 80 # Запускаємо NGINX
CMD ["nginx", "-g", "daemon off;"]
```
pic
Ті ж самі команди для збереження.
Пояснення Dockerfile:
1. **FROM nginx:alpine
: Використовує базовий образ Nginx, заснований на Alpine Linux (легка версія Nginx).
2. COPY index.html /usr/share/nginx/html/index.html: Копіює файл index.html з вашої локальної директорії до директорії Nginx всередині контейнера.
3. EXPOSE 80: Вказує, що контейнер використовуватиме порт 80 для HTTP трафіку.
4. CMD [“nginx”, “-g”, “daemon off;”]: Визначає команду, яка буде виконуватися під час запуску контейнера — запустити Nginx на передньому плані (параметр daemon off запобігає запуску Nginx у фоновому режимі).

Далі ми зробимо те саме для app2, тому скопіюємо обидва файли (Dockerfile та index.html) до папки app2.

cp Dockerfile index.html ../app2/
cd ../app2/
ls

pic
У папці app2 зміниться лише один рядок HTML.

nano index.html

Рядок, що буде змінений:

"Цей запит виконується контейнером 02."

pic
Після збереження файлу, перейдемо до папки nginx.

cd ../nginx/

Тепер ми створимо файл конфігурації для балансувальника навантаження NGINX.

nano nginx.conf

Конфігурація:

events {}
http {
upstream backend_servers {
server app1:80;
server app2:80;
}
server {
listen 80;
location / {
proxy_pass http://backend_servers;
}
}
}

pic
Пояснення:
1. events {}: Налаштування, що стосуються керування з'єднаннями та подіями, зазвичай для оптимізації продуктивності, але без конкретних визначень тут.
2. http {}: Визначає налаштування для HTTP сервера, включаючи обробку вхідних з'єднань.
3. upstream backend_servers {}: Визначає групу бекенд серверів (названих app1 та app2), яку NGINX використовує для балансування навантаження.
4. server { listen 80; }: Налаштовує NGINX на прослуховування порту 80 для отримання HTTP трафіку.
5. location / { proxy_pass http://backend_servers; }: Перенаправляє весь трафік до групи серверів бекенду, визначених у секції upstream. NGINX працює як зворотний проксі для пересилання запитів до app1 або app2.

Після збереження файлу конфігурації повернемося до папки nginx-site та відредагуємо файл docker-compose.yml.

cd ..
nano docker-compose.yml

Далі додамо таку конфігурацію в docker-compose.yml:

services:
load-balancer:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
app1:
image: nginx-lb-app1
build: ./app1
app2:
image: nginx-lb-app2
build: ./app2

pic
Зберігаємо та виходимо.
Пояснення щодо docker-compose:
1. services: Визначає сервіси, які будуть запущені в Docker Compose.
2.
текст перекладу
load-balancer: Сервіс для NGINX, який працює як балансувальник навантаження.

  • image: nginx:latest: Використовує останній образ NGINX.
  • ports: “8080:80”: Мапує порт 80 контейнера на порт 8080 хоста.
  • volumes: ./nginx/nginx.conf:/etc/nginx/nginx.conf: Замінює конфігураційний файл NGINX всередині контейнера на файл nginx.conf, розташований у директорії ./nginx на хості.
  1. app1: Сервіс для першого додатку.
  • image: nginx-lb-app1: Використовує образ nginx-lb-app1 для додатку.
  • build: ./app1: Створює образ сервісу з директорії ./app1.
  1. app2: Сервіс для другого додатку.
  • image: nginx-lb-app2: Використовує образ nginx-lb-app2 для додатку.
  • build: ./app2: Створює образ сервісу з директорії ./app2.

Ці сервіси разом налаштовують балансувальник навантаження, який розподіляє трафік між app1 та app2.

Зберігши файл конфігурації, тепер ми виконаємо docker-compose для запуску нашого додатку та балансувальника навантаження.

Виконайте наступну команду:

docker compose up -d

Примітка: опція -d в Docker Compose дозволяє запускати контейнери в фоні (detached mode), тобто вона запускає контейнери та повертає контроль до терміналу, без необхідності залишати термінал відкритим для перегляду логів контейнерів.

pic

Введіть команду ‘docker ps’, щоб побачити активні контейнери, і ви побачите наші додатки разом з балансувальником навантаження.

Тепер, якщо ми відкриємо браузер і введемо IP нашої віртуальної машини разом з портом, ми отримаємо доступ до нашого статичного сайту.

Примітка: якщо хочете перевірити IP машини, просто введіть ‘ip a’, і ви побачите IP, який за замовчуванням буде 192.168.x.x.

Введіть у пошук браузера: 192.168.x.x:8080

pic

pic

Готово! Тепер ми маємо доступ до нашого додатку за допомогою балансувальника навантаження.

Просто оновіть сторінку (F5), і вона буде перемикатися між app1 та app2.

Але це лише для демонстрації, ви також можете використовувати лише один додаток для обох контейнерів, і все працюватиме так само!

Перекладено з: Site estático com HTML, NGINX e Docker

Leave a Reply

Your email address will not be published. Required fields are marked *