add app, add nfs operator

This commit is contained in:
Vassiliy Yegorov
2021-05-20 14:20:41 +07:00
parent 79f0275027
commit 1b42b9592f
35 changed files with 983 additions and 24 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.env
.idea
.DS_Store

3
App/docker/.env.axample Normal file
View File

@@ -0,0 +1,3 @@
MARIADB_USER=restuser
MARIADB_PASSWORD=
MARIADB_DATABASE=restdb

2
App/docker/db/Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM mariadb:10.6.0-focal
COPY users.sql /docker-entrypoint-initdb.d/

3
App/docker/db/build.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
docker build -t vasyakrg/php-db . && docker push vasyakrg/php-db

72
App/docker/db/users.sql Normal file
View File

@@ -0,0 +1,72 @@
-- phpMyAdmin SQL Dump
-- version 4.8.5
-- https://www.phpmyadmin.net/
--
-- Хост: 127.0.0.1:3306
-- Время создания: Дек 09 2019 г., 21:42
-- Версия сервера: 10.3.13-MariaDB
-- Версия PHP: 7.1.22
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- База данных: `test`
--
-- --------------------------------------------------------
--
-- Структура таблицы `users`
--
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`last_name` varchar(50) NOT NULL,
`pos` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Дамп данных таблицы `users`
--
INSERT INTO `users` (`id`, `name`, `last_name`, `pos`) VALUES
(1, 'Иван', 'Иванов', 'Менеджер'),
(2, 'Петр', 'Петров', 'Сисадмин'),
(3, 'Сара', 'Конор', 'Бухгалтер'),
(4, 'Федор', 'Федоров', 'Архитектор'),
(5, 'Алексей', 'Алексеев', 'Оператор'),
(6, 'Марина', 'Маринина', 'Менеджер'),
(7, 'Михаил', 'Михайлов', 'Директор'),
(8, 'Владислав', 'Валдаев', 'Водитель'),
(9, 'Валентина', 'Иванова', 'Художник'),
(10, 'Владислав', 'Валдаев', 'Водитель');
--
-- Индексы сохранённых таблиц
--
--
-- Индексы таблицы `users`
--
ALTER TABLE `users`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT для сохранённых таблиц
--
--
-- AUTO_INCREMENT для таблицы `users`
--
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

View File

@@ -1,12 +1,34 @@
version: '3.7'
services:
app:
build: ./php
container_name: myapp
ports:
- 80:80
networks:
app_net:
app:
image: vasyakrg/php-app
container_name: myapp
environment:
MARIADB_HOST: db
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
MARIADB_DATABASE: ${MARIADB_DATABASE}
ports:
- 80:80
networks:
app_net:
db:
image: vasyakrg/php-db
container_name: db
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_PASSWORD}
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
MARIADB_DATABASE: ${MARIADB_DATABASE}
volumes:
- db_volume:/var/lib/mysql
ports:
- 3306:3306
networks:
app_net:
volumes:
db_volume:
networks:
app_net:

View File

@@ -1,12 +1,15 @@
FROM php:7.4-apache-buster
MAINTAINER vasyakrg <vasyakrg@gmail.com>
RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y --no-install-recommends \
apt-transport-https \
curl \
wget \
git \
&& apt-get update && rm -rf /var/lib/apt/lists/*
libpq-dev \
&& docker-php-ext-install mysqli pdo_pgsql pdo_mysql \
&& apt-get update \
&& rm -rf /var/lib/apt/lists/*
RUN rm /etc/apache2/sites-enabled/*
COPY myapp.conf /etc/apache2/sites-available/myapp.conf

View File

@@ -0,0 +1,12 @@
<?php
$host=$_ENV['MARIADB_HOST'];
$db=$_ENV['MARIADB_DATABASE'];
$login=$_ENV['MARIADB_USER'];
$password=$_ENV['MARIADB_PASSWORD'];
try {
$pdo = new PDO("mysql:dbname=$db; host=$host", $login, $password);
} catch (PDOException $e) {
die($e->getMessage());
}

View File

@@ -0,0 +1,47 @@
<?php
include 'config.php';
$name = $_POST['name'];
$last_name = $_POST['last_name'];
$pos = $_POST['pos'];
// Create
if (isset($_POST['submit'])) {
$sql = ("INSERT INTO `users`(`name`, `last_name`, `pos`) VALUES(?,?,?)");
$query = $pdo->prepare($sql);
$query->execute([$name, $last_name, $pos]);
$success = '<div class="alert alert-success alert-dismissible fade show" role="alert">
<strong>Данные успешно отправлены!</strong> Вы можете закрыть это сообщение.
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>';
}
// Read
$sql = $pdo->prepare("SELECT * FROM `users`");
$sql->execute();
$result = $sql->fetchAll();
// Update
$edit_name = $_POST['edit_name'];
$edit_last_name = $_POST['edit_last_name'];
$edit_pos = $_POST['edit_pos'];
$get_id = $_GET['id'];
if (isset($_POST['edit-submit'])) {
$sqll = "UPDATE users SET name=?, last_name=?, pos=? WHERE id=?";
$querys = $pdo->prepare($sqll);
$querys->execute([$edit_name, $edit_last_name, $edit_pos, $get_id]);
header('Location: '. $_SERVER['HTTP_REFERER']);
}
// DELETE
if (isset($_POST['delete_submit'])) {
$sql = "DELETE FROM users WHERE id=?";
$query = $pdo->prepare($sql);
$query->execute([$get_id]);
header('Location: '. $_SERVER['HTTP_REFERER']);
}

View File

@@ -1,8 +1,83 @@
<html>
<head>
<title>Тестируем PHP</title>
</head>
<body>
<?php echo '<p>Привет, мир!</p>'; ?>
</body>
<?php
include 'func.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CRUD приложение на PHP</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col mt-1">
<?=$success ?>
<button class="btn btn-success mb-1" data-toggle="modal" data-target="#Modal"><i class="fa fa-user-plus"></i></button>
<table class="table shadow ">
<thead class="thead-dark">
<tr>
<th>№</th>
<th>Имя</th>
<th>Фамилия</th>
<th>Должность</th>
<th>Действие</th>
</tr>
<?php foreach ($result as $value) { ?>
<tr>
<td><?=$value['id'] ?></td>
<td><?=$value['name'] ?></td>
<td><?=$value['last_name'] ?></td>
<td><?=$value['pos'] ?></td>
<td>
<a href="?edit=<?=$value['id'] ?>" class="btn btn-success btn-sm" data-toggle="modal" data-target="#editModal<?=$value['id'] ?>"><i class="fa fa-edit"></i></a>
<a href="?delete=<?=$value['id'] ?>" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#deleteModal<?=$value['id'] ?>"><i class="fa fa-trash"></i></a>
<?php require 'modal.php'; ?>
</td>
</tr> <?php } ?>
</thead>
</table>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" tabindex="-1" role="dialog" id="Modal">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content shadow">
<div class="modal-header">
<h5 class="modal-title">Добавить пользователя</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="" method="post">
<div class="form-group">
<input type="text" class="form-control" name="name" value="" placeholder="Имя">
</div>
<div class="form-group">
<input type="text" class="form-control" name="last_name" value="" placeholder="Фамилия">
</div>
<div class="form-group">
<input type="text" class="form-control" name="pos" value="" placeholder="Должность">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Отмена</button>
<button type="submit" name="submit" class="btn btn-primary">Добавить</button>
</div>
</form>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script>
</body>
</html>

View File

@@ -0,0 +1,49 @@
<!-- Modal Edit-->
<div class="modal fade" id="editModal<?=$value['id'] ?>" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content shadow">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Редактировать запись <?=$value['id'] ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="?id=<?=$value['id'] ?>" method="post">
<div class="form-group">
<input type="text" class="form-control" name="edit_name" value="<?=$value['name'] ?>" placeholder="Имя">
</div>
<div class="form-group">
<input type="text" class="form-control" name="edit_last_name" value="<?=$value['last_name'] ?>" placeholder="Фамилия">
</div>
<div class="form-group">
<input type="text" class="form-control" name="edit_pos" value="<?=$value['pos'] ?>" placeholder="Должность">
</div>
<div class="modal-footer">
<button type="submit" name="edit-submit" class="btn btn-primary">Обновить</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- DELETE MODAL -->
<div class="modal fade" id="deleteModal<?=$value['id'] ?>" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content shadow">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Удалить запись № <?=$value['id'] ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Отмена</button>
<form action="?id=<?=$value['id'] ?>" method="post">
<button type="submit" name="delete_submit" class="btn btn-danger">Удалить</button>
</form>
</div>
</div>
</div>
</div>

View File

@@ -25,3 +25,62 @@ spec:
imagePullPolicy: Always
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myapp
labels:
app: myapp-psql
name: myapp-psql
spec:
replicas: 1
selector:
matchLabels:
app: myapp-psql
strategy:
type: Recreate
template:
metadata:
labels:
app: myapp-psql
spec:
hostname: myapp-psql-pod
restartPolicy: Always
containers:
- name: myapp-db
image: postgres:12-alpine
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: myapp-psql-secret
key: postgress-user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: myapp-psql-secret
key: postgress-password
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: myapp-psql-secret
key: postgress-dbname
volumeMounts:
- name: vol-myapp-postgres
mountPath: /var/lib/postgresql/data
subPath: data
- name: pgsql-tmpfs
mountPath: /run
- name: pgsql-tmpfs
mountPath: /tmp
volumes:
- name: vol-myapp-postgres
persistentVolumeClaim:
claimName: myapp-db-pvc
- name: pgsql-tmpfs
emptyDir:
medium: Memory

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: myapp-psql-secret
namespace: myapp
data:
postgress-user: cmVzdHVzZXI=
postgress-password: dkVIQ1ZuN0NndXdGd0ViZXQySEMxQQ==
postgress-dbname: cmVzdGRi
---

View File

@@ -11,3 +11,16 @@ spec:
selector:
app: myapp
---
apiVersion: v1
kind: Service
metadata:
name: app-postgress-service
spec:
type: NodePort
ports:
- name: myapp-postgress-port
port: 5432
selector:
app: myapp-psql
---

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-db-pvc
namespace: myapp
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: nfs-client
---

View File

@@ -22,4 +22,5 @@ kubectl -n cert-manager rollout status deploy/cert-manager
sleep 5
# Add ACME issuer - FIX email in file BEFORE!!!
kubectl apply -f certmanager/orc-letsencrypt-issuer.yaml

View File

@@ -6,24 +6,24 @@ ignore_docker_version: true
kubernetes_version: v1.19.9-rancher1-1
nodes:
- address: 65.21.148.66
internal_address: 10.0.0.3
- address: 65.21.177.5
# internal_address: 10.0.0.3
hostname_override: node1
user: root
labels:
worker: yes
location: nsk
role: [controlplane, worker, etcd]
- address: 65.21.146.162
internal_address: 10.0.0.2
- address: 65.21.177.4
# internal_address: 10.0.0.2
hostname_override: node2
user: root
labels:
worker: yes
location: nsk
role: [controlplane, worker, etcd]
- address: 65.21.149.204
internal_address: 10.0.0.4
- address: 65.21.177.3
# internal_address: 10.0.0.4
hostname_override: node3
user: root
labels:
@@ -49,7 +49,7 @@ services:
authentication:
strategy: x509
sans:
- "167.233.11.162"
- "95.217.170.205"
- "rke.k8s-nsk.tk"
dns:

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# From ALL k8s-nodes
apt install -y nfs-common && systemctl enable rpcbind && systemctl start rpcbind
# from Lens
kubectl create ns nfs-provisioner
# Check VALUES BEFORE !!!
helm upgrade --install nfs-provisioner -n nfs-provisioner nfs-provisioner

View File

@@ -0,0 +1,13 @@
apiVersion: v1
appVersion: 4.0.2
description: nfs-subdir-external-provisioner is an automatic provisioner that used your *already configured* NFS server, automatically creating Persistent Volumes.
name: nfs-subdir-external-provisioner
home: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
version: 4.0.7
kubeVersion: ">=1.9.0-0"
sources:
- https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
keywords:
- nfs
- storage
- provisioner

View File

@@ -0,0 +1,79 @@
# NFS Subdirectory External Provisioner Helm Chart
The [NFS subdir external provisioner](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner) is an automatic provisioner for Kubernetes that uses your *already configured* NFS server, automatically creating Persistent Volumes.
## TL;DR;
```console
$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=x.x.x.x \
--set nfs.path=/exported/path
```
## Introduction
This charts installs custom [storage class](https://kubernetes.io/docs/concepts/storage/storage-classes/) into a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. It also installs a [NFS client provisioner](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner) into the cluster which dynamically creates persistent volumes from single NFS share.
## Prerequisites
- Kubernetes >=1.9
- Existing NFS Share
## Installing the Chart
To install the chart with the release name `my-release`:
```console
$ helm install my-release nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=x.x.x.x \
--set nfs.path=/exported/path
```
The command deploys the given storage class in the default configuration. It can be used afterswards to provision persistent volumes. The [configuration](#configuration) section lists the parameters that can be configured during installation.
> **Tip**: List all releases using `helm list`
## Uninstalling the Chart
To uninstall/delete the `my-release` deployment:
```console
$ helm delete my-release
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
The following tables lists the configurable parameters of this chart and their default values.
| Parameter | Description | Default |
| ----------------------------------- | ----------------------------------------------------------- | ------------------------------------------------- |
| `replicaCount` | Number of provisioner instances to deployed | `1` |
| `strategyType` | Specifies the strategy used to replace old Pods by new ones | `Recreate` |
| `image.repository` | Provisioner image | `gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner` |
| `image.tag` | Version of provisioner image | `v4.0.2` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `storageClass.name` | Name of the storageClass | `nfs-client` |
| `storageClass.defaultClass` | Set as the default StorageClass | `false` |
| `storageClass.allowVolumeExpansion` | Allow expanding the volume | `true` |
| `storageClass.reclaimPolicy` | Method used to reclaim an obsoleted volume | `Delete` |
| `storageClass.provisionerName` | Name of the provisionerName | null |
| `storageClass.archiveOnDelete` | Archive PVC when deleting | `true` |
| `storageClass.onDelete` | Strategy on PVC deletion. Overrides `archiveOnDelete` when set to lowercase values `delete` or `retain` | null |
| `storageClass.pathPattern` | Specifies a template for the directory name | null |
| `storageClass.accessModes` | Set access mode for PV | `ReadWriteOnce` |
| `leaderElection.enabled` | Enables or disables leader election | `true` |
| `nfs.server` | Hostname of the NFS server (required) | null (ip or hostname) |
| `nfs.path` | Basepath of the mount point to be used | `/nfs-storage` |
| `nfs.mountOptions` | Mount options (e.g. 'nfsvers=3') | null |
| `resources` | Resources required (e.g. CPU, memory) | `{}` |
| `rbac.create` | Use Role-based Access Control | `true` |
| `podSecurityPolicy.enabled` | Create & use Pod Security Policy resources | `false` |
| `priorityClassName` | Set pod priorityClassName | null |
| `serviceAccount.create` | Should we create a ServiceAccount | `true` |
| `serviceAccount.name` | Name of the ServiceAccount to use | null |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `affinity` | Affinity settings | `{}` |
| `tolerations` | List of node taints to tolerate | `[]` |

View File

@@ -0,0 +1,5 @@
nfs:
server: 127.0.0.1
podSecurityPolicy:
enabled: true
buildMode: true

View File

@@ -0,0 +1,62 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "nfs-subdir-external-provisioner.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "nfs-subdir-external-provisioner.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "nfs-subdir-external-provisioner.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "nfs-subdir-external-provisioner.provisionerName" -}}
{{- if .Values.storageClass.provisionerName -}}
{{- printf .Values.storageClass.provisionerName -}}
{{- else -}}
cluster.local/{{ template "nfs-subdir-external-provisioner.fullname" . -}}
{{- end -}}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "nfs-subdir-external-provisioner.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "nfs-subdir-external-provisioner.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}
{{/*
Return the appropriate apiVersion for podSecurityPolicy.
*/}}
{{- define "podSecurityPolicy.apiVersion" -}}
{{- if semverCompare ">=1.10-0" .Capabilities.KubeVersion.GitVersion -}}
{{- print "policy/v1beta1" -}}
{{- else -}}
{{- print "extensions/v1beta1" -}}
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,30 @@
{{- if .Values.rbac.create }}
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ template "nfs-subdir-external-provisioner.fullname" . }}-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
{{- if .Values.podSecurityPolicy.enabled }}
- apiGroups: ['extensions']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: [{{ template "nfs-subdir-external-provisioner.fullname" . }}]
{{- end }}
{{- end }}

View File

@@ -0,0 +1,19 @@
{{- if .Values.rbac.create }}
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: run-{{ template "nfs-subdir-external-provisioner.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ template "nfs-subdir-external-provisioner.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: {{ template "nfs-subdir-external-provisioner.fullname" . }}-runner
apiGroup: rbac.authorization.k8s.io
{{- end }}

View File

@@ -0,0 +1,81 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "nfs-subdir-external-provisioner.fullname" . }}
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
strategy:
type: {{ .Values.strategyType }}
selector:
matchLabels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
release: {{ .Release.Name }}
template:
metadata:
annotations:
{{- if and (.Values.tolerations) (semverCompare "<1.6-0" .Capabilities.KubeVersion.GitVersion) }}
scheduler.alpha.kubernetes.io/tolerations: '{{ toJson .Values.tolerations }}'
{{- end }}
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
release: {{ .Release.Name }}
spec:
serviceAccountName: {{ template "nfs-subdir-external-provisioner.serviceAccountName" . }}
{{- if .Values.nodeSelector }}
nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
{{- end }}
{{- if .Values.affinity }}
affinity:
{{ toYaml .Values.affinity | indent 8 }}
{{- end }}
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName | quote }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets:
{{ toYaml .Values.imagePullSecrets | indent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: nfs-subdir-external-provisioner-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: {{ template "nfs-subdir-external-provisioner.provisionerName" . }}
- name: NFS_SERVER
value: {{ .Values.nfs.server }}
- name: NFS_PATH
value: {{ .Values.nfs.path }}
{{- if eq .Values.leaderElection.enabled false }}
- name: ENABLE_LEADER_ELECTION
value: "false"
{{- end }}
{{- with .Values.resources }}
resources:
{{ toYaml . | indent 12 }}
{{- end }}
volumes:
- name: nfs-subdir-external-provisioner-root
{{- if .Values.buildMode }}
emptyDir: {}
{{- else if .Values.nfs.mountOptions }}
persistentVolumeClaim:
claimName: pvc-{{ template "nfs-subdir-external-provisioner.fullname" . }}
{{- else }}
nfs:
server: {{ .Values.nfs.server }}
path: {{ .Values.nfs.path }}
{{- end }}
{{- if and (.Values.tolerations) (semverCompare "^1.6-0" .Capabilities.KubeVersion.GitVersion) }}
tolerations:
{{ toYaml .Values.tolerations | indent 6 }}
{{- end }}

View File

@@ -0,0 +1,25 @@
{{ if .Values.nfs.mountOptions -}}
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-{{ template "nfs-subdir-external-provisioner.fullname" . }}
labels:
nfs-subdir-external-provisioner: {{ template "nfs-subdir-external-provisioner.fullname" . }}
spec:
capacity:
storage: 10Mi
volumeMode: Filesystem
accessModes:
- {{ .Values.storageClass.accessModes }}
persistentVolumeReclaimPolicy: {{ .Values.storageClass.reclaimPolicy }}
storageClassName: ""
{{- if .Values.nfs.mountOptions }}
mountOptions:
{{- range .Values.nfs.mountOptions }}
- {{ . }}
{{- end }}
{{- end }}
nfs:
server: {{ .Values.nfs.server }}
path: {{ .Values.nfs.path }}
{{ end -}}

View File

@@ -0,0 +1,17 @@
{{ if .Values.nfs.mountOptions -}}
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-{{ template "nfs-subdir-external-provisioner.fullname" . }}
spec:
accessModes:
- {{ .Values.storageClass.accessModes }}
volumeMode: Filesystem
storageClassName: ""
selector:
matchLabels:
nfs-subdir-external-provisioner: {{ template "nfs-subdir-external-provisioner.fullname" . }}
resources:
requests:
storage: 10Mi
{{ end -}}

View File

@@ -0,0 +1,31 @@
{{- if .Values.podSecurityPolicy.enabled }}
apiVersion: {{ template "podSecurityPolicy.apiVersion" . }}
kind: PodSecurityPolicy
metadata:
name: {{ template "nfs-subdir-external-provisioner.fullname" . }}
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'secret'
- 'nfs'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
readOnlyRootFilesystem: false
{{- end }}

View File

@@ -0,0 +1,21 @@
{{- if .Values.rbac.create }}
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: leader-locking-{{ template "nfs-subdir-external-provisioner.fullname" . }}
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
{{- if .Values.podSecurityPolicy.enabled }}
- apiGroups: ['extensions']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: [{{ template "nfs-subdir-external-provisioner.fullname" . }}]
{{- end }}
{{- end }}

View File

@@ -0,0 +1,19 @@
{{- if .Values.rbac.create }}
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: leader-locking-{{ template "nfs-subdir-external-provisioner.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ template "nfs-subdir-external-provisioner.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: Role
name: leader-locking-{{ template "nfs-subdir-external-provisioner.fullname" . }}
apiGroup: rbac.authorization.k8s.io
{{- end }}

View File

@@ -0,0 +1,11 @@
{{ if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ template "nfs-subdir-external-provisioner.serviceAccountName" . }}
{{- end -}}

View File

@@ -0,0 +1,32 @@
{{ if .Values.storageClass.create -}}
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
labels:
app: {{ template "nfs-subdir-external-provisioner.name" . }}
chart: {{ template "nfs-subdir-external-provisioner.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ .Values.storageClass.name }}
{{- if .Values.storageClass.defaultClass }}
annotations:
storageclass.kubernetes.io/is-default-class: "true"
{{- end }}
provisioner: {{ template "nfs-subdir-external-provisioner.provisionerName" . }}
allowVolumeExpansion: {{ .Values.storageClass.allowVolumeExpansion }}
reclaimPolicy: {{ .Values.storageClass.reclaimPolicy }}
parameters:
archiveOnDelete: "{{ .Values.storageClass.archiveOnDelete }}"
{{- if .Values.storageClass.pathPattern }}
pathPattern: "{{ .Values.storageClass.pathPattern }}"
{{- end }}
{{- if .Values.storageClass.onDelete }}
onDelete: "{{ .Values.storageClass.onDelete }}"
{{- end }}
{{- if .Values.nfs.mountOptions }}
mountOptions:
{{- range .Values.nfs.mountOptions }}
- {{ . }}
{{- end }}
{{- end }}
{{ end -}}

View File

@@ -0,0 +1,87 @@
replicaCount: 1
strategyType: Recreate
image:
repository: gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner
tag: v4.0.2
pullPolicy: IfNotPresent
nfs:
server: 65.21.177.6
path: /mnt/data
mountOptions:
# For creating the StorageClass automatically:
storageClass:
create: true
# Set a provisioner name. If unset, a name will be generated.
# provisionerName:
# Set StorageClass as the default StorageClass
# Ignored if storageClass.create is false
defaultClass: true
# Set a StorageClass name
# Ignored if storageClass.create is false
name: nfs-client
# Allow volume to be expanded dynamically
allowVolumeExpansion: true
# Method used to reclaim an obsoleted volume
reclaimPolicy: Delete
# When set to false your PVs will not be archived by the provisioner upon deletion of the PVC.
archiveOnDelete: true
# If it exists and has 'delete' value, delete the directory. If it exists and has 'retain' value, save the directory.
# Overrides archiveOnDelete.
# Ignored if value not set.
onDelete:
# Specifies a template for creating a directory path via PVC metadata's such as labels, annotations, name or namespace.
# Ignored if value not set.
pathPattern:
# Set access mode - ReadWriteOnce, ReadOnlyMany or ReadWriteMany
accessModes: ReadWriteOnce
leaderElection:
# When set to false leader election will be disabled
enabled: true
## For RBAC support:
rbac:
# Specifies whether RBAC resources should be created
create: true
# If true, create & use Pod Security Policy resources
# https://kubernetes.io/docs/concepts/policy/pod-security-policy/
podSecurityPolicy:
enabled: false
## Set pod priorityClassName
# priorityClassName: ""
serviceAccount:
# Specifies whether a ServiceAccount should be created
create: true
# The name of the ServiceAccount to use.
# If not set and create is true, a name is generated using the fullname template
name:
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}

19
Cluster/nfs/nfs-server.sh Normal file
View File

@@ -0,0 +1,19 @@
#!/bin/bash
# ubuntu 20.04
NODE1=65.21.177.5
NODE2=65.21.177.4
NODE3=65.21.177.3
FOLDER=/mnt/data
apt update && apt install -y nfs-kernel-server
mkdir -p $FOLDER
chmod 777 -R $FOLDER
chown nobody:nogroup -R $FOLDER
echo "$FOLDER ${NODE1}/24(rw,sync,no_subtree_check,no_root_squash) ${NODE2}/24(rw,sync,no_subtree_check,no_root_squash) ${NODE3}/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
systemctl restart nfs-kernel-server

View File

@@ -6,3 +6,14 @@
- rke - https://github.com/rancher/rke/releases/tag/v1.2.8
- helm - https://helm.sh/docs/intro/install/
- kubectl - https://kubernetes.io/ru/docs/tasks/tools/install-kubectl/
## Видео к курсу
- [видео]()
- [презентация](https://drive.google.com/file/d/1PWHZHNrwBRln2Ezk_JtWhl59hoivaOey/view?usp=sharing)
##### Автор
- **Vassiliy Yegorov** [vasyakrg](https://github.com/vasyakrg)
- [сайт](https://vk.com/realmanual)
- [youtube](https://youtube.com/realmanual)
- [группа в телеге](https://t.me/realmanual_group)