"Нові Билини". Їмо слона частинами

"Нові Билини". Їмо слона частинами

У цій статті я налаштовуватиму робоче оточення для розробки гри «Билини», а також виконаю розбиття самої гри на частини, придатні для використання в OpenFaaS. Всі маніпуляції робитиму на Linux, Kubernetes розгортатиму в minikube з використанням VirtualBox. У моїй робочій машині 2 процесорні ядра і 12гб оперативної пам'яті, як системний диск я застосовую SSD. Як основна система для розробки буду використовувати debian 8, з встановленими пакетами emacs, sudo, git і virtualbox, все інше встановлю шляхом завантаження з GitHub та інших джерел. Ці програми будемо встановлювати в /usr/local/bin, якщо не вказано інше. Почнемо!

Підготовка робочого оточення

Установка Go

Слідуємо інструкціям з офіційного сайту:

$ curl -L0 https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz -o go.tar.gz
$ sudo tar -C /usr/local -xzf go.tar.gz
$ echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile

Перевіряємо працездатність:

$ mkdir -p ~/go/src/hello && cd ~/go/src/hello
$ echo 'package main

import "fmt"

func main() {
fmt.Printf("hello, worldn")
}' > hello.go
$ go build
$ ./hello
hello, world

Установка faas-cli

Слідуємо інструкціям з офіційного сайту:

$ curl -sSL https://cli.openfaas.com | sudo -E sh
x86_64
Downloading package https://github.com/openfaas/faas-cli/releases/download/0.11.3/faas-cli as /tmp/faas-cli
Download complete.

Running with sufficient permissions to attempt to move faas-cli to /usr/local/bin
New version of faas-cli installed to /usr/local/bin
Creating alias 'faas' for 'faas-cli'.
  ___                   _____           ____
 / _  _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_  / _  '_ | |_ / _` |/ _` ___ 
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 ___/| .__/ ___|_| |_|_|  __,_|__,_|____/
      |_|

CLI:
 commit:  73004c23e5a4d3fdb7352f953247473477477a64
 version: 0.11.3

Додатково можна підключити роботу bash-completion:

faas-cli completion --shell bash | sudo tee /etc/bash_completion.d/faas-cli

Встановлення та налаштування Kubernetes

Для розробки достатньо minikube, так що встановимо його і kubelet в /usr/local/bin, для встановлення додатків також встановимо helm:

$ curl https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 -o minikube && chmod +x minikube && sudo mv minikube /usr/local/bin/
$ curl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl -o kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
$ curl https://get.helm.sh/helm-v3.0.2-linux-amd64.tar.gz | tar -xzvf - linux-amd64/helm --strip-components=1; sudo mv helm /usr/local/bin

Запускаємо minikube:

$ minikube start
  minikube v1.6.2 on Debian 8.11
  Automatically selected the 'virtualbox' driver (alternates: [])
  Downloading VM boot image ...
    > minikube-v1.6.0.iso.sha256: 65 B / 65 B [--------------] 100.00% ? p/s 0s
    > minikube-v1.6.0.iso: 150.93 MiB / 150.93 MiB [-] 100.00% 5.67 MiB p/s 27s
  Creating virtualbox VM (CPUs=2, Memory=8192MB, Disk=20000MB) ...
  Preparing Kubernetes v1.17.0 on Docker '19.03.5' ...
  Downloading kubeadm v1.17.0
  Downloading kubelet v1.17.0
  Pulling images ...
  Launching Kubernetes ...  Waiting for cluster to come online ...
  Done! kubectl is now configured to use "minikube"

перевіряємо:

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE
kube-system   coredns-6955765f44-knlcb           1/1     Running   0          29m
kube-system   coredns-6955765f44-t9cpn           1/1     Running   0          29m
kube-system   etcd-minikube                      1/1     Running   0          28m
kube-system   kube-addon-manager-minikube        1/1     Running   0          28m
kube-system   kube-apiserver-minikube            1/1     Running   0          28m
kube-system   kube-controller-manager-minikube   1/1     Running   0          28m
kube-system   kube-proxy-hv2wc                   1/1     Running   0          29m
kube-system   kube-scheduler-minikube            1/1     Running   0          28m
kube-system   storage-provisioner                1/1     Running   1          29m

Встановлення OpenFaaS

Розробники рекомендують створити 2 namespace для роботи:

$ kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/namespaces.yml
namespace/openfaas created
namespace/openfaas-fn created

Додаємо репозиторій для helm:

$ helm repo add openfaas https://openfaas.github.io/faas-netes/
"openfaas" has been added to your repositories

У чарті є можливість задати пароль перед встановленням, скористаємося нею та збережемо дані доступу у вигляді секрету k8s:

$ PASSWORD=verysecurerandompasswordstring
$ kubectl -n openfaas create secret generic basic-auth --from-literal=basic-auth-user=admin --from-literal=basic-auth-password="$PASSWORD"
secret/basic-auth created

Виконуємо розгортання:

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "openfaas" chart repository
Update Complete.  Happy Helming!
$ helm upgrade openfaas --install openfaas/openfaas --namespace openfaas --set functionNamespace=openfaas-fn --set generateBasicAuth=false
Release "openfaas" does not exist. Installing it now.
NAME: openfaas
LAST DEPLOYED: Fri Dec 25 10:28:22 2019
NAMESPACE: openfaas
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
To verify that openfaas has started, run:

  kubectl -n openfaas get deployments -l "release=openfaas, app=openfaas"

Через деякий час запускаємо запропоновану команду:

$ kubectl -n openfaas get deployments -l "release=openfaas, app=openfaas"
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
alertmanager        1/1     1            1           114s
basic-auth-plugin   1/1     1            1           114s
faas-idler          1/1     1            1           114s
gateway             1/1     1            1           114s
nats                1/1     1            1           114s
prometheus          1/1     1            1           114s
queue-worker        1/1     1            1           114s

Перевіряємо працездатність:

$ kubectl rollout status -n openfaas deploy/gateway
deployment "gateway" successfully rolled out
$ kubectl port-forward -n openfaas svc/gateway 8080:8080 &
[1] 6985
Forwarding from 127.0.0.1:8080 -> 8080
$ echo -n $PASSWORD | faas-cli login --username admin --password-stdin
Calling the OpenFaaS server to validate the credentials...
Handling connection for 8080
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.
credentials saved for admin http://127.0.0.1:8080
$ faas-cli list
Function                        Invocations     Replicas

Установка Mongodb

Ставимо все з використанням helm:

$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
"stable" has been added to your repositories
$ helm install stable/mongodb --generate-name
NAME: mongodb-1577466908
LAST DEPLOYED: Fri Dec 25 11:15:11 2019
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

MongoDB can be accessed via port 27017 on the following DNS name from within your cluster:

    mongodb-1577466908.default.svc.cluster.local

To get the root password run:

    export MONGODB_ROOT_PASSWORD=$(kubectl get secret --namespace default mongodb-1577466908 -o jsonpath="{.data.mongodb-root-password}" | base64 --decode)

To connect to your database run the following command:

    kubectl run --namespace default mongodb-1577466908-client --rm --tty -i --restart='Never' --image bitnami/mongodb --command -- mongo admin --host mongodb-1577466908 --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD

To connect to your database from outside the cluster execute the following commands:

    kubectl port-forward --namespace default svc/mongodb-1577466908 27017:27017 &
    mongo --host 127.0.0.1 --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD

перевіряємо:

kubectl run --namespace default mongodb-1577466908-client --rm --tty -i --restart='Never' --image bitnami/mongodb --command -- mongo admin --host mongodb-1577466908 --authenticationDatabase admin -u root -p $(kubectl get secret --namespace default mongodb-1577466908 -o jsonpath="{.data.mongodb-root-password}" | base64 --decode)
If you don't see a command prompt, try pressing enter.

> db.version();
4.0.14

Тиснемо ctrl+D для виходу з контейнера.

Налаштування emacs

В принципі, все було вже налаштоване цієї статті, Так що не буду детально розписувати.

Розбиття гри на функції

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

Реєстрація

На вході цієї функції – JSON з ігровим псевдонімом та паролем. При виклику цієї функції виконується перевірка відсутності цього псевдоніма у базі даних, при успішній перевірці – вставка псевдоніма та хеша пароля у базу. Реєстрація необхідна для активної участі у грі.

Вхід

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

Перегляд списку ігор

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

створення гри

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

Приєднання до гри

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

Перегляд подій гри

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

Відправлення події гри

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

Статистика гри

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

Функції, що періодично запускаються

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

Ще одне періодичне завдання — примусове перемикання режиму гри з ночі на день і назад для ігор, які цього не відбулися під час ходу (наприклад, гравець, якому треба відреагувати на ігрову подію, не надіслав свого рішення з будь-яких причин).

Анонс

  • Запровадження
  • Установка оточення для розробки, розбиття задач на функції
  • Роботи над backend
  • Роботи над frontend
  • Налаштування CICD, організація тестування
  • Запуск пробного сеансу гри
  • Підсумки

Джерело: habr.com

Додати коментар або відгук