В этом руководстве показаны подробные шаги по развертыванию MySQL в Kubernetes.
Я буду использовать minikube, чтобы продемонстрировать примеры работы на Kubernetes СУБД MySQL.
Все мы знаем о большой важности сохранения данных, и почти все наши приложения во многом полагаются на какие-то системы управления базами данных (СУБД).
Настройка СУБД на Kubernetes помогает команде DevOps и администраторам баз данных легко использовать и масштабировать базу данных.
Подготовьте окружающую среду следуя этому руководству, вам необходимо установить Minikube на Ubuntu Linux.
Вы можете проверить, успешно ли был запущен Minikube, с помощью следующей команды:
$ minikube status
Вывод:
minikube type: Control Plane host: Running kubelet: Running apiserver: Running kubeconfig: Configured
Создадим секрет для MySQL
Kubernetes использует Secret для хранения и управления конфиденциальной информацией, такой как пароли, ключи ssh и токены OAuth.
В этом руководстве мы используем кодировку base64 для хранения MYSQL_ROOT_PASSWORD.
Например:
$ echo -n 'admin' | base64
Вывод:
YWRtaW4=
Создайте файл mysql-secret.yaml для MySQL, который будет отображаться как переменная среды следующим образом:
apiVersion: v1 kind: Secret metadata: name: mysql-pass type: Opaque data: password: YWRtaW4=
Примените манифест:
$ kubectl create -f mysql-secret.yaml secret/mysql-pass created
Убедитесь, что секрет только что успешно создан:
$ kubectl get secrets NAME TYPE DATA AGE default-token-l7t7b kubernetes.io/service-account-token 3 4h24m mysql-pass Opaque 1 1m
Развертка MySQL
Создайте файл mysql-pod.yaml для развертывания модуля MySQL в кластере Kubernetes:
apiVersion: v1 kind: Pod metadata: name: k8s-mysql labels: name: lbl-k8s-mysql spec: containers: - name: mysql image: mysql:latest env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-pass key: password ports: - name: mysql containerPort: 3306 protocol: TCP volumeMounts: - name: k8s-mysql-storage mountPath: /var/lib/mysql volumes: - name: k8s-mysql-storage emptyDir: {}
Применим файл манифеста:
$ kubectl create -f mysql-pod.yaml pod/k8s-mysql created
$ kubectl get pod NAME READY STATUS RESTARTS AGE k8s-mysql 1/1 Running 0 30s
Теперь мы можем подключиться к поду k8s-mysql: 2
$ kubectl exec k8s-mysql -it -- bash root@k8s-mysql:/# echo $MYSQL_ROOT_PASSWORD admin root@k8s-mysql:/# mysql --user=root --password=$MYSQL_ROOT_PASSWORD mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 11 Server version: 8.0.22 MySQL Community Server - GPL Copyright (c) 2000, 2020, 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 databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec) mysql>
Kubernetes использует Service для предоставления доступа к подам другим подам или внешним системам.
Мы будем использовать следующий файл манифеста mysql-service.yaml, чтобы сделать pod k8s-mysql доступным:
apiVersion: v1 kind: Service metadata: name: mysql-service labels: name: lbl-k8s-mysql spec: ports: - port: 3306 selector: name: lbl-k8s-mysql type: ClusterIP
Примените манифест для создания сервиса:
$ kubectl create -f mysql-service.yaml service/mysql-service created
Убедитесь, что служба была успешно создана:
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 5h4m mysql-service ClusterIP 10.110.22.182 3306/TCP 30s
Создание NodeJS Api для обращения к mysql
Чтобы иметь возможность подключиться к mysql из другого подая, нам необходимо иметь IP-адрес нашего пода, что можно сделать с помощью:
$ kubectl get pod k8s-mysql -o template --template={{.status.podIP}} 172.17.0.5
Хорошо, теперь я собираюсь создать образец приложения NodeJS, чтобы хранить набор сообщений в таблице MESSAGES базы данных, приложение будет иметь две конечные точки:
- ‘/ping’: проверить работоспособность сервера
- ‘/msg-api/all’: получить все сохраненные сообщения
Для простоты … в таблице будет только один столбец с именем TEXT.
Первым делом приложение узла: //api.js -> сюда идут конечные точки
var express = require('express') var mysql = require('mysql') var Router = express.Router(); var ConnPool = mysql.createPool({ host: '172.17.0.5', user: 'root', password: 'admin', database: 'k8smysqldb' }) // create database and MESSAGE table if not exist ConnPool.query('CREATE DATABASE IF NOT EXISTS k8smysqldb', function (err) { if (err) throw Error('\n\t **** error creating database **** ' + err) console.log('\n\t ==== database k8smysqldb created !! ====') ConnPool.query('USE k8smysqldb', function (err) { if (err) throw Error('\n\t **** error using database **** ' + err); console.log('\n\t ==== database k8smysqldb switched !! ====') ConnPool.query('CREATE TABLE IF NOT EXISTS messages(' + 'id INT NOT NULL AUTO_INCREMENT,' + 'PRIMARY KEY(id),' + 'text VARCHAR(100)' + ')', function (err) { if (err) throw Error('\n\t **** error creating table **** ' + err); }) }) }) /** * /all */ Router.get('/all', function (req, res) { ConnPool.getConnection(function (errConn, conn) { if (errConn) throw Error('error get connection : ' + errConn) conn.query('SELECT * FROM messages', function (errSelect, rows) { if (errSelect) throw Error('error selecting messages : ' + errSelect) res.writeHead(200, { 'Content-Type': 'application/json' }); var result = { success: true, rows: rows.length, } res.write(JSON.stringify(rows)); res.end(); }) }) }) module.exports = Router
var express = require('express') var msgApi = require('./api') var app = express() app.use('/msg-api', msgApi) app.get('/ping', function (req, res) { res.write("hello there! I m up and running!"); res.end(); }) app.listen(8080, function () { console.log('\n\t ==== Message API listening on 8080! ====') })
FROM node:latest RUN mkdir -p /usr/src/app WORKDIR /usr/src/app COPY package.json /usr/src/app/package.json RUN npm i COPY . /usr/src/app/ EXPOSE 8080 CMD [ "node", "server.js" ]
$ docker build -t itisgood/msg-api:v0.0.3 . --no-cache=true Sending build context to Docker daemon 5.12kB Step 1/8 : FROM node:latest ---> 2d840844f8e7 Step 2/8 : RUN mkdir -p /usr/src/app ---> Using cache ---> 1c29cda3dcd8 Step 3/8 : WORKDIR /usr/src/app ...
$ docker push itisgood/msg-api:v0.0.3 The push refers to a repository [docker.io/linoxide/msg-api] c4477a160652: Pushed 32c1bac97782: Pushed 3d629e3d2e5a: Pushed ... v1: digest: sha256:dba64e7ff64561f4af866fbbb657555cad7621688c7f312975943f5baf89efa2 size: 2628
Теперь мы можем создать под нашего приложения NodeJS, приведенный ниже файл спецификации msg-api-pod.yaml
apiVersion: v1 kind: Pod metadata: name: k8s-msg-api labels: name: lbl-msg-api spec: containers: - name: msg-api image: itisgood/msg-api:v0.0.1 ports: - name: msg-api
Примените манифест:
$ kubectl create -f msg-api-pod.yaml pod/k8s-msg-api created
$ kubectl get pod NAME READY STATUS RESTARTS AGE k8s-msg-api 1/1 Running 0 22s k8s-mysql 1/1 Running 0 1h
$ kubectl expose pod k8s-msg-api --port=8080 --name=k8s-srv-msg-api --type=NodePort service/k8s-srv-msg-api exposed
Получение данных из базы данных mysql с использованием nodejs api
На этом уровне мне нужно указать на некоторые важные вещи, чтобы понять все части, давайте сначала подведем итоги того, что мы уже сделали.
Пока мы создали под MySQL и представили его через службу, чтобы сделать его доступным для других подов.
Во-вторых, мы создали образец приложения nodejs, чтобы использовать его для обращения к поду MySQL; аналогично, чтобы получить доступ к API обмена сообщениями, нам нужно предоставить его через службу, я надеюсь, что до этого все ясно!
Теперь вопрос в том, как мы можем вызвать наш API обмена сообщениями извне нашего кластера в основном minikube?
Для этого нам нужен IP-адрес нашего узла, поскольку я использую minikube, который создает только один узел, поэтому IP-адрес разрешен, это сам IP-адрес minikube, просто запустите:
$ minikube ip 192.168.99.100
А что с портом?
Давайте опишем нашу службу API обмена сообщениями, чтобы убедиться в этом:
$ kubectl describe service k8s-srv-msg-api Name: k8s-srv-msg-api Namespace: default Labels: name=lbl-msg-api Selector: name=lbl-msg-api Type: NodePort IP: 10.0.0.170 Port: <unset> 8080/TCP NodePort: <unset> 30887/TCP Endpoints: 172.17.0.6:8080 Session Affinity: None No events.
Итак, у нас есть порт, который является портом нашей службы обмена сообщениями.
NodePort – это порт, на котором предоставленная служба доступна, то есть служба доступна на NodeIP:NodePort
Давайте попробуем:
$ curl 192.168.99.100:30887/ping hello there! I m up and running!% $ curl 192.168.99.100:30887/msg-api/all []%
Очень хорошо, пока мы можем попасть в нашу базу данных MySQL, давайте вставим некоторые данные в нашу базу данных с помощью терминала.
$ kubectl exec k8s-mysql -it -- bash root@k8s-mysql:/# mysql --user=root --password=$MYSQL_ROOT_PASSWORD mysql: [Warning] Using a password on the command line interface can be insecure. ... mysql> use k8smysqldb; 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; +----------------------+ | Tables_in_k8smysqldb | +----------------------+ | messages | +----------------------+ 1 row in set (0.01 sec) mysql> insert into messages(text) values ('this is the first msg!'); Query OK, 1 row affected (0.01 sec) mysql> insert into messages(text) values ('this is the second msg!'); Query OK, 1 row affected (0.01 sec)
Давайте получим эти данные через наш API nodejs с помощью curl:
$ curl 192.168.99.100:30887/msg-api/all [{"id":1,"text":"this is the first msg!"},{"id":2,"text":"this is the second msg!"}]%
Заключение
Контейнеризация базы данных MySQL и запуск СУБД в кластере Kubernetes дает команде DevOps множество преимуществ, таких как переносимость между средами, упрощение запуска/остановки и обновления, а также лучшая безопасность благодаря изолированности служб.