1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/daba0007-k8s-web

В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
k8s-web.md 27 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 27.11.2024 19:37 12f99c6

k8s-web кластерная архитектура с нуля

K8s как архитектура сама по себе представляет собой довольно трудоёмкий процесс настройки окружения. Я попробовал множество методов, надеясь на быструю и прямую настройку. Вот мой опыт:

Процесс настройки k8s

  1. Я попытался использовать Rancher для настройки. Rancher — это открытая платформа для управления контейнерами корпоративного уровня, которая предоставляет развёртывание k8s. Нам нужно только добавить хост, а Rancher поможет нам развернуть. Однако этот процесс развёртывания действительно требует усилий, и не только из-за медленного извлечения образов. Так что те, у кого есть возможность, могут попробовать, но я должен искать другие методы.

  2. Самый сложный метод, конечно, — это ручная установка. Ручная установка не только помогает нам лучше понять процесс работы k8s, но и гарантирует, что каждый шаг будет выполнен без ошибок. Но это очень сложно. Я уже написал документ MD, который может быть полезен для заинтересованных студентов.

  3. Третий метод, который я нашёл в интернете, заключается в том, что кто-то уже написал 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, можно эффективно реализовать разделение чтения и записи базы данных, тем самым повышая способность сервера выдерживать нагрузку. Основная база данных в основном выполняет операции записи, в то время как подчинённая база данных отвечает за операции чтения.

Процесс:

  1. Когда подчинённая база данных запускается, она отправляет команду синхронизации основной базе данных;
  2. После получения команды синхронизации основная база данных начинает сохранять снимок в фоновом режиме (выполняя операцию RDB) и сохраняет все команды, полученные во время сохранения снимка;
  3. После завершения сохранения снимка Redis отправит снимок файла и все сохранённые команды подчинённой базе данных;
  4. После того как подчинённая база данных получит его, она загрузит снимок файла и выполнит сохранённые команды.

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-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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/daba0007-k8s-web.git
git@api.gitlife.ru:oschina-mirror/daba0007-k8s-web.git
oschina-mirror
daba0007-k8s-web
daba0007-k8s-web
master