k8s-web кластерная архитектура с нуля
K8s как архитектура сама по себе представляет собой довольно трудоёмкий процесс настройки окружения. Я попробовал множество методов, надеясь на быструю и прямую настройку. Вот мой опыт:
Процесс настройки k8s
Я попытался использовать Rancher для настройки. Rancher — это открытая платформа для управления контейнерами корпоративного уровня, которая предоставляет развёртывание k8s. Нам нужно только добавить хост, а Rancher поможет нам развернуть. Однако этот процесс развёртывания действительно требует усилий, и не только из-за медленного извлечения образов. Так что те, у кого есть возможность, могут попробовать, но я должен искать другие методы.
Самый сложный метод, конечно, — это ручная установка. Ручная установка не только помогает нам лучше понять процесс работы k8s, но и гарантирует, что каждый шаг будет выполнен без ошибок. Но это очень сложно. Я уже написал документ MD, который может быть полезен для заинтересованных студентов.
Третий метод, который я нашёл в интернете, заключается в том, что кто-то уже написал playbook Ansible для ручной установки. Это значительно упрощает установку, и я хочу выразить свою благодарность за это.
Настройка k8s-web
Здесь упоминается множество файлов YAML, которые я в основном комментирую. Однако я не буду повторять комментарии для тех, кто их уже сделал. Надеюсь, читатели смогут закончить чтение и продолжить.
Redis-сервис
После стольких обсуждений наш кластер k8s наконец настроен. В соответствии с нашим предыдущим веб-кластером мы сначала настроим архитектуру конфигурации главного и подчинённого Redis.
Принцип
Для постоянных баз данных, таких как MySQL, Oracle и SQL Server, данные хранятся на жёстком диске компьютера, на котором развёрнута база данных. Когда объём обработки и доступа к веб-сайту становится большим, нагрузка на базу данных также увеличивается. Чтобы повысить эффективность веб-сайта, снизить количество операций чтения и записи базы данных и уменьшить нагрузку на неё, мы должны внедрить технологию кэширования. Кэширование — это резервное копирование данных в памяти. Когда данные не претерпевают существенных изменений, мы не позволяем запросу данных выполнять операции с базой данных, а извлекаем данные из памяти. Таким образом, значительно снижается количество операций чтения и записи в базе данных, и скорость извлечения данных из памяти выше, чем скорость запроса к базе данных.
Redis поддерживает не только простые структуры данных типа ключ-значение, но также списки, наборы, упорядоченные наборы и хэши. Он также обеспечивает постоянство данных и может сохранять данные в памяти на диск, чтобы при перезапуске можно было снова загрузить и использовать их. По сравнению с Memcache, максимальное ограничение одного значения составляет 1 ГБ, а Memcached может хранить только 1 МБ данных.
Поэтому мы используем Redis в качестве службы кэширования для нашего веб-кластера.
Главный и подчинённый серверы
Сначала создадим собственное изображение Redis. Изображения Redis делятся на два типа: Redis-master и Redis-slave. Функция репликации Redis позволяет синхронизировать данные между несколькими базами данных. Одна — основная база данных (master), а другая — подчинённая база данных (slave). Основная база данных может выполнять операции чтения и записи, а когда происходит операция записи, она автоматически синхронизирует данные с подчинённой базой данных. Подчинённая база данных обычно предназначена только для чтения и получает данные, синхронизированные основной базой данных. Основная база данных может иметь несколько подчинённых баз данных, но каждая подчинённая база данных имеет только одну основную базу данных.
Используя функцию репликации Redis, можно эффективно реализовать разделение чтения и записи базы данных, тем самым повышая способность сервера выдерживать нагрузку. Основная база данных в основном выполняет операции записи, в то время как подчинённая база данных отвечает за операции чтения.
Процесс:
Redis-master
Мы можем использовать команду docker pull для извлечения стандартного образа Redis (в прошлый раз я обнаружил, что извлечение из daocloud.io было быстрее).
docker pull daocloud.io/redis
Затем мне нужно написать собственный файл конфигурации Redis и поместить его в образ для использования (основное изменение — закомментировать bind для включения удалённого доступа и использования фонового режима).
Мой Dockerfile выглядит следующим образом:
FROM daocloud.io/redis
MAINTAINER daba0007
ADD redis-master.conf /etc/redis/redis.conf
WORKDIR /etc/redis/
CMD redis-server redis.conf
Создайте Dockerfile и отправьте его в мой репозиторий.
docker build -t daba0007/redis-master .
docker push daba0007/redis-master
Таким образом, у нас есть изображение Redis-master, которое нам нужно.
Теперь давайте начнём использовать k8s и сначала напишем файл redis-master-rc.yaml.
apiVersion: v1 # api версия
kind: ReplicationController # тип rc
metadata: # метаданные (объект rc)
name: redis-master
spec: #
replicas: 1 # означает запуск одного модуля, если модулей больше, можно сделать балансировку нагрузки и высокую доступность
selector: # селектор rc, то есть модуль, соответствующий этим меткам, будет управляться и контролироваться. Когда запущенных модулей меньше, чем replicas, rc будет создавать новый модуль на основе определения шаблона в spec:template, когда это необходимо.
name: redis-master
template: # определение шаблона, модуль будет запущен, когда недостаточно модулей
metadata:
labels: # метки свойств определяют метки модуля, обратите внимание: здесь метки должны соответствовать селектору rc:spec
name: redis-master
spec:
containers:
- name: redis-master
image: daba0007/redis-master
ports:
- containerPort: 6379
Используйте команду для публикации в кластере k8s.
[root@k8s-master redis-master]# kubectl create -f redis-master-rc.yaml
replicationcontroller "redis-master" создан
[root@k8s-master redis-master]# kubectl get pods
NAME READY STATUS RESTARTS AGE
redis-master-25bpz 1/1 Running 0 13s
[root@k8s-master redis-master]# kubectl get rc
NAME DESIRED CURRENT READY AGE
redis-master 1 1 1 30s
Далее мы создадим сервис.
apiVersion: v1
kind: Service
metadata:
name:redis-master
labels:
name: redis-master
spec:
ports:
- port: 6379 # service открыт на виртуальном IP кластера, то есть виртуальный порт
targetPort: 6379 # порт модуля
selector:
name: redis-master # какие модули принадлежат этому сервису
Запустите сервис.
[root@k8s-master redis-master]# kubectl create -f redis-master-svc.yaml
service "redis-master" создана
[root@k8s-master redis-master]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 3h
redis-master ClusterIP 10.68.69.173 <none> 6379/TCP 5s
Так успешно создан главный сервис Redis. Создание пользователя и предоставление прав в MySQL:
CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ; GRANT REPLICATION SLAVE ON . TO '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ; FLUSH PRIVILEGES ;
Создание образа Docker:
docker build -t daba0007/mysql-master . docker push daba0007/mysql-master
Генерация нового образа MySQL-Master для предоставления услуг:
Затем создаётся файл mysql-master-rc.yaml, где мы хотим смонтировать папку с данными database для последующего переноса данных:
apiVersion: v1 kind: ReplicationController metadata: name: mysql-master labels: name: mysql-master spec: replicas: 1 selector: name: mysql-master template: metadata: labels: name: mysql-master spec: containers: - name: mysql-master image: daba0007/mysql-master volumeMounts: # Смонтированный на контейнере том данных - name: mysql-database # Метка mountPath: /etc/mysql/database # Путь тома данных на контейнере readOnly: false # Возможность чтения и записи env: - name: MYSQL_ROOT_PASSWORD # Пароль базы данных root value: "123456" - name: MYSQL_REPLICATION_USER # Предоставленный пользователю репликации доступ value: "test" - name: MYSQL_REPLICATION_PASSWORD # Пароль предоставленного пользователя репликации value: "123456" ports: - containerPort: 3306 volumes: # Смонтированные на хосте тома данных - name: mysql-database # Соответствующая метка hostPath: path: /root/k8s/mysql/mysql-master/database # Путь тома данных на хосте
После этого выполняется команда:
kubectl create -f mysql-master-rc.yaml replicationcontroller "mysql-master" created
Получение информации о контроллерах репликации:
kubectl get rc NAME DESIRED CURRENT READY AGE mysql-master 1 1 1 12s redis-master 1 1 1 1d redis-slave 2 2 2 1d
Получение информации об активных модулях:
kubectl get pods NAME READY STATUS RESTARTS AGE mysql-master-whtwd 1/1 Running 0 8s redis-master-25bpz 1/1 Running 3 2d redis-slave-plrxq 1/1 Running 2 1d redis-slave-thb9r 1/1 Running 2 1d
Далее создаётся файл mysql-master-svc.yaml для сервиса MySQL:
apiVersion: v1
kind: Service
metadata:
name: mysql-master
labels:
name: mysql-master
spec:
ports:
- port: 3306
targetPort: 3306
selector:
name: mysql-master
И затем создаётся сервис:
kubectl create -f mysql-master-svc.yaml service "mysql-master" created
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 443/TCP 2d mysql-master ClusterIP 10.68.83.79 3306/TCP 5s redis-master ClusterIP 10.68.69.173 6379/TCP 2d redis-slave ClusterIP 10.68.174.55 6379/TCP 1d
На этом этапе мы создали основной сервис MySQL.
Создание MySQL-Slave немного отличается от создания MySQL-Master. В файле Dockerfile добавляется следующая строка (одновременно изменяется предыдущая):
RUN RAND="$(date +%s | rev | cut -c 1-2)$(echo ${RANDOM})" && sed -i '/[mysqld]/a server-id='$RAND'\nlog-bin' /etc/mysql/mysql.conf.d/mysqld.cnf
Здесь server-id использует случайное число.
В файле docker-entrypoint.sh добавляется следующее:
echo "STOP SLAVE;" | "${mysql[@]}" echo "CHANGE MASTER TO master_host='$MYSQL_MASTER_SERVICE_HOST', master_user='$MYSLAVE_REPLICATION_USER', master_password='$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}" echo "START SLAVE;" | "${mysql[@]}"
В конфигурации slave используется master_host, который является $MYSQL_MASTER_SERVICE_HOST. Эта переменная окружения генерируется Kubernetes.
После создания сервиса Kubernetes автоматически назначает динамический кластерный IP-адрес. Мы не можем использовать или жёстко кодировать этот адрес, поэтому Kubernetes создаёт набор переменных окружения для записи сопоставления между именем сервиса и кластерным IP-адресом. Это позволяет контейнерам использовать эти переменные для доступа к сервису.
Например, если имя сервиса — foo, то генерируются следующие переменные окружения:
FOO_SERVICE_HOST FOO_SERVICE_PORT
Для получения дополнительной информации рекомендуется обратиться к официальным документам Kubernetes: http://kubernetes.io/docs/user-guide/container-environment/. docker build -t daba0007/mysql-slave .
docker push daba0007/mysql-slave
Затем написать mysql-slave-rc.yaml
apiVersion: v1 kind: ReplicationController metadata: name: mysql-slave labels: name: mysql-slave spec: replicas: 2 selector: name: mysql-slave template: metadata: labels: name: mysql-slave spec: containers: - name: mysql-slave image: daba0007/mysql-slave env: - name: MYSQL_ROOT_PASSWORD value: "123456" - name: MYSQL_REPLICATION_USER value: "test" - name: MYSQL_REPLICATION_PASSWORD value: "123456" ports: - containerPort: 3306
**Затем создать**
[root@k8s-master mysql-slave]# kubectl create -f mysql-slave-rc.yaml replicationcontroller "mysql-slave" created
[root@k8s-master mysql-slave]# kubectl get rc NAME DESIRED CURRENT READY AGE mysql-master 1 1 1 22m mysql-slave 2 2 1 7s redis-master 1 1 1 1d redis-slave 2 2 2 1d
[root@k8s-master mysql-slave]# kubectl get pods NAME READY STATUS RESTARTS AGE mysql-master-whtwd 1/1 Running 0 1m mysql-slave-6x8bx 1/1 Running 0 11s mysql-slave-n58vk 1/1 Running 0 11s redis-master-25bpz 1/1 Running 3 2d redis-slave-plrxq 1/1 Running 2 1d redis-slave-thb9r 1/1 Running 2 1d
После этого написать mysql-slave-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-slave
labels:
name: mysql-slave
spec:
ports:
- port: 3306
targetPort: 3306
selector:
name: mysql-slave
**Затем создать mysql-slave сервис**
[root@k8s-master mysql-slave]# kubectl create -f mysql-slave-svc.yaml service "mysql-slave" created
[root@k8s-master mysql-slave]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 443/TCP 2d mysql-master ClusterIP 10.68.83.79 3306/TCP 1m mysql-slave ClusterIP 10.68.208.186 3306/TCP 9s redis-master ClusterIP 10.68.69.173 6379/TCP 2d redis-slave ClusterIP 10.68.174.55 6379/TCP 1d
Таким образом, mysql-slave служба успешно создана. Теперь можно проверить, синхронизируются ли данные с главной базой данных.
### Тестирование
Как убедиться, что мы успешно создали соединение между главной и подчинённой базами данных MySQL?
Сначала нужно войти в нашу главную базу данных, импортировать нашу базу данных и просмотреть её содержимое. Мы увидим, что данные были импортированы.
```bash
[root@k8s-master mysql-slave]# kubectl exec -ti mysql-master-whtwd /bin/bash
root@mysql-master-whtwd:/# cd /etc/mysql/database/
root@mysql-master-whtwd:/etc/mysql/database# mysql -uroot -p -e "create database form;" # 创建form数据库
Enter password:
root@mysql-master-whtwd:/etc/mysql/database# mysql -uroot -p form < form.sql # 导入我们之前的数据库
Enter password:
root@mysql-master-whtwd:/etc/mysql/database# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.20-log MySQL Community Server (GPL)
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show master status;
+-------------------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------------------+----------+--------------+------------------+-------------------+
| mysql-master-whtwd-bin.000003 | 18218 | | | |
+-------------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)
mysql> use form;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables; **Перевод текста на русский язык:**
Здесь необходимо заменить host MySQL и location Redis на IP-адреса сервисов. Сначала создадим Dockerfile:
# Базовый образ
FROM daocloud.io/python:3.6
# Информация о сопровождающем
MAINTAINER daba0007
ADD dabaweb.tar.gz /usr/src/
# Каталог приложения
WORKDIR /usr/src/dabaweb
RUN pip install xlutils
RUN pip install django-redis
# Установка необходимых зависимостей приложения
RUN pip install --no-cache-dir -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
# Запуск выполнения команды
COPY entrypoint.sh /usr/src/
WORKDIR /usr/src
RUN chmod +x /usr/src/entrypoint.sh
ENTRYPOINT ["/usr/src/entrypoint.sh"]
Вот содержимое скрипта запуска entrypoint.sh:
#!/bin/bash
sed -i "s/service_mysql/$(echo $MYSQL_MASTER_SERVICE_HOST)/g" /usr/src/dabaweb/dabaweb/setting.py
sed -i "s/service_redis/$(echo $REDIS_MASTER_SERVICE_HOST)/g" /usr/src/dabaweb/dabaweb/setting.py
# Использование uwsgi для запуска Django
/usr/local/bin/uwsgi --http :8000 --chdir /usr/src/dabaweb -w dabaweb.wsgi
Создадим Dockerfile и загрузим его:
docker build -t daba0007/dabaweb .
docker push daba0007/dabaweb
Теперь создадим Dockerfile для nginx:
FROM daba0007/nginx
MAINTAINER daba0007
RUN rm /etc/nginx/conf.d/default.conf
ADD nginx-conf/ /etc/nginx/conf.d/
В конфигурации nginx proxy_pass будет указывать на localhost, так как всё находится в одном pod.
server {
listen 80;
server_name localhost;
charset utf-8;
root /usr/src/dabaweb;
access_log /var/log/nginx/django.log;
location ^~ /static {
alias /usr/src/dabaweb/static;
}
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Нам нужно смонтировать папку. Создадим файл dabacluster-rc.yaml:
apiVersion: v1
kind: ReplicationController
metadata:
name: dabacluster
labels:
name: dabacluster
spec:
replicas: 3
selector:
name: dabacluster
template:
metadata:
labels:
name: dabacluster
spec:
containers:
- name: dabaweb
image: daba0007/dabaweb
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 8000
volumeMounts:
- name: dabaweb-dir
mountPath: /usr/src/dabaweb
readOnly: false
- name: dabanginx # Этот контейнер — nginx кластера, который выставляет порт 80 для удобства доступа к сервисам
image: daba0007/dabanginx
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 80
volumeMounts: # Также нужно монтировать эти два тома данных
- name: dabaweb-dir
mountPath: /usr/src/dabaweb
readOnly: false
volumes:
- name: dabaweb-dir
hostPath:
path: /root/k8s/web/web/dabaweb/
Затем выполним:
[root@k8s-master web]# kubectl create -f dabacluster-rc.yaml
replicationcontroller "dabacluster" created
NAME DESIRED CURRENT READY AGE
dabacluster 3 3 3 1m
mysql-master 1 1 1 1d
mysql-slave 2 2 2 1d
redis-master 1 1 1 3d
redis-slave 2 2 2 3d
[root@k8s-master web]# kubectl get pod
NAME READY STATUS RESTARTS AGE
dabacluster-5kp26 2/2 Running 0 18s
dabacluster-7dhsk 2/2 Running 0 18s
dabacluster-mww8t 2/2 Running 0 18s
mysql-master-whtwd 1/1 Running 3 2d
mysql-slave-6x8bx 1/1 Running 3 2d
mysql-slave-n58vk 1/1 Running 3 2d
redis-master-25bpz 1/1 Running 6 4d
redis-slave-plrxq 1/1 Running 5 4d
redis-slave-thb9r 1/1
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )