Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4ae5edc69 |
87
readme.md
@@ -2,89 +2,6 @@
|
|||||||
|
|
||||||
## Homeworks
|
## Homeworks
|
||||||
|
|
||||||
* [01.1 Введение в DevOps](/src/homework/01-intro/1.1)
|
* [1.1](/src/homework/1.1)
|
||||||
* [02.1 Системы контроля версий](/src/homework/02-git/2.1)
|
* [2.1 Системы контроля версий](/src/homework/2.1)
|
||||||
* [02.2 Основы Git](/src/homework/02-git/2.2)
|
|
||||||
* [02.3 Ветвления в Git](/src/homework/02-git/2.3)
|
|
||||||
* [02.4 Ветвления в Git](/src/homework/02-git/2.4)
|
|
||||||
* [03.1 Работа в терминале, лекция 1](/src/homework/03-sysadmin/3.1)
|
|
||||||
* [03.2 Работа в терминале, лекция 2](/src/homework/03-sysadmin/3.2)
|
|
||||||
* [03.3. Операционные системы, лекция 1](/src/homework/03-sysadmin/3.3)
|
|
||||||
* [03.4. Операционные системы, лекция 2](/src/homework/03-sysadmin/3.4)
|
|
||||||
* [03.5. Файловые системы](/src/homework/03-sysadmin/3.5)
|
|
||||||
* [03.6. Компьютерные сети, лекция 1](/src/homework/03-sysadmin/3.6)
|
|
||||||
* [03.7. Компьютерные сети, лекция 2](/src/homework/03-sysadmin/3.7)
|
|
||||||
* [03.8. Компьютерные сети, лекция 3](/src/homework/03-sysadmin/3.8)
|
|
||||||
* [03.9. Элементы безопасности информационных систем](/src/homework/03-sysadmin/3.9)
|
|
||||||
* [04.1. Командная оболочка Bash: Практические навыки](/src/homework/04-script/4.1)
|
|
||||||
* [04.2. Использование Python для решения типовых DevOps задач](/src/homework/04-script/4.2)
|
|
||||||
* [04.3. Языки разметки JSON и YAML](/src/homework/04-script/4.3)
|
|
||||||
* [05.1. Основы виртуализации](/src/homework/05-virtualization/5.1)
|
|
||||||
* [05.2. Применение принципов IaaC в работе с виртуальными машинами](/src/homework/05-virtualization/5.2)
|
|
||||||
* [05.3. Введение. Экосистема. Архитектура. Жизненный цикл Docker контейнера](/src/homework/05-virtualization/5.3)
|
|
||||||
* [05.4. Оркестрация группой Docker контейнеров на примере Docker Compose](/src/homework/05-virtualization/5.4)
|
|
||||||
* [05.5. Оркестрация кластером Docker контейнеров на примере Docker Swarm](/src/homework/05-virtualization/5.5)
|
|
||||||
* [06.1. Типы и структура СУБД](/src/homework/06-database/6.1)
|
|
||||||
* [06.2. SQL](/src/homework/06-database/6.2)
|
|
||||||
* [06.3. MySQL](/src/homework/06-database/6.3)
|
|
||||||
* [06.4. PostgreSQL](/src/homework/06-database/6.4)
|
|
||||||
* [06.5. Elasticsearch](/src/homework/06-database/6.5)
|
|
||||||
* [06.6. Troubleshooting](/src/homework/06-database/6.6)
|
|
||||||
* [07.1. Инфраструктура как код](/src/homework/07-terraform/7.1)
|
|
||||||
* [07.2. Облачные провайдеры и синтаксис Terraform](/src/homework/07-terraform/7.2)
|
|
||||||
* [07.3. Основы и принцип работы Terraform](/src/homework/07-terraform/7.3)
|
|
||||||
* [07.4. Средства командной работы над инфраструктурой](/src/homework/07-terraform/7.4)
|
|
||||||
* [07.5. Основы golang](/src/homework/07-terraform/7.5)
|
|
||||||
* [07.6. Написание собственных провайдеров для Terraform](/src/homework/07-terraform/7.6)
|
|
||||||
* [08.1. Введение в Ansible](/src/homework/08-ansible/8.1)
|
|
||||||
* [08.2. Работа с Playbook](/src/homework/08-ansible/8.2)
|
|
||||||
* [08.3. Использование Yandex Cloud](/src/homework/08-ansible/8.3)
|
|
||||||
* [08.4. Работа с Roles](/src/homework/08-ansible/8.4)
|
|
||||||
* [08.5. Тестирование Roles](/src/homework/08-ansible/8.5)
|
|
||||||
* [08.6. Создание собственных modules](/src/homework/08-ansible/8.6)
|
|
||||||
* [09.1. Жизненный цикл ПО](/src/homework/09-ci/9.1)
|
|
||||||
* [09.3. CI\CD](/src/homework/09-ci/9.3)
|
|
||||||
* [09.4. Jenkins](/src/homework/09-ci/9.4)
|
|
||||||
* [09.5. Teamcity](/src/homework/09-ci/9.5)
|
|
||||||
* [09.6. Gitlab](/src/homework/09-ci/9.6)
|
|
||||||
* [10.1. Зачем и что нужно мониторить](/src/homework/10-monitoring/10.1)
|
|
||||||
* [10.2. Системы мониторинга](/src/homework/10-monitoring/10.2)
|
|
||||||
* [10.3. Grafana](/src/homework/10-monitoring/10.3)
|
|
||||||
* [10.4. ELK](/src/homework/10-monitoring/10.4)
|
|
||||||
* [10.5. Sentry](/src/homework/10-monitoring/10.5)
|
|
||||||
* [10.6. Инцидент-менеджмент](/src/homework/10-monitoring/10.6)
|
|
||||||
* [11.1. Введение в микросервисы](/src/homework/11-microservices/11.1)
|
|
||||||
* [11.2. Микросервисы: принципы](/src/homework/11-microservices/11.2)
|
|
||||||
* [11.3. Микросервисы: подходы](/src/homework/11-microservices/11.3)
|
|
||||||
* [11.4. Микросервисы: масштабирование](/src/homework/11-microservices/11.4)
|
|
||||||
* [12.1. Компоненты Kubernetes](/src/homework/12-kubernetes/12.1)
|
|
||||||
* [12.2. Команды для работы с Kubernetes](/src/homework/12-kubernetes/12.2)
|
|
||||||
* [12.3. Развертывание кластера на собственных серверах, лекция 1](/src/homework/12-kubernetes/12.3)
|
|
||||||
* [12.4. Развертывание кластера на собственных серверах, лекция 2](/src/homework/12-kubernetes/12.4)
|
|
||||||
* [12.5. Сетевые решения CNI](/src/homework/12-kubernetes/12.5)
|
|
||||||
* [13.1. Контейнеры, поды, deployment, statefulset, services, endpoints](/src/homework/13-kubernetes-config/13.1)
|
|
||||||
* [13.2. Разделы и монтирование](/src/homework/13-kubernetes-config/13.2)
|
|
||||||
* [13.3. Работа с kubectl](/src/homework/13-kubernetes-config/13.3)
|
|
||||||
* [13.4. Инструменты для упрощения написания конфигурационных файлов. Helm и Jsonnet](/src/homework/13-kubernetes-config/13.4)
|
|
||||||
* [13.5. Поддержка нескольких окружений на примере Qbec](/src/homework/13-kubernetes-config/13.5)
|
|
||||||
* [14.1. Создание и использование секретов](/src/homework/14-kubernetes-security/14.1)
|
|
||||||
* [14.2. Синхронизация секретов с внешними сервисами. Vault](/src/homework/14-kubernetes-security/14.2)
|
|
||||||
* [14.3. Карты конфигураций](/src/homework/14-kubernetes-security/14.3)
|
|
||||||
* [14.4. Сервис-аккаунты](/src/homework/14-kubernetes-security/14.4)
|
|
||||||
* [14.5. SecurityContext, NetworkPolicies](/src/homework/14-kubernetes-security/14.5)
|
|
||||||
* [15.1. Организация сети](/src/homework/15-cloud-providers/15.1)
|
|
||||||
* [15.2. Вычислительные мощности. Балансировщики нагрузки](/src/homework/15-cloud-providers/15.2)
|
|
||||||
* [15.3. Безопасность в облачных провайдерах](/src/homework/15-cloud-providers/15.3)
|
|
||||||
|
|
||||||
## Graduate work
|
|
||||||
|
|
||||||
[**Дипломная работа**](/src/graduate_work)
|
|
||||||
|
|
||||||
## Related repositories
|
|
||||||
|
|
||||||
* [Dannecron/netology-devops-ansible-lighthouse](https://github.com/Dannecron/netology-devops-ansible-lighthouse)
|
|
||||||
* [Dannecron/netology-devops-ansible-yandex-cloud-cvl](https://github.com/Dannecron/netology-devops-ansible-yandex-cloud-cvl)
|
|
||||||
* [Dannecron/netology-devops-ansible-vector](https://github.com/Dannecron/netology-devops-ansible-vector)
|
|
||||||
* [Dannecron/netology-devops-teamcity-example](https://github.com/Dannecron/netology-devops-teamcity-example)
|
|
||||||
* [Dannecron/netology-devops-gitlab](https://github.com/Dannecron/netology-devops-gitlab)
|
|
||||||
* [Dannecron/netology-devops-gw-infra](https://github.com/Dannecron/netology-devops-gw-infra)
|
|
||||||
|
|||||||
@@ -1,316 +0,0 @@
|
|||||||
## Дипломная работа
|
|
||||||
|
|
||||||
Выполнение дипломной работы курса netology DevOps инженер. Оригинал задания доступен по [ссылке](https://github.com/netology-code/devops-diplom-yandexcloud/blob/main/README.md).
|
|
||||||
|
|
||||||
Весь код, выполненный по ходу выполнения работы находится в репозиториях на github:
|
|
||||||
* terraform/ansible/helm: [Dannecron/netology-devops-gw-infra](https://github.com/Dannecron/netology-devops-gw-infra)
|
|
||||||
* приложение: [Dannecron/parcel-example-neko](https://github.com/Dannecron/parcel-example-neko)
|
|
||||||
|
|
||||||
### Создание облачной инфраструктуры
|
|
||||||
|
|
||||||
[Задание](./tasks.md#создание-облачной-инфраструктуры).
|
|
||||||
|
|
||||||
#### Предварительная настройка
|
|
||||||
|
|
||||||
Данный параграф описывает выполнения шагов 1-3 из задания.
|
|
||||||
|
|
||||||
Предварительная настройка включает в себя несколько шагов, необходимых для последующей работы с `yandex.cloud` через `terraform`.
|
|
||||||
Данные шаги выполняются в ручную, но могут быть автоматизированы, например, через `ansible`.
|
|
||||||
|
|
||||||
1. Установить утилиту [yc](https://cloud.yandex.ru/docs/cli/quickstart) и подключится к облаку.
|
|
||||||
2. Создание сервисного аккаунта с ролью `editor` на дефолтной директории облака:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
yc iam service-account create --name terraform-acc
|
|
||||||
yc resource-manager folder add-access-binding --name default --role editor --subject "serviceAccount:<accId>"
|
|
||||||
```
|
|
||||||
|
|
||||||
где `<accId>` - это уникальный идентификатор нового сервисного аккаунта.
|
|
||||||
Затем нужно получить ключ доступа для данного сервисного аккаунта:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
yc iam access-key create --service-account-name terraform-acc --format=json
|
|
||||||
```
|
|
||||||
3. Создание s3-bucket для хранения состояния `terraform`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
yc storage bucket create --name=dnc-netology-tf-state
|
|
||||||
```
|
|
||||||
|
|
||||||
Следующий шаг - инициализация terraform и создание нового workspace. Для инициализации используется команда:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
terraform init \
|
|
||||||
-backend-config="bucket=dnc-netology-tf-state" \
|
|
||||||
-backend-config="access_key=<service_account_key_id>" \
|
|
||||||
-backend-config="secret_key=<service_account_secret_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
где `<service_account_key_id>` и `<service_account_secret_key>` данные полученные на шаге получения ключа доступа для сервисного аккаунта.
|
|
||||||
|
|
||||||
Создание и переключение на новый workspace с названием `prod`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
terraform workspace new prod
|
|
||||||
```
|
|
||||||
|
|
||||||
Для упрощения процесса был создан ansible-playbook [terraform_init.yml](https://github.com/Dannecron/netology-devops-gw-infra/blob/main/terraform_init.yml).
|
|
||||||
Чтобы усилить безопасность некоторые переменные были зашифрованы через `ansible-vault`.
|
|
||||||
Таким образом, для запуска достаточно выполнить команду
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook --ask-vault-pass -i ansible/terraform_init terraform_init.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
После выполнения данных шагов можно приступать непосредственно к разворачиванию инфрастуктуры через команды terraform.
|
|
||||||
|
|
||||||
#### Создание VPC и подсетей через terraform
|
|
||||||
|
|
||||||
Для создания VPC и двух подсетей будет использована следующая конфигурация:
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
resource "yandex_vpc_network" "netology-gw-network" {
|
|
||||||
name = "netology-gw-network"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "yandex_vpc_subnet" "netology-gw-subnet-a" {
|
|
||||||
name = "netology-gw-subnet-a"
|
|
||||||
zone = "ru-central1-a"
|
|
||||||
network_id = yandex_vpc_network.netology-gw-network.id
|
|
||||||
v4_cidr_blocks = ["192.168.10.0/24"]
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "yandex_vpc_subnet" "netology-gw-subnet-b" {
|
|
||||||
name = "netology-gw-subnet-b"
|
|
||||||
zone = "ru-central1-b"
|
|
||||||
network_id = yandex_vpc_network.netology-gw-network.id
|
|
||||||
v4_cidr_blocks = ["192.168.15.0/24"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем нужно последовательно выполнить команды для проверки применения конфигурации в облаке (выполняется из [директории terraform](https://github.com/Dannecron/netology-devops-gw-infra/tree/main/terraform)):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
terraform plan
|
|
||||||
terraform apply
|
|
||||||
terraform destroy
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Создание Kubernetes кластера
|
|
||||||
|
|
||||||
[Задание](./tasks.md#создание-Kubernetes-кластера).
|
|
||||||
|
|
||||||
Конфигурация машин будет одинаковая, поэтому terraform-конфигурация будет выглядеть следующим образом:
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
resource "random_shuffle" "netology-gw-subnet-random" {
|
|
||||||
input = [yandex_vpc_subnet.netology-gw-subnet-a.id, yandex_vpc_subnet.netology-gw-subnet-b.id]
|
|
||||||
result_count = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "yandex_compute_instance" "k8s-cluster" {
|
|
||||||
for_each = toset(["control", "node01", "node2"])
|
|
||||||
|
|
||||||
name = each.key
|
|
||||||
|
|
||||||
resources {
|
|
||||||
cores = 2
|
|
||||||
memory = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_disk {
|
|
||||||
initialize_params {
|
|
||||||
image_id = "fd8kdq6d0p8sij7h5qe3" # ubuntu-20-04-lts-v20220822
|
|
||||||
size = "20"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
network_interface {
|
|
||||||
subnet_id = random_shuffle.netology-gw-subnet-random.result[0]
|
|
||||||
nat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata = {
|
|
||||||
ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output "cluster_ips" {
|
|
||||||
value = {
|
|
||||||
internal = values(yandex_compute_instance.k8s-cluster)[*].network_interface.0.ip_address
|
|
||||||
external = values(yandex_compute_instance.k8s-cluster)[*].network_interface.0.nat_ip_address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Для распределения по разным зонам доступности использован ресурс `random_shuffle`.
|
|
||||||
|
|
||||||
После деплоя инфраструктуры необходимо скачать репозиторий [kubespray](https://github.com/kubernetes-sigs/kubespray),
|
|
||||||
сформировать inventory-директорию, содержащую сам `inventory.ini` с данными о виртуальных машинах и `group_vars`.
|
|
||||||
|
|
||||||
После данного шага достаточно запустить ansible-playbook `cluster.yml` с переданным inventory:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook -i ansible/kubespray/inventory.ini vendor/kubespray/cluster.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
Когда установка кластера закончится необходимо с control-node взять файл `/etc/kubernetes/admin.conf`,
|
|
||||||
положить его локально по пути `~/.kube/conf` и изменить ip-адрес кластера на ip-адрес самой control-node.
|
|
||||||
Этого будет достаточно, чтобы подключится к кластеру через утилиту `kubectl`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get pods --all-namespaces
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
|
||||||
NAMESPACE NAME READY STATUS RESTARTS AGE
|
|
||||||
kube-system calico-kube-controllers-7f679c5d6f-kfmkz 1/1 Running 0 49m
|
|
||||||
kube-system calico-node-8v2d9 1/1 Running 0 50m
|
|
||||||
kube-system calico-node-rrbcv 1/1 Running 0 50m
|
|
||||||
kube-system calico-node-w67gl 1/1 Running 0 50m
|
|
||||||
kube-system coredns-5867d9544c-7n4qz 1/1 Running 0 47m
|
|
||||||
kube-system coredns-5867d9544c-rfbxs 1/1 Running 0 47m
|
|
||||||
kube-system dns-autoscaler-59b8867c86-2rqdd 1/1 Running 0 47m
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Создание тестового приложения
|
|
||||||
|
|
||||||
[Задание](./tasks.md#создание-тестового-приложения).
|
|
||||||
|
|
||||||
Для данного задания будет использован [репозиторий тестового приложения](https://github.com/Dannecron/parcel-example-neko)
|
|
||||||
в котором расположено небольшое тестовое приложение на JS. Данное приложение запаковывается в образ с nginx.
|
|
||||||
Dockerfile расположен внутри репозитория ([file](https://github.com/Dannecron/parcel-example-neko/blob/main/Dockerfile))
|
|
||||||
|
|
||||||
Docker-образ доступен на [Docker Hub](https://hub.docker.com/r/dannecron/parcel-example-neko).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Подготовка системы мониторинга и деплой приложения
|
|
||||||
|
|
||||||
[Задание](./tasks.md#подготовка-системы-мониторинга-и-деплой-приложения).
|
|
||||||
|
|
||||||
Перед деплоем необходимо было активировать nginx-ingress-controller в конфигурации kubespray.
|
|
||||||
Для этого в файле [ansible/kubespray/group_vars/k8s_cluster/addons.yml](https://github.com/Dannecron/netology-devops-gw-infra/blob/main/ansible/kubespray/group_vars/k8s_cluster/addons.yml) изменено значение
|
|
||||||
по ключам `ingress_nginx_enabled` и `ingress_nginx_host_network` на `true`.
|
|
||||||
|
|
||||||
Для деплоя всех необходимых сервисов было создано 2 helm-чарта и использован готовый helm-чарт:
|
|
||||||
* чарт [k8s/helm/atlantis](https://github.com/Dannecron/netology-devops-gw-infra/tree/main/k8s/helm/atlantis) для упрощённого деплоя `atlantis`
|
|
||||||
* чарт [k8s/helm/simple-app](https://github.com/Dannecron/netology-devops-gw-infra/tree/main/k8s/helm/simple-app) для деплоя приложения
|
|
||||||
* готовый чарт [kube-prometheus-stack](https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack)
|
|
||||||
и конфигурация для него [k8s/helm/kube-prometheus-stack/values.yml](https://github.com/Dannecron/netology-devops-gw-infra/blob/main/k8s/helm/kube-prometheus-stack/values.yml)
|
|
||||||
|
|
||||||
Применение изменений производится командами `helm`:
|
|
||||||
* `helm install` - первый деплой чарта
|
|
||||||
* `helm upgrade` - повторный деплой чарта для применения изменений
|
|
||||||
* `helm upgrade -i` - установка или обновление чарта
|
|
||||||
|
|
||||||
Конкретные команды, которые были выполнены:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
|
||||||
helm install monitoring prometheus-community/kube-prometheus-stack -f k8s/helm/kube-prometheus-stack/values.yml
|
|
||||||
helm install simple-app k8s/helm/simple-app
|
|
||||||
helm install --set "config.github.user=<access_token>" --set "config.github.token=<token_secret>" --set "config.github.secret=<webhook_secret>" atlantis k8s/helm/atlantis
|
|
||||||
```
|
|
||||||
|
|
||||||
где `<access_token>`, `<token_secret>` - это данные персонального access-токена, созданного на github,
|
|
||||||
а `<webhook_secret>` - строка, которая должна совпадать в конфигурации webhook и atlantis.
|
|
||||||
|
|
||||||
После выполнения сервисы стали доступны по следующим доменам:
|
|
||||||
* `http://grafana-gw.my.to` - grafana (логин `admin`, пароль `prom-operator`)
|
|
||||||
* `http://app-gw.my.to` - приложение
|
|
||||||
* `http://atlantis-gw.my.to/` - atlantis
|
|
||||||
|
|
||||||
_UPD_ atlantis был подключён к репозиторию, но не получается корректно настроить backend для terraform.
|
|
||||||
Особенно вызывает проблемы необходимость каждый день выпускать новый токен для сервисного аккаунта yandex.cloud.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Установка и настройка CI/CD
|
|
||||||
|
|
||||||
[Задание](./tasks.md#установка-и-настройка-CI/CD).
|
|
||||||
|
|
||||||
В качестве сервиса автоматизации сборки и развёртывания приложения был выбран [jenkins](https://www.jenkins.io/).
|
|
||||||
Для его деплоя создан helm-чарт [k8s/helm/jenkins](https://github.com/Dannecron/netology-devops-gw-infra/tree/main/k8s/helm/jenkins),
|
|
||||||
деплой которого производится стандартно:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
helm install --set "docker.dockerHubUser=<dockerHubUser>" --set "docker.dockerHubPassword=<dockerHubPassword>" jenkins k8s/helm/jenkins
|
|
||||||
```
|
|
||||||
|
|
||||||
где `<dockerHubUser>` и `<dockerHubPassword>` - данные авторизации в [hub.docker.com](https://hub.docker.com)
|
|
||||||
для возможности пушить образы в регистри.
|
|
||||||
|
|
||||||
После установки jenkins будет доступен по ip-адресу любой рабочей node кластера по пути `/jenkins` (например ` http://84.201.172.95/jenkins`).
|
|
||||||
Далее необходима первоначальная настройка сервиса в которую входят:
|
|
||||||
* авторизация в качестве начального администратора. Ключ доступа можно посмотреть в логах pod, например, командой:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl --namespace ci-cd logs jenkins-production-main-0
|
|
||||||
```
|
|
||||||
* установка первоначальных плагинов (можно выбрать рекомендованный вариант).
|
|
||||||
* создание дополнительного пользователя (можно пропустить).
|
|
||||||
* изменение конфигурации безопасности `Host Key Verification Strategy` на `Accept first connection`
|
|
||||||
* установка дополнительных плагинов:
|
|
||||||
* [Kubernetes](https://plugins.jenkins.io/kubernetes/) для возможности запускать jenkins-воркеры внутри k8s-кластера
|
|
||||||
* [Generic Webhook Trigger](https://plugins.jenkins.io/generic-webhook-trigger/) для возможности более гибко настраивать
|
|
||||||
поведение скриптов jenkins на github-webhooks.
|
|
||||||
* выставить значение 0 в настройке `Количество процессов-исполнителей` для мастер-ноды.
|
|
||||||
* в `Configure Clouds` добавить новую конфигурацию kubernetes. Адрес кластера и сертификат можно взять из локальной конфигурации `kubectl`.
|
|
||||||
|
|
||||||
После данных действий останется создать два проекта с типом `pipeline`:
|
|
||||||
* для сборки образов при каждом изменении кода в ветках. Скрипт для этого проекта находится в файле [jenkins/ref.jenkinsfile](https://github.com/Dannecron/netology-devops-gw-infra/blob/main/jenkins/ref.jenkinsfile)
|
|
||||||
* для сборки образов и деплое изменений при создании нового git-тэга. Скрипт для этого проекта находится в файле [jenkins/tag.jenkinsfile](https://github.com/Dannecron/netology-devops-gw-infra/blob/main/jenkins/tag.jenkinsfile)
|
|
||||||
|
|
||||||
Плагин `Generic Webhook Trigger`, который используется внутри данных скриптов, требует, чтобы сборка каждого проекта была запущена
|
|
||||||
хотя бы раз перед фактическим использованием. Это необходимо для применения конфигурации переменных для проекта.
|
|
||||||
|
|
||||||
Последним шагом будет настройка двух github-webhook в репозитории приложения [Dannecron/parcel-example-neko](https://github.com/Dannecron/parcel-example-neko).
|
|
||||||
Webhook для первого приложения должен инициироваться при каждом push в репозиторий (`Just the push event.`).
|
|
||||||
Webhook для второго приложения должен инициироваться только при создании тэга (`Branch or tag creation`, создание веток будет отфильтровано).
|
|
||||||
|
|
||||||
По такой логике были созданы следующие теги в [регистри](https://hub.docker.com/r/dannecron/parcel-example-neko/tags)
|
|
||||||
* `feature-1` - при создании новой git-ветки в репозитории.
|
|
||||||
* `0.1.0` - при создании нового тега. При этом в кластер была задеплоена соответствующая версия приложения. Это можно проверить, выполнив команды
|
|
||||||
|
|
||||||
```shell
|
|
||||||
helm list --selector "name=simple-app"
|
|
||||||
kubectl describe pod --show-events=false simple-app-production-application-7c777968c6-cndh2 | grep Image
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
|
||||||
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
|
|
||||||
simple-app default 3 2023-04-01 04:48:20.999406345 +0000 UTC deployed simple-app-0.1.0 latest
|
|
||||||
|
|
||||||
Image: dannecron/parcel-example-neko:0.1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Данные, необходимые для сдачи задания
|
|
||||||
|
|
||||||
1. Репозиторий с конфигурационными файлами Terraform: [Dannecron/netology-devops-gw-infra](https://github.com/Dannecron/netology-devops-gw-infra) директория `terraform`;
|
|
||||||
2. Пример pull request с комментариями созданными atlantis'ом: [github](https://github.com/Dannecron/netology-devops-gw-infra/pull/2);
|
|
||||||
3. Репозиторий с конфигурацией ansible, если был выбран способ создания Kubernetes кластера при помощи ansible:
|
|
||||||
[Dannecron/netology-devops-gw-infra](https://github.com/Dannecron/netology-devops-gw-infra) директория `ansible/kubespray`;
|
|
||||||
4. Репозиторий с Dockerfile тестового приложения и ссылка на собранный docker image:
|
|
||||||
* репозиторий тестового приложения: [Dannecron/parcel-example-neko](https://github.com/Dannecron/parcel-example-neko);
|
|
||||||
* docker image: [dannecron/parcel-example-neko](https://hub.docker.com/r/dannecron/parcel-example-neko);
|
|
||||||
5. Репозиторий с конфигурацией Kubernetes кластера: [Dannecron/netology-devops-gw-infra](https://github.com/Dannecron/netology-devops-gw-infra) директория `k8s`;
|
|
||||||
6. Ссылка на тестовое приложение и веб интерфейс Grafana с данными доступа:
|
|
||||||
* тестовое приложение: `http://app-gw.my.to`
|
|
||||||
* web-интерфейс grafana: `http://grafana-gw.my.to` (логин `admin`, пароль `prom-operator`)
|
|
||||||
|
|
||||||
### Допущения
|
|
||||||
|
|
||||||
Небольшой список допущений, которые были сделаны во время выполнения работы:
|
|
||||||
* Все ноды имеют внешний ip-адрес. В реальном проекте стоило сделать `Bastion host` для доступа по ssh до всех остальных нод,
|
|
||||||
а так же перенаправления трафика к кластеру.
|
|
||||||
* Создано несколько ansible-playbook под разные задачи. Возможно, стоило объединить всё в один playbook с подключением разных ролей.
|
|
||||||
* Helm-чарт для деплоя приложения никуда не опубликован, что усложняет работу с ним.
|
|
||||||
Таким образом, в дальнейшем стоит настроить хотя бы публикацию версии (архива) в качестве артефактов в релизах github.
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
## Цели
|
|
||||||
|
|
||||||
* [Цели](#цели)
|
|
||||||
* [Этапы выполнения](#этапы-выполнения)
|
|
||||||
* [Создание облачной инфраструктуры](#создание-облачной-инфраструктуры)
|
|
||||||
* [Создание Kubernetes кластера](#создание-Kubernetes-кластера)
|
|
||||||
* [Создание тестового приложения](#создание-тестового-приложения)
|
|
||||||
* [Подготовка cистемы мониторинга и деплой приложения](#подготовка-cистемы-мониторинга-и-деплой-приложения)
|
|
||||||
* [Установка и настройка CI/CD](#установка-и-настройка-CI/CD)
|
|
||||||
* [Что необходимо для сдачи задания?](#что-необходимо-для-сдачи-задания)
|
|
||||||
|
|
||||||
## Этапы выполнения
|
|
||||||
|
|
||||||
### Создание облачной инфраструктуры
|
|
||||||
|
|
||||||
Для начала необходимо подготовить облачную инфраструктуру в ЯО при помощи [Terraform](https://www.terraform.io/).
|
|
||||||
|
|
||||||
Особенности выполнения:
|
|
||||||
|
|
||||||
- Бюджет купона ограничен, что следует иметь в виду при проектировании инфраструктуры и использовании ресурсов;
|
|
||||||
- Следует использовать последнюю стабильную версию [Terraform](https://www.terraform.io/).
|
|
||||||
|
|
||||||
Предварительная подготовка к установке и запуску Kubernetes кластера.
|
|
||||||
|
|
||||||
1. Создайте сервисный аккаунт, который будет в дальнейшем использоваться Terraform для работы с инфраструктурой с необходимыми и достаточными правами. Не стоит использовать права суперпользователя
|
|
||||||
2. Подготовьте [backend](https://www.terraform.io/docs/language/settings/backends/index.html) для Terraform:
|
|
||||||
а. Рекомендуемый вариант: [Terraform Cloud](https://app.terraform.io/)
|
|
||||||
б. Альтернативный вариант: S3 bucket в созданном ЯО аккаунте
|
|
||||||
3. Настройте [workspaces](https://www.terraform.io/docs/language/state/workspaces.html)
|
|
||||||
а. Рекомендуемый вариант: создайте два workspace: *stage* и *prod*. В случае выбора этого варианта все последующие шаги должны учитывать факт существования нескольких workspace.
|
|
||||||
б. Альтернативный вариант: используйте один workspace, назвав его *stage*. Пожалуйста, не используйте workspace, создаваемый Terraform-ом по-умолчанию (*default*).
|
|
||||||
4. Создайте VPC с подсетями в разных зонах доступности.
|
|
||||||
5. Убедитесь, что теперь вы можете выполнить команды `terraform destroy` и `terraform apply` без дополнительных ручных действий.
|
|
||||||
6. В случае использования [Terraform Cloud](https://app.terraform.io/) в качестве [backend](https://www.terraform.io/docs/language/settings/backends/index.html) убедитесь, что применение изменений успешно проходит, используя web-интерфейс Terraform cloud.
|
|
||||||
|
|
||||||
Ожидаемые результаты:
|
|
||||||
|
|
||||||
1. Terraform сконфигурирован и создание инфраструктуры посредством Terraform возможно без дополнительных ручных действий.
|
|
||||||
2. Полученная конфигурация инфраструктуры является предварительной, поэтому в ходе дальнейшего выполнения задания возможны изменения.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Создание Kubernetes кластера
|
|
||||||
|
|
||||||
На этом этапе необходимо создать [Kubernetes](https://kubernetes.io/ru/docs/concepts/overview/what-is-kubernetes/) кластер на базе предварительно созданной инфраструктуры. Требуется обеспечить доступ к ресурсам из Интернета.
|
|
||||||
|
|
||||||
Это можно сделать двумя способами:
|
|
||||||
|
|
||||||
1. Рекомендуемый вариант: самостоятельная установка Kubernetes кластера.
|
|
||||||
а. При помощи Terraform подготовить как минимум 3 виртуальных машины Compute Cloud для создания Kubernetes-кластера. Тип виртуальной машины следует выбрать самостоятельно с учётом требовании к производительности и стоимости. Если в дальнейшем поймете, что необходимо сменить тип инстанса, используйте Terraform для внесения изменений.
|
|
||||||
б. Подготовить [ansible](https://www.ansible.com/) конфигурации, можно воспользоваться, например [Kubespray](https://kubernetes.io/docs/setup/production-environment/tools/kubespray/)
|
|
||||||
в. Задеплоить Kubernetes на подготовленные ранее инстансы, в случае нехватки каких-либо ресурсов вы всегда можете создать их при помощи Terraform.
|
|
||||||
2. Альтернативный вариант: воспользуйтесь сервисом [Yandex Managed Service for Kubernetes](https://cloud.yandex.ru/services/managed-kubernetes)
|
|
||||||
а. С помощью terraform resource для [kubernetes](https://registry.terraform.io/providers/yandex-cloud/yandex/latest/docs/resources/kubernetes_cluster) создать региональный мастер kubernetes с размещением нод в разных 3 подсетях
|
|
||||||
б. С помощью terraform resource для [kubernetes node group](https://registry.terraform.io/providers/yandex-cloud/yandex/latest/docs/resources/kubernetes_node_group)
|
|
||||||
|
|
||||||
Ожидаемый результат:
|
|
||||||
|
|
||||||
1. Работоспособный Kubernetes кластер.
|
|
||||||
2. В файле `~/.kube/config` находятся данные для доступа к кластеру.
|
|
||||||
3. Команда `kubectl get pods --all-namespaces` отрабатывает без ошибок.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Создание тестового приложения
|
|
||||||
|
|
||||||
Для перехода к следующему этапу необходимо подготовить тестовое приложение, эмулирующее основное приложение разрабатываемое вашей компанией.
|
|
||||||
|
|
||||||
Способ подготовки:
|
|
||||||
|
|
||||||
1. Рекомендуемый вариант:
|
|
||||||
а. Создайте отдельный git репозиторий с простым nginx конфигом, который будет отдавать статические данные.
|
|
||||||
б. Подготовьте Dockerfile для создания образа приложения.
|
|
||||||
2. Альтернативный вариант:
|
|
||||||
а. Используйте любой другой код, главное, чтобы был самостоятельно создан Dockerfile.
|
|
||||||
|
|
||||||
Ожидаемый результат:
|
|
||||||
|
|
||||||
1. Git репозиторий с тестовым приложением и Dockerfile.
|
|
||||||
2. Регистр с собранным docker image. В качестве регистра может быть DockerHub или [Yandex Container Registry](https://cloud.yandex.ru/services/container-registry), созданный также с помощью terraform.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Подготовка системы мониторинга и деплой приложения
|
|
||||||
|
|
||||||
Уже должны быть готовы конфигурации для автоматического создания облачной инфраструктуры и поднятия Kubernetes кластера.
|
|
||||||
Теперь необходимо подготовить конфигурационные файлы для настройки нашего Kubernetes кластера.
|
|
||||||
|
|
||||||
Цель:
|
|
||||||
1. Задеплоить в кластер [prometheus](https://prometheus.io/), [grafana](https://grafana.com/), [alertmanager](https://github.com/prometheus/alertmanager), [экспортер](https://github.com/prometheus/node_exporter) основных метрик Kubernetes.
|
|
||||||
2. Задеплоить тестовое приложение, например, [nginx](https://www.nginx.com/) сервер отдающий статическую страницу.
|
|
||||||
|
|
||||||
Рекомендуемый способ выполнения:
|
|
||||||
1. Воспользовать пакетом [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus), который уже включает в себя [Kubernetes оператор](https://operatorhub.io/) для [grafana](https://grafana.com/), [prometheus](https://prometheus.io/), [alertmanager](https://github.com/prometheus/alertmanager) и [node_exporter](https://github.com/prometheus/node_exporter). При желании можете собрать все эти приложения отдельно.
|
|
||||||
2. Для организации конфигурации использовать [qbec](https://qbec.io/), основанный на [jsonnet](https://jsonnet.org/). Обратите внимание на имеющиеся функции для интеграции helm конфигов и [helm charts](https://helm.sh/)
|
|
||||||
3. Если на первом этапе вы не воспользовались [Terraform Cloud](https://app.terraform.io/), то задеплойте в кластер [atlantis](https://www.runatlantis.io/) для отслеживания изменений инфраструктуры.
|
|
||||||
|
|
||||||
Альтернативный вариант:
|
|
||||||
1. Для организации конфигурации можно использовать [helm charts](https://helm.sh/)
|
|
||||||
|
|
||||||
Ожидаемый результат:
|
|
||||||
1. Git репозиторий с конфигурационными файлами для настройки Kubernetes.
|
|
||||||
2. Http доступ к web интерфейсу grafana.
|
|
||||||
3. Дашборды в grafana отображающие состояние Kubernetes кластера.
|
|
||||||
4. Http доступ к тестовому приложению.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Установка и настройка CI/CD
|
|
||||||
|
|
||||||
Осталось настроить ci/cd систему для автоматической сборки docker image и деплоя приложения при изменении кода.
|
|
||||||
|
|
||||||
Цель:
|
|
||||||
|
|
||||||
1. Автоматическая сборка docker образа при коммите в репозиторий с тестовым приложением.
|
|
||||||
2. Автоматический деплой нового docker образа.
|
|
||||||
|
|
||||||
Можно использовать [teamcity](https://www.jetbrains.com/ru-ru/teamcity/), [jenkins](https://www.jenkins.io/) либо [gitlab ci](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/)
|
|
||||||
|
|
||||||
Ожидаемый результат:
|
|
||||||
|
|
||||||
1. Интерфейс ci/cd сервиса доступен по http.
|
|
||||||
2. При любом коммите в репозиторие с тестовым приложением происходит сборка и отправка в регистр Docker образа.
|
|
||||||
3. При создании тега (например, v1.0.0) происходит сборка и отправка с соответствующим label в регистр, а также деплой соответствующего Docker образа в кластер Kubernetes.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Что необходимо для сдачи задания?
|
|
||||||
|
|
||||||
1. Репозиторий с конфигурационными файлами Terraform и готовность продемонстрировать создание всех ресурсов с нуля.
|
|
||||||
2. Пример pull request с комментариями созданными atlantis'ом или снимки экрана из Terraform Cloud.
|
|
||||||
3. Репозиторий с конфигурацией ansible, если был выбран способ создания Kubernetes кластера при помощи ansible.
|
|
||||||
4. Репозиторий с Dockerfile тестового приложения и ссылка на собранный docker image.
|
|
||||||
5. Репозиторий с конфигурацией Kubernetes кластера.
|
|
||||||
6. Ссылка на тестовое приложение и веб интерфейс Grafana с данными доступа.
|
|
||||||
7. Все репозитории рекомендуется хранить на одном ресурсе (github, gitlab)
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/02-git-02-base/README.md)
|
|
||||||
по теме "Основы Git".
|
|
||||||
|
|
||||||
### Other repos
|
|
||||||
|
|
||||||
В ходе выполнения ДЗ были созданы следующие репозитории-зеркала:
|
|
||||||
- [gitlab](https://gitlab.com/Dannecron/netology-devops)
|
|
||||||
- [bitbucket](https://bitbucket.org/dannecron/netology-devops/src/main/)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# display command line options
|
|
||||||
|
|
||||||
count=1
|
|
||||||
while [[ -n "$1" ]]; do
|
|
||||||
echo "Parameter #$count = $1"
|
|
||||||
count=$(( $count + 1 ))
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# display command line options
|
|
||||||
|
|
||||||
count=1
|
|
||||||
for param in "$@"; do
|
|
||||||
echo "Next parameter: $param"
|
|
||||||
count=$(( $count + 1 ))
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "====="
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/02-git-04-tools/README.md)
|
|
||||||
по теме "Инструменты Git".
|
|
||||||
|
|
||||||
## Git search
|
|
||||||
|
|
||||||
- Какому тегу соответствует коммит `85024d3`?
|
|
||||||
|
|
||||||
Для поиска информации о коммите можно использовать функцию `git show`. Вывод краткой информации о коммите в саму консоль:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git --no-pager show --oneline -s 85024d3
|
|
||||||
85024d310 (tag: v0.12.23) v0.12.23
|
|
||||||
```
|
|
||||||
|
|
||||||
где: `--no-pager` - отключает открытие информации в отдельной утилите, `-s` - убирает информацию о `diff`.
|
|
||||||
|
|
||||||
Ответ: `v0.12.23`
|
|
||||||
|
|
||||||
- Сколько родителей у коммита `b8d720`? Напишите их хеши.
|
|
||||||
|
|
||||||
Есть два способа найти необходимую информацию: через `git show` или через `git log`.
|
|
||||||
|
|
||||||
Для вывода информации через `git show` нужно описать определённый формат для отображения:
|
|
||||||
```shell
|
|
||||||
git --no-pager show --pretty=format:"commit: %h%nparents: %p%n" -s b8d720
|
|
||||||
commit: b8d720f83
|
|
||||||
parents: 56cd7859e 9ea88f22f
|
|
||||||
```
|
|
||||||
|
|
||||||
Для вывода информации через `git log` нужно по аналогии с `git show` описать формат для отображения:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git --no-pager log --pretty="commit: %h%nparents: %p%n" --graph -n 1 b8d720
|
|
||||||
* commit: b8d720f83
|
|
||||||
|\ parents: 56cd7859e 9ea88f22f
|
|
||||||
| |
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: 2 родителя с хэшами `56cd7859e` и `9ea88f22f`.
|
|
||||||
|
|
||||||
- Перечислите хеши и комментарии всех коммитов которые были сделаны между тегами `v0.12.23` и `v0.12.24`.
|
|
||||||
|
|
||||||
Вывод данной информации возможен через команду `git log`. Чтобы включить в отображение сам коммит, к которому создана первая версия, нужно добавить `^`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git log --oneline --graph v0.12.23^..v0.12.24
|
|
||||||
* 33ff1c03b (tag: v0.12.24) v0.12.24
|
|
||||||
* b14b74c49 [Website] vmc provider links
|
|
||||||
* 3f235065b Update CHANGELOG.md
|
|
||||||
* 6ae64e247 registry: Fix panic when server is unreachable
|
|
||||||
* 5c619ca1b website: Remove links to the getting started guide's old location
|
|
||||||
* 06275647e Update CHANGELOG.md
|
|
||||||
* d5f9411f5 command: Fix bug when using terraform login on Windows
|
|
||||||
* 4b6d06cc5 Update CHANGELOG.md
|
|
||||||
* dd01a3507 Update CHANGELOG.md
|
|
||||||
* 225466bc3 Cleanup after v0.12.23 release
|
|
||||||
* 85024d310 (tag: v0.12.23) v0.12.23
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ:
|
|
||||||
|
|
||||||
| commit | comment |
|
|
||||||
|-----------|-------------------------------------------------------------------|
|
|
||||||
| b14b74c49 | [Website] vmc provider links |
|
|
||||||
| 3f235065b | Update CHANGELOG.md |
|
|
||||||
| 6ae64e247 | registry: Fix panic when server is unreachable |
|
|
||||||
| 5c619ca1b | website: Remove links to the getting started guide's old location |
|
|
||||||
| 06275647e | Update CHANGELOG.md |
|
|
||||||
| d5f9411f5 | command: Fix bug when using terraform login on Windows |
|
|
||||||
| 4b6d06cc5 | Update CHANGELOG.md |
|
|
||||||
| dd01a3507 | Update CHANGELOG.md |
|
|
||||||
| 225466bc3 | Cleanup after v0.12.23 release |
|
|
||||||
|
|
||||||
- Найдите коммит в котором была создана функция `func providerSource`, ее определение в коде выглядит так `func providerSource(...)` (вместо троеточия перечислены аргументы).
|
|
||||||
|
|
||||||
Для поиска самого раннего коммита воспользуемся возможностью команды `git log` искать содержимое по регулярному выражению (флаг `-G`).
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git --no-pager log --oneline -G"func providerSource(.*)"
|
|
||||||
f5012c12d command/cliconfig: Installation methods, not installation sources
|
|
||||||
5af1e6234 main: Honor explicit provider_installation CLI config when present
|
|
||||||
8c928e835 main: Consult local directories as potential mirrors of providers
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверить правильность поиска можно посмотрев все изменения в коммите:
|
|
||||||
```shell
|
|
||||||
git show 8c928e835
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: `8c928e835`
|
|
||||||
|
|
||||||
- Найдите все коммиты в которых была изменена функция `globalPluginDirs`
|
|
||||||
|
|
||||||
По аналогии с предыдущим пунктом:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git --no-pager log --oneline -G"func globalPluginDirs(.*)"
|
|
||||||
8364383c3 Push plugin discovery down into command package
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: после добавления функции её изменений не было.
|
|
||||||
|
|
||||||
- Кто автор функции `synchronizedWriters`?
|
|
||||||
|
|
||||||
По аналогии с предыдущим пунктом используем функцию `git log`, только изменим формат отображения на `short`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git --no-pager log --pretty=short -G"func synchronizedWriters(.*)"
|
|
||||||
commit bdfea50cc85161dea41be0fe3381fd98731ff786
|
|
||||||
Author: James Bardin <j.bardin@gmail.com>
|
|
||||||
|
|
||||||
remove unused
|
|
||||||
|
|
||||||
commit 5ac311e2a91e381e2f52234668b49ba670aa0fe5
|
|
||||||
Author: Martin Atkins <mart@degeneration.co.uk>
|
|
||||||
|
|
||||||
main: synchronize writes to VT100-faker on Windows
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: `Martin Atkins`
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Git
|
|
||||||
|
|
||||||
## Git new commands
|
|
||||||
|
|
||||||
В git постепенно появляются алиасы, чтобы команды становились узконаправленными. Новые полезные команды:
|
|
||||||
1. [`git restore`](https://git-scm.com/docs/git-restore) - восстановление файлов в рабочей директории (например, откат изменений как при использовании `git checkout -- .`)
|
|
||||||
2. [`git switch`](https://git-scm.com/docs/git-switch) - переключение веток. Более узконаправленная команда, чем `git checkout` или `git branch`.
|
|
||||||
|
|
||||||
## Git rebase
|
|
||||||
|
|
||||||
Примерный порядок действий перебазирования веток в `main`:
|
|
||||||
1. `git switch new-branch`
|
|
||||||
2. `git rebase main`
|
|
||||||
3. _optional_ исправление конфликтов, выполнение команды `git rebase --continue`
|
|
||||||
4. `git checkout main`
|
|
||||||
5. `git merge new-branch`
|
|
||||||
6. `git branch -D new-branch`
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
[[ -d /tmp ]]
|
|
||||||
echo $?
|
|
||||||
|
|
||||||
[[ -d /tmp/some-dir ]]
|
|
||||||
echo $?
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-01-terminal/README.md)
|
|
||||||
по теме "Работа в терминале, лекция 1".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
Какие ресурсы выделены для виртуальной машины по умолчанию?
|
|
||||||
|
|
||||||
```
|
|
||||||
RAM: 1024 MB
|
|
||||||
CPU: 2
|
|
||||||
VRAM: 4 MB
|
|
||||||
HDD: 64GB
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
Как добавить оперативной памяти или ресурсов процессора виртуальной машине?
|
|
||||||
|
|
||||||
В конфигурацию `Vargrantfile` необходимо добавить следующие строки:
|
|
||||||
|
|
||||||
```
|
|
||||||
config.vm.provider "virtualbox" do |v|
|
|
||||||
v.memory = 2048
|
|
||||||
v.cpus = 4
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
Исследование `man bash`.
|
|
||||||
|
|
||||||
> 1. какой переменной можно задать длину журнала history, и на какой строчке manual это описывается?
|
|
||||||
|
|
||||||
При помощи проставления переменной `HISTSIZE`. Описание находится на 591 строке мануала.
|
|
||||||
Показать строки возможно при помощи указания кастомного пейджера для команды `man`:
|
|
||||||
```shell
|
|
||||||
man --pager="less -N" bash
|
|
||||||
```
|
|
||||||
|
|
||||||
> 2. что делает директива `ignoreboth` в bash?
|
|
||||||
|
|
||||||
Значение `ignoreboth` проставляется для переменной `HISTCONTROL` и является сокращением для значений `ignorespace` и `ignoredups`.
|
|
||||||
Конкретно это означает, что команды, которые начинаются с пробела или совпадают с предыдущей записью в истории, не попадут в файл истории `bash`.
|
|
||||||
|
|
||||||
> 3. в каких сценариях использования применимы скобки `{}` и на какой строчке man bash это описано?
|
|
||||||
|
|
||||||
Фигурные скобки используются при написании сложных команд (`Compound Commands`). Про это написано на 196 строке мануала.
|
|
||||||
|
|
||||||
> 4. Как создать однократным вызовом touch 100000 файлов? Получится ли аналогичным образом создать 300000? Если нет, то почему?
|
|
||||||
|
|
||||||
Создать множество файлов можно написанием сложной команды `touch {1..100000}`. Создать более `ARG_MAX` файлов в рамках одного запуска не получится.
|
|
||||||
На текущей версии linux данная переменная равна 2097152.
|
|
||||||
|
|
||||||
> 5. Что делает конструкция `[[ -d /tmp ]]`
|
|
||||||
|
|
||||||
Возвращает 0, если `/tmp` существует и это директория, или 1, в ином случае.
|
|
||||||
Скрипт, проверяющий данный ответ находится в файле [double_square_braket.sh](double_square_braket.sh).
|
|
||||||
|
|
||||||
> 4. Добейтесь в выводе type -a bash в виртуальной машине наличия первым пунктом в списке.
|
|
||||||
|
|
||||||
Подобного можно добиться, сделав три шага:
|
|
||||||
* Создать новую директорию `mkdir /tmp/new_path_directory`
|
|
||||||
* Сделать символическую ссылку для баша `ln -s /usr/bin/bash /tmp/new_path_directory/bash`
|
|
||||||
* Изменив переменную окружения `PATH` с помощью `export PATH=/tmp/new_path_directory:${PATH}`
|
|
||||||
|
|
||||||
Таким образом вывод команды будет таким, как в задаче:
|
|
||||||
```shell
|
|
||||||
type -a bash
|
|
||||||
bash is /tmp/new_path_directory/bash
|
|
||||||
bash is /usr/bin/bash
|
|
||||||
bash is /bin/bash
|
|
||||||
```
|
|
||||||
> 5. Чем отличается планирование команд с помощью `batch` и `at`?
|
|
||||||
|
|
||||||
Ничем, это одна и та же команда.
|
|
||||||
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-02-terminal/README.md)
|
|
||||||
по теме "Работа в терминале, лекция 2".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Какого типа команда `cd`?
|
|
||||||
|
|
||||||
При вызове `type cd` будет выведено, что `cd is a shell builtin`, то есть команда встроенная в оболочку.
|
|
||||||
Данная команда необходима для работы пользователя с терминалом и для работы других команд, именно поэтому она встроена в ядро операционной системы.
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Какая альтернатива без pipe команде `grep <some_string> <some_file> | wc -l`?
|
|
||||||
|
|
||||||
Альтернативой является команда `grep -c <some_string> <some_file>`.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Какой процесс с PID 1 является родителем для всех процессов в вашей виртуальной машине Ubuntu 20.04?
|
|
||||||
|
|
||||||
Найти родителя всех процессов можно вызвав команду `pstree -p | grep \(1\)`.
|
|
||||||
Ответ: процесс с PID 1 - `systemd`.
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Как будет выглядеть команда, которая перенаправит вывод stderr `ls` на другую сессию терминала?
|
|
||||||
|
|
||||||
Откроем два терминала на виртуальной машине. Для каждого из них будет создан новый файл в директории `/dev/pts/`.
|
|
||||||
Таким образом, если мы хотим перенаправить stderr команды, то нужно выполнить следующие действия:
|
|
||||||
перенаправить вывод stderr в stdout, затем перенаправить stdout в `/dev/pts/<n>`, где <n> - целое число, идентификатор сессии терминала.
|
|
||||||
Полный пример команды:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ls /some/invalid/dir 2>&1 1>&/dev/pts/<n>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Получится ли одновременно передать команде файл на stdin и вывести ее stdout в другой файл?
|
|
||||||
|
|
||||||
Да, подобное можно реализовать следующим способом.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
touch in_file
|
|
||||||
echo "abc" > in_file
|
|
||||||
echo "bcd" >> in_file
|
|
||||||
grep abc < in_file 1>&out_file
|
|
||||||
cat out_file
|
|
||||||
```
|
|
||||||
|
|
||||||
Содержимое out_file является выводом команды grep, а именно одна строка `abc`.
|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Получится ли находясь в графическом режиме, вывести данные из PTY в какой-либо из эмуляторов TTY? Сможете ли вы наблюдать выводимые данные?
|
|
||||||
|
|
||||||
Да, подобное возможно. Достаточно, например, открыть новую сессию терминала в графической оболочке и выполнить перенаправление потока в `/dev/pts/<n>`.
|
|
||||||
Так же любая программа с графическим интерфейсом может выполнить данное действие. Наблюдать данные возможно,
|
|
||||||
если открыт терминал, подключённый к конкретной сессии.
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Выполните команду `bash 5>&1`. К чему она приведет? Что будет, если вы выполните `echo netology > /proc/$$/fd/5`? Почему так происходит?
|
|
||||||
|
|
||||||
Насколько я понимаю, команда `bash 5>&1` создаёт новую терминальную сессию с перенаправлением потока из `5` в `1`, то есть в `stdout`.
|
|
||||||
Но так как `5` - это не стандартный идентификатор потока, поэтому оболочка создаст новый файл `/proc/$$/fd/5`.
|
|
||||||
Данный файл будет алиасом для stdout, поэтому выполнение `echo` выведет содержимое в терминал,
|
|
||||||
как это сделал бы обычный вызов команды без перенаправлений потока.
|
|
||||||
|
|
||||||
### Задача 8
|
|
||||||
|
|
||||||
> Получится ли в качестве входного потока для pipe использовать только stderr команды, не потеряв при этом отображение stdout на pty?
|
|
||||||
|
|
||||||
Да, такая возможность есть. Сначала необходимо запустить терминал с новым перенаправлением, как в предыдущем вопросе: `bash 5>&1`.
|
|
||||||
Затем уже можно выполнить перенаправление потоков следующим образом:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ls -la /tmp/wrong_dir 2>&1 1>&5 | less
|
|
||||||
```
|
|
||||||
|
|
||||||
Таким образом в команду `less` попадёт следующий текст: `ls: cannot access '/tmp/wrong_dir': No such file or directory`.
|
|
||||||
|
|
||||||
### Задача 9
|
|
||||||
|
|
||||||
> Что выведет команда `cat /proc/$$/environ`? Как еще можно получить аналогичный по содержанию вывод?
|
|
||||||
|
|
||||||
Данная команда выведет все переменные окружения, которые инициализированы в текущей сессии терминала.
|
|
||||||
Аналогичный результат может быть достигнут вызовом команд `printenv` или `env`.
|
|
||||||
|
|
||||||
### Задача 11
|
|
||||||
|
|
||||||
> Используя `man`, опишите что доступно по адресам `/proc/<PID>/cmdline`, `/proc/<PID>/exe`.
|
|
||||||
|
|
||||||
Файл `/proc/<PID>/cmdline` - это файл, предназначенный только для чтения, который содержит в себе полную команду процесса, но только если процесс не зомби.
|
|
||||||
Файл `/proc/<PID>/exe` - это файл-символическая ссылка, содержащая актуальный полный путь до выполняемой команды.
|
|
||||||
|
|
||||||
### Задача 12
|
|
||||||
|
|
||||||
> Узнайте, какую наиболее старшую версию набора инструкций SSE поддерживает ваш процессор с помощью `/proc/cpuinfo`
|
|
||||||
|
|
||||||
Выполним команду `cat /proc/cpuinfo | grep sse`. В выводе можно найти такие версии, как `sse`, `sse2`, `ssse3`, `sse4_1`, `sse4_2`.
|
|
||||||
Таким образом, ответом на вопрос будет `sse4_2`.
|
|
||||||
|
|
||||||
### Задача 13
|
|
||||||
|
|
||||||
> Почему команда `ssh localhost 'tty'` внутри виртуальной машины выдаёт ошибку `not a tty`
|
|
||||||
|
|
||||||
Изначально, нужно понять, что происходит при выполнении исходной команды. Судя по мануалу команды `ssh`,
|
|
||||||
`localhost` является пунктом назначения, куда будет произведено подключение,
|
|
||||||
а `tty` - это команда, которая будет выполнена на удалённом сервере. Из того же мануала следует,
|
|
||||||
что при указании команды будет произведено выполнение команды, а не логин пользователя. То есть,
|
|
||||||
команда будет выполнена без выделения отдельной сессии для пользователя,
|
|
||||||
а значит команда `tty` в данном случае действительно не сможет найти запущенный экземпляр терминала.
|
|
||||||
|
|
||||||
Изменить поведение можно принудительно заставив `ssh` создать новую сессию, для этого нужно добавить ключ `-t`,
|
|
||||||
то есть выполнить команду `ssh -t localhost 'tty'`.
|
|
||||||
|
|
||||||
### Задача 14
|
|
||||||
|
|
||||||
> Необходимо переместить запущенный процесс из одной сессии в другую с использованием утилиты `reptyr`
|
|
||||||
|
|
||||||
На виртуальной машине утилита не установлена, поэтому установим её `sudo apt install reptyr`.
|
|
||||||
В качестве примера запустим утилиту `screen`, которая запустит новую сессию внутри себя.
|
|
||||||
В другом подключении через ssh к виртуальной машине запустим "долгий" процесс, например, `less .bash_history`.
|
|
||||||
Внутри сессии `screen` найдём PID процесса `less`, для этого выполним команду `lsof | grep less`.
|
|
||||||
Затем выполним команду `reptyr <PID>`.
|
|
||||||
|
|
||||||
К сожалению, полностью перенести процесс не получилось, есть какие-то странные ошибки по типу `Operation not permitted`
|
|
||||||
или "зависания" второго терминала, если выполнить команду от администратора.
|
|
||||||
|
|
||||||
### Задача 15
|
|
||||||
|
|
||||||
> Узнайте что делает команда `tee` и почему в отличие от `sudo echo` команда с `sudo tee` будет работать.
|
|
||||||
|
|
||||||
Команда `tee` читает стандартный поток ввода и пишет его в стандартный поток вывода и файлы.
|
|
||||||
В отличие от `echo` перенаправление идёт в рамках одного процесса, именно поэтому `sudo tee` будет работать,
|
|
||||||
так как процесс берёт стандартный поток ввода от текущего пользователя, затем начинает запись с повышенными привилегиями.
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-03-os/README.md)
|
|
||||||
по теме "3.3. Операционные системы, лекция 1".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Какой системный вызов делает команда `cd`?
|
|
||||||
|
|
||||||
Для удобства поиска перенаправим вывод команды `strace` в утилиту `less`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
strace /bin/bash -c 'cd /tmp' 2>&1 | less
|
|
||||||
```
|
|
||||||
|
|
||||||
Далее, найдём в трейсе упоминание директории `tmp`, указанной в команде. Таким образом, обнаружим, что команда `cd`
|
|
||||||
делает системный вызов `chdir("/tmp")`.
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Используя `strace` выясните, где находится база данных `file` на основании которой она делает свои догадки.
|
|
||||||
|
|
||||||
При использовании команды `file` на любом файле, `strace` выведет такую строку:
|
|
||||||
|
|
||||||
```
|
|
||||||
openat(AT_FDCWD, "/usr/share/misc/magic.mgc", O_RDONLY) = 3
|
|
||||||
```
|
|
||||||
|
|
||||||
Предположительно, `/usr/share/misc/magic.mgc` - это и есть база данных для команды `file`.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Предложите способ обнуления открытого удаленного файла (чтобы освободить место на файловой системе)
|
|
||||||
|
|
||||||
Зная PID процесса и то, что каждый процесс пишет свои потоки в файлы в директории `/proc/<PID>/fd`.
|
|
||||||
Таким образом, можно найти конкретный поток, который пишет в файл, вызвав команду
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ls -la /proc/1988/fd/
|
|
||||||
|
|
||||||
total 0
|
|
||||||
dr-x------ 2 vagrant vagrant 0 Feb 16 03:25 .
|
|
||||||
dr-xr-xr-x 9 vagrant vagrant 0 Feb 16 03:25 ..
|
|
||||||
lrwx------ 1 vagrant vagrant 64 Feb 16 03:25 0 -> /dev/pts/0
|
|
||||||
lrwx------ 1 vagrant vagrant 64 Feb 16 03:25 1 -> /dev/pts/0
|
|
||||||
lrwx------ 1 vagrant vagrant 64 Feb 16 03:25 2 -> /dev/pts/0
|
|
||||||
lr-x------ 1 vagrant vagrant 64 Feb 16 03:25 3 -> /tmp/do_not_delete_me
|
|
||||||
```
|
|
||||||
|
|
||||||
В данном случае, поток под номером 3 держит соединение с искомым файлом. Таким образом, чтобы обнулить данный файл,
|
|
||||||
достаточно направить пустую строку в данный поток:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "" > /proc/1988/fd/3
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Занимают ли зомби-процессы какие-то ресурсы в ОС (CPU, RAM, IO)?
|
|
||||||
|
|
||||||
Нет, zombie-процессы не используют никаких ресурсов операционной системы.
|
|
||||||
Единственное, что они занимают - это идентификатор процесса.
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> На какие файлы вы увидели вызовы группы `open` за первую секунду работы утилиты `opensnoop-bpfcc`?
|
|
||||||
|
|
||||||
За первую секунду работы утилиты был произведён следующий вывод:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo opensnoop-bpfcc
|
|
||||||
|
|
||||||
PID COMM FD ERR PATH
|
|
||||||
833 vminfo 5 0 /var/run/utmp
|
|
||||||
619 dbus-daemon -1 2 /usr/local/share/dbus-1/system-services
|
|
||||||
619 dbus-daemon 19 0 /usr/share/dbus-1/system-services
|
|
||||||
619 dbus-daemon -1 2 /lib/dbus-1/system-services
|
|
||||||
619 dbus-daemon 19 0 /var/lib/snapd/dbus-1/system-services/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Какой системный вызов использует `uname -a`? Приведите цитату из man по этому системному вызову,
|
|
||||||
> где описывается альтернативное местоположение в /proc, где можно узнать версию ядра и релиз ОС.
|
|
||||||
|
|
||||||
Утилита `uname` использует системный вызов `uname`, мануал к которому можно прочитать командой `man 2 uname`.
|
|
||||||
|
|
||||||
Цитата из мануала
|
|
||||||
> Part of the utsname information is also accessible via /proc/sys/ker‐nel/{ostype, hostname, osrelease, version, domainname}.
|
|
||||||
|
|
||||||
PS. На виртуальной машине не было установленных мануалов для системных вызовов. Чтобы их установить,
|
|
||||||
нужно выполнить команду `sudo apt install manpages-dev`.
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Чем отличается последовательность команд через `;` и через `&&` в bash?
|
|
||||||
> Есть ли смысл использовать в bash `&&`, если применить `set -e`?
|
|
||||||
|
|
||||||
При использовании `&&` будет учитываться код выхода предыдущей выполненой команды. Если он не 0, то выполнение последовательности будет прервано.
|
|
||||||
В случае же `;` последовательность будет выполнена в любом случае.
|
|
||||||
|
|
||||||
В случае `set -e` параметр имеет следующее определение
|
|
||||||
|
|
||||||
> When this option is on, if a simple command fails for any of the reasons listed in Consequences of Shell Errors or returns an exit status value >0,
|
|
||||||
> and is not part of the compound list following a while, until, or if keyword,
|
|
||||||
> and is not a part of an AND or OR list,
|
|
||||||
> and is not a pipeline preceded by the ! reserved word, then the shell shall immediately exit.
|
|
||||||
|
|
||||||
То есть, если данная команда будет выполнена в связке с другими командами, то она не сможет прервать выполнение последовательности.
|
|
||||||
Таким образом, для данной команды использование `&&` и `;` будет иметь одинаковое поведение.
|
|
||||||
|
|
||||||
### Задача 8
|
|
||||||
|
|
||||||
> Из каких опций состоит режим bash `set -euxo pipefail` и почему его хорошо было бы использовать в сценариях?
|
|
||||||
|
|
||||||
Параметр `-e` уже был рассмотрен в предыдущем вопросе.
|
|
||||||
|
|
||||||
`-u` - пишет ошибку в stderr, когда скрипт пытается обратиться к несуществующей переменной, но при этом не останавливает его работу.
|
|
||||||
Если запущен интерактивный режим, то его работа никогда не прерывается.
|
|
||||||
|
|
||||||
`-x` - пишет в stderr трейс (последовательность выполнения системных вызовов) для каждой команды перед её выполнением.
|
|
||||||
|
|
||||||
`-o` - устанавливает настройку работы последовательности команд. В данном случае значение `pipefail` говорит о том,
|
|
||||||
что статус работы всей последовательности будет значение последней команды с ненулевым кодом выхода или 0, если все команды выполнились успешно.
|
|
||||||
|
|
||||||
### Задача 9
|
|
||||||
|
|
||||||
> Используя `-o stat` для `ps`, определите, какой наиболее часто встречающийся статус у процессов в системе.
|
|
||||||
|
|
||||||
Выполним данную команду на виртуальной машине
|
|
||||||
```shell
|
|
||||||
ps -o stat
|
|
||||||
|
|
||||||
STAT
|
|
||||||
Ss
|
|
||||||
R+
|
|
||||||
```
|
|
||||||
|
|
||||||
Таким образом, самым встречающимся статусом является `Ss`. Первая буква - это непосредственно статус (`S - interruptible sleep (waiting for an event to complete)`),
|
|
||||||
вторая - дополнительная информация (`s - is a session leader`).
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-04-os/README.md)
|
|
||||||
по теме "3.4. Операционные системы, лекция 2".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Создайте самостоятельно простой unit-файл для [node_exporter](https://github.com/prometheus/node_exporter)
|
|
||||||
|
|
||||||
Для начала необходимо установить `node_exporter` в систему. Для этого воспользуемся [официальным гайдом](https://prometheus.io/docs/guides/node-exporter/#installing-and-running-the-node-exporter),
|
|
||||||
а именно:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
wget https://github.com/prometheus/node_exporter/releases/download/v1.3.1/node_exporter-1.3.1.linux-amd64.tar.gz
|
|
||||||
tar xvfz node_exporter-1.3.1.linux-amd64.tar.gz
|
|
||||||
cd node_exporter-1.3.1.linux-amd64
|
|
||||||
sudo mv node_exporter /usr/local/bin/
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что всё работает, выполнив команду
|
|
||||||
|
|
||||||
```shell
|
|
||||||
node_exporter --help
|
|
||||||
|
|
||||||
usage: node_exporter [<flags>]
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
-h, --help Show context-sensitive help (also try --help-long and --help-man).
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем, создадим простой unit-файл по пути `/etc/systemd/system`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo touch /etc/systemd/system/prometheus_node_exporter.service
|
|
||||||
```
|
|
||||||
|
|
||||||
И добавим в него следующее содержимое:
|
|
||||||
|
|
||||||
```unit file (systemd)
|
|
||||||
[Unit]
|
|
||||||
Description=Prometheuth node exporter service
|
|
||||||
StartLimitIntervalSec=0
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
Restart=always
|
|
||||||
RestartSec=1
|
|
||||||
User=vagrant
|
|
||||||
ExecStart=/usr/local/bin/node_exporter
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем запустим сервис, проверим, что он имеет статус "запущен", проверим работоспособность самого приложения и остановим выполнение:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo systemctl start prometheus_node_exporter
|
|
||||||
sudo systemctl status prometheus_node_exporter
|
|
||||||
|
|
||||||
● prometheus_node_exporter.service - Prometheuth node exporter service
|
|
||||||
Loaded: loaded (/etc/systemd/system/prometheus_node_exporter.service; disabled; vendor preset: enabled)
|
|
||||||
Active: active (running) since Wed 2022-02-23 03:52:14 UTC; 2s ago
|
|
||||||
Main PID: 1520 (node_exporter)
|
|
||||||
Tasks: 4 (limit: 1112)
|
|
||||||
Memory: 2.2M
|
|
||||||
CGroup: /system.slice/prometheus_node_exporter.service
|
|
||||||
└─1520 /usr/local/bin/node_exporter
|
|
||||||
|
|
||||||
Feb 23 03:52:14 vagrant node_exporter[1520]: ts=2022-02-23T03:52:14.087Z caller=node_exporter.go:115 level=info collector=thermal_zone
|
|
||||||
Feb 23 03:52:14 vagrant node_exporter[1520]: ts=2022-02-23T03:52:14.087Z caller=node_exporter.go:115 level=info collector=time
|
|
||||||
<...>
|
|
||||||
|
|
||||||
curl -I http://localhost:9100/metrics
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Content-Type: text/plain; version=0.0.4; charset=utf-8
|
|
||||||
Date: Wed, 23 Feb 2022 04:01:31 GMT
|
|
||||||
|
|
||||||
sudo systemctl stop prometheus_node_exporter
|
|
||||||
sudo systemctl status prometheus_node_exporter
|
|
||||||
|
|
||||||
sudo systemctl status prometheus_node_exporter
|
|
||||||
● prometheus_node_exporter.service - Prometheuth node exporter service
|
|
||||||
Loaded: loaded (/etc/systemd/system/prometheus_node_exporter.service; disabled; vendor preset: enabled)
|
|
||||||
Active: inactive (dead)
|
|
||||||
|
|
||||||
<...>
|
|
||||||
Feb 23 04:02:22 vagrant systemd[1]: Stopping Prometheuth node exporter service...
|
|
||||||
Feb 23 04:02:22 vagrant systemd[1]: prometheus_node_exporter.service: Succeeded.
|
|
||||||
Feb 23 04:02:22 vagrant systemd[1]: Stopped Prometheuth node exporter service.
|
|
||||||
```
|
|
||||||
|
|
||||||
Для добавления конфигурации через файл, необходимо создать файл с переменной окружения `EXTRA_OPTS`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo mkdir -p /usr/local/lib/node_exporter
|
|
||||||
sudo touch /usr/local/lib/node_exporter/conf.env
|
|
||||||
sudo chmod +r /usr/local/lib/node_exporter/conf.env
|
|
||||||
echo "EXTRA_OPTS=--collector.cpu.info" | sudo tee /usr/local/lib/node_exporter/conf.env
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем сделать изменения в unit-файле:
|
|
||||||
* В блок `[Service]` добавить новую строку `EnvironmentFile=-/usr/local/lib/node_exporter/conf.env`
|
|
||||||
* В ключ `ExecStart` после полного пути до приложения добавить вывод переменной окружения `$EXTRA_OPTS`
|
|
||||||
|
|
||||||
Далее проверить, что приложение запускается с дополнительным флагом:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo systemctl start prometheus_node_exporter
|
|
||||||
sudo systemctl status prometheus_node_exporter
|
|
||||||
|
|
||||||
● prometheus_node_exporter.service - Prometheuth node exporter service
|
|
||||||
Loaded: loaded (/etc/systemd/system/prometheus_node_exporter.service; disabled; vendor preset: enabled)
|
|
||||||
Active: active (running) since Wed 2022-02-23 04:18:07 UTC; 4s ago
|
|
||||||
Main PID: 1820 (node_exporter)
|
|
||||||
Tasks: 4 (limit: 1112)
|
|
||||||
Memory: 2.3M
|
|
||||||
CGroup: /system.slice/prometheus_node_exporter.service
|
|
||||||
└─1820 /usr/local/bin/node_exporter --collector.cpu.info
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Приведите несколько опций, которые вы бы выбрали для базового мониторинга хоста по CPU, памяти, диску и сети.
|
|
||||||
|
|
||||||
По умолчанию в `node_exporter` включено достаточно много различной информации (~1000 строк). Поэтому, на мой взгляд,
|
|
||||||
для начала стоит включить только следующие флаги:
|
|
||||||
* `--collector.disable-defaults` - отключение всех коллекторов по умолчанию
|
|
||||||
* `--collector.cpu` - отображение статистики по CPU
|
|
||||||
* `--collector.filesystem` - отображение статистики по файловой системе (например, количество использованного места)
|
|
||||||
* `--collector.meminfo` - отображение статистики по памяти
|
|
||||||
* `--collector.os` - отображение информации об операционной системе
|
|
||||||
* `--collector.time` - отображение информации о текущем системном времени
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Ознакомьтесь с метриками, которые по умолчанию собираются `Netdata`, и с комментариями, которые даны к этим метрикам.
|
|
||||||
|
|
||||||
`netdata` отображает следующие метрики:
|
|
||||||
* `cpu` - утилизация CPU по всем ядрам
|
|
||||||
* `load` - текущая загрузка системы (количество процессов, которые используют или ожидают различные системные ресурсы), поделённая на три усреднённых значения.
|
|
||||||
* `disk` - текущие показатели I/O для физических дисков
|
|
||||||
* `ram` - информация об оперативной памяти
|
|
||||||
* `swap` - информация о файлах подкачки
|
|
||||||
* `network` - информация о пропускной способности физических сетевых интерфейсов
|
|
||||||
* и другие
|
|
||||||
|
|
||||||
Доступны так же подробные графики по каждой из категорий.
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Можно ли по выводу `dmesg` понять, осознает ли ОС, что загружена не на настоящем оборудовании, а на системе виртуализации?
|
|
||||||
|
|
||||||
В `dmesg` можно найти следующий вывод `Detected virtualization oracle.` от `systemd`. Таким образом да, можно понять, что система осознаёт,
|
|
||||||
что находится внутри виртуальной машины, а не на физическом оборудовании.
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Как настроен `sysctl fs.nr_open` на системе по-умолчанию? Какой другой существующий лимит не позволит достичь такого числа?
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sysctl fs.nr_open
|
|
||||||
fs.nr_open = 1048576
|
|
||||||
```
|
|
||||||
|
|
||||||
`fs.nr_open` является системным лимитом на количество открытых файлов для пользователя.
|
|
||||||
Для текущей сессии bash можно посмотреть и изменить ограничение при помощи команды `ulimit -n`.
|
|
||||||
Для конкретных групп и пользователей ограничения можно задать в файле `/etc/security/limits.conf`.
|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Запустите любой долгоживущий процесс в отдельном неймспейсе процессов; покажите, что ваш процесс работает под PID 1 через `nsenter`.
|
|
||||||
|
|
||||||
Запустим процесс `bash` в изолированном пространстве имён:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo unshare -f --pid --mount-proc /bin/bash
|
|
||||||
ps aux
|
|
||||||
|
|
||||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
|
||||||
root 1 0.2 0.3 8960 3988 pts/0 S 03:22 0:00 /bin/bash
|
|
||||||
root 8 0.0 0.3 10616 3352 pts/0 R+ 03:22 0:00 ps aux
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем, в отдельной терминальной сессии подключимся к созданной сессии, для начала, найдя её в списке запущенных процессов через `ps`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ps au --forest -C unshare
|
|
||||||
|
|
||||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
|
||||||
vagrant 2177 0.0 0.4 9092 4632 pts/1 Ss 03:23 0:00 -bash
|
|
||||||
vagrant 2345 0.0 0.3 10616 3400 pts/1 R+ 03:34 0:00 \_ ps au --forest -C unshare
|
|
||||||
vagrant 2081 0.0 0.4 9092 4512 pts/0 Ss 03:21 0:00 -bash
|
|
||||||
root 2123 0.0 0.4 11016 4660 pts/0 S 03:22 0:00 \_ sudo unshare -f --pid --mount-proc /bin/bash
|
|
||||||
root 2124 0.0 0.0 7232 528 pts/0 S 03:22 0:00 \_ unshare -f --pid --mount-proc /bin/bash
|
|
||||||
root 2125 0.0 0.3 8960 3988 pts/0 S+ 03:22 0:00 \_ /bin/bash
|
|
||||||
|
|
||||||
sudo nsenter --target 2125 --pid --mount
|
|
||||||
|
|
||||||
ps aux
|
|
||||||
|
|
||||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
|
||||||
root 1 0.0 0.3 8960 3988 pts/0 S+ 03:22 0:00 /bin/bash
|
|
||||||
root 21 0.0 0.3 8960 4000 pts/1 S 03:35 0:00 -bash
|
|
||||||
root 52 0.0 0.3 10616 3252 pts/1 R+ 03:36 0:00 ps aux
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Найдите информацию о том, что такое `:(){ :|:& };:`.
|
|
||||||
> Запустите эту команду в своей виртуальной машине. Некоторое время все будет "плохо", после чего (минуты) – ОС должна стабилизироваться.
|
|
||||||
> Вызов `dmesg` расскажет, какой механизм помог автоматической стабилизации.
|
|
||||||
> Как настроен этот механизм по-умолчанию, и как изменить число процессов, которое можно создать в сессии?
|
|
||||||
|
|
||||||
Команда - это `fork bomb`, которую можно разделить на следующие блоки:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
:() # define a function named :, () defines a function in bash
|
|
||||||
{
|
|
||||||
: | :; # the pipe needs two instances of this function, which forks two shells
|
|
||||||
}
|
|
||||||
; # end function definition
|
|
||||||
: # run it
|
|
||||||
```
|
|
||||||
|
|
||||||
В `dmesg` можно увидеть следующее сообщение:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cgroup: fork rejected by pids controller in /user.slice/user-1000.slice/session-10.scope
|
|
||||||
```
|
|
||||||
|
|
||||||
Число процессов можно изменить с помощью команды `ulimit -u <num>`.
|
|
||||||
@@ -1,429 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-05-fs/README.md)
|
|
||||||
по теме "3.5. Файловые системы".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Разряженные файлы
|
|
||||||
|
|
||||||
Суть таких файлов в том, чтобы разделить реальные данные последовательностью нуль-символов (`\x00`), которые не занимают реального места на физическом носителе.
|
|
||||||
При этом сами данные записываются на разных фрагментах на физическом диске.
|
|
||||||
|
|
||||||
Например, если есть разряжённый файл размером в 4KB, то он может быть поделён на 4 блока по 1KB и записан на диск именно такими фрагментами.
|
|
||||||
Это позволяет сделать запись туда, где доступно 1-2KB (например, после удаления другого файла),
|
|
||||||
но куда оригинальный файл целиком не поместится.
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Могут ли файлы, являющиеся жесткой ссылкой на один объект, иметь разные права доступа и владельца? Почему?
|
|
||||||
|
|
||||||
Не могут. Причина в том, что жёсткие ссылки всегда ссылаются на одну `Inode` (идентификатор объекта файла внутри ОС).
|
|
||||||
То есть, все файлы, которые имеют одну `Inode` будут синхронизированы по: содержимому, правам доступа и другим мета-данным.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Реконфигурация виртуальной машины
|
|
||||||
|
|
||||||
В текущую конфигурацию [`vagrant`](/src/vagrant/Vagrantfile) добавлена конфигурация дисков:
|
|
||||||
|
|
||||||
```
|
|
||||||
config.vm.provider :virtualbox do |vb|
|
|
||||||
lvm_experiments_disk0_path = "/tmp/lvm_experiments_disk0.vmdk"
|
|
||||||
lvm_experiments_disk1_path = "/tmp/lvm_experiments_disk1.vmdk"
|
|
||||||
vb.customize ['createmedium', '--filename', lvm_experiments_disk0_path, '--size', 2560]
|
|
||||||
vb.customize ['createmedium', '--filename', lvm_experiments_disk1_path, '--size', 2560]
|
|
||||||
vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', lvm_experiments_disk0_path]
|
|
||||||
vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 2, '--device', 0, '--type', 'hdd', '--medium', lvm_experiments_disk1_path]
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
После запуска ВМ (`vagrant up`) можно проверить, что файлы дисков из конфигурации были созданы:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ls /tmp | grep lvm
|
|
||||||
lvm_experiments_disk0.vmdk
|
|
||||||
lvm_experiments_disk1.vmdk
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Используя `fdisk`, разбейте первый диск на 2 раздела: 2 Гб, оставшееся пространство.
|
|
||||||
|
|
||||||
Найдём диски, которые были подключены на предыдущем шаге
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo fdisk -l
|
|
||||||
|
|
||||||
<...>
|
|
||||||
|
|
||||||
Disk /dev/sdb: 2.51 GiB, 2684354560 bytes, 5242880 sectors
|
|
||||||
Disk model: VBOX HARDDISK
|
|
||||||
Units: sectors of 1 * 512 = 512 bytes
|
|
||||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
|
||||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
|
||||||
|
|
||||||
|
|
||||||
Disk /dev/sdc: 2.51 GiB, 2684354560 bytes, 5242880 sectors
|
|
||||||
Disk model: VBOX HARDDISK
|
|
||||||
Units: sectors of 1 * 512 = 512 bytes
|
|
||||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
|
||||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
|
||||||
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
Проведём операцию на диске `/dev/sdb`. Утилита `fdisk` - интерактивная, поэтому вводить команды нужно непосредственно после её запуска.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo fdisk /dev/sdb
|
|
||||||
|
|
||||||
Changes will remain in memory only, until you decide to write them.
|
|
||||||
Be careful before using the write command.
|
|
||||||
|
|
||||||
Device does not contain a recognized partition table.
|
|
||||||
Created a new DOS disklabel with disk identifier 0x0c6b10a9.
|
|
||||||
|
|
||||||
Command (m for help): g
|
|
||||||
Created a new GPT disklabel (GUID: F75C9D4B-5A47-7540-8A8D-D7448C95BCE5).
|
|
||||||
|
|
||||||
Command (m for help): n
|
|
||||||
Partition number (1-128, default 1): 1
|
|
||||||
First sector (2048-5242846, default 2048): 2048
|
|
||||||
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-5242846, default 5242846): +2G
|
|
||||||
|
|
||||||
Created a new partition 1 of type 'Linux filesystem' and of size 2 GiB.
|
|
||||||
|
|
||||||
Command (m for help): n
|
|
||||||
Partition number (2-128, default 2): 2
|
|
||||||
First sector (4196352-5242846, default 4196352):
|
|
||||||
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4196352-5242846, default 5242846):
|
|
||||||
|
|
||||||
Created a new partition 2 of type 'Linux filesystem' and of size 511 MiB.
|
|
||||||
|
|
||||||
Command (m for help): w
|
|
||||||
The partition table has been altered.
|
|
||||||
Calling ioctl() to re-read partition table.
|
|
||||||
Syncing disks.
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что всё прошло успешно
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo fdisk -l /dev/sdb
|
|
||||||
Disk /dev/sdb: 2.51 GiB, 2684354560 bytes, 5242880 sectors
|
|
||||||
Disk model: VBOX HARDDISK
|
|
||||||
Units: sectors of 1 * 512 = 512 bytes
|
|
||||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
|
||||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
|
||||||
Disklabel type: gpt
|
|
||||||
Disk identifier: F75C9D4B-5A47-7540-8A8D-D7448C95BCE5
|
|
||||||
|
|
||||||
Device Start End Sectors Size Type
|
|
||||||
/dev/sdb1 2048 4196351 4194304 2G Linux filesystem
|
|
||||||
/dev/sdb2 4196352 5242846 1046495 511M Linux filesystem
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Используя `sfdisk`, перенесите данную таблицу разделов на второй диск.
|
|
||||||
|
|
||||||
Перенесём таблицу разделов с `/dev/sdb` на `/dev/sdc`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo sfdisk --dump /dev/sdb > /tmp/sdb.dump
|
|
||||||
|
|
||||||
sudo sfdisk /dev/sdc < /tmp/sdb.dump
|
|
||||||
|
|
||||||
Checking that no-one is using this disk right now ... OK
|
|
||||||
|
|
||||||
Disk /dev/sdc: 2.51 GiB, 2684354560 bytes, 5242880 sectors
|
|
||||||
Disk model: VBOX HARDDISK
|
|
||||||
Units: sectors of 1 * 512 = 512 bytes
|
|
||||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
|
||||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
|
||||||
|
|
||||||
>>> Script header accepted.
|
|
||||||
>>> Script header accepted.
|
|
||||||
>>> Script header accepted.
|
|
||||||
>>> Script header accepted.
|
|
||||||
>>> Script header accepted.
|
|
||||||
>>> Script header accepted.
|
|
||||||
>>> Created a new GPT disklabel (GUID: F75C9D4B-5A47-7540-8A8D-D7448C95BCE5).
|
|
||||||
/dev/sdc1: Created a new partition 1 of type 'Linux filesystem' and of size 2 GiB.
|
|
||||||
/dev/sdc2: Created a new partition 2 of type 'Linux filesystem' and of size 511 MiB.
|
|
||||||
/dev/sdc3: Done.
|
|
||||||
|
|
||||||
New situation:
|
|
||||||
Disklabel type: gpt
|
|
||||||
Disk identifier: F75C9D4B-5A47-7540-8A8D-D7448C95BCE5
|
|
||||||
|
|
||||||
Device Start End Sectors Size Type
|
|
||||||
/dev/sdc1 2048 4196351 4194304 2G Linux filesystem
|
|
||||||
/dev/sdc2 4196352 5242846 1046495 511M Linux filesystem
|
|
||||||
|
|
||||||
The partition table has been altered.
|
|
||||||
Calling ioctl() to re-read partition table.
|
|
||||||
Syncing disks.
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что всё прошло успешно
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo fdisk -l /dev/sdc
|
|
||||||
Disk /dev/sdc: 2.51 GiB, 2684354560 bytes, 5242880 sectors
|
|
||||||
Disk model: VBOX HARDDISK
|
|
||||||
Units: sectors of 1 * 512 = 512 bytes
|
|
||||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
|
||||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
|
||||||
Disklabel type: gpt
|
|
||||||
Disk identifier: F75C9D4B-5A47-7540-8A8D-D7448C95BCE5
|
|
||||||
|
|
||||||
Device Start End Sectors Size Type
|
|
||||||
/dev/sdc1 2048 4196351 4194304 2G Linux filesystem
|
|
||||||
/dev/sdc2 4196352 5242846 1046495 511M Linux filesystem
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Соберите `mdadm` `RAID1` на паре разделов 2 Гб.
|
|
||||||
|
|
||||||
Разделы, которые необходимо объединить в `RAID1`: `/dev/sdb1` и `/dev/sdc1`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
|
|
||||||
mdadm: Defaulting to version 1.2 metadata
|
|
||||||
mdadm: array /dev/md0 started.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Соберите `mdadm` `RAID0` на второй паре маленьких разделов
|
|
||||||
|
|
||||||
Разделы, которые необходимо объединить в `RAID0`: `/dev/sdb2` и `/dev/sdc2`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo mdadm --create /dev/md1 --level=0 --raid-devices=2 /dev/sdb2 /dev/sdc2
|
|
||||||
mdadm: Defaulting to version 1.2 metadata
|
|
||||||
mdadm: array /dev/md1 started.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 8
|
|
||||||
|
|
||||||
> Создайте 2 независимых PV на получившихся md-устройствах
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo pvcreate /dev/md0
|
|
||||||
Physical volume "/dev/md0" successfully created.
|
|
||||||
sudo pvcreate /dev/md1
|
|
||||||
Physical volume "/dev/md1" successfully created.
|
|
||||||
|
|
||||||
sudo pvdisplay
|
|
||||||
"/dev/md0" is a new physical volume of "<2.00 GiB"
|
|
||||||
--- NEW Physical volume ---
|
|
||||||
PV Name /dev/md0
|
|
||||||
VG Name
|
|
||||||
PV Size <2.00 GiB
|
|
||||||
Allocatable NO
|
|
||||||
PE Size 0
|
|
||||||
Total PE 0
|
|
||||||
Free PE 0
|
|
||||||
Allocated PE 0
|
|
||||||
PV UUID hNpE2z-h7m3-W1HT-dBIh-Xm24-6Zal-dhtPfl
|
|
||||||
|
|
||||||
"/dev/md1" is a new physical volume of "1017.00 MiB"
|
|
||||||
--- NEW Physical volume ---
|
|
||||||
PV Name /dev/md1
|
|
||||||
VG Name
|
|
||||||
PV Size 1017.00 MiB
|
|
||||||
Allocatable NO
|
|
||||||
PE Size 0
|
|
||||||
Total PE 0
|
|
||||||
Free PE 0
|
|
||||||
Allocated PE 0
|
|
||||||
PV UUID PB8hEQ-bZGA-M6Xe-tOQV-1CAb-DRSf-syoUSA
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 9
|
|
||||||
|
|
||||||
> Создайте общую volume-group на этих двух PV.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo vgcreate test_vg /dev/md0 /dev/md1
|
|
||||||
Volume group "test_vg" successfully created
|
|
||||||
|
|
||||||
sudo vgdisplay
|
|
||||||
--- Volume group ---
|
|
||||||
VG Name test_vg
|
|
||||||
System ID
|
|
||||||
Format lvm2
|
|
||||||
Metadata Areas 2
|
|
||||||
Metadata Sequence No 1
|
|
||||||
VG Access read/write
|
|
||||||
VG Status resizable
|
|
||||||
MAX LV 0
|
|
||||||
Cur LV 0
|
|
||||||
Open LV 0
|
|
||||||
Max PV 0
|
|
||||||
Cur PV 2
|
|
||||||
Act PV 2
|
|
||||||
VG Size <2.99 GiB
|
|
||||||
PE Size 4.00 MiB
|
|
||||||
Total PE 765
|
|
||||||
Alloc PE / Size 0 / 0
|
|
||||||
Free PE / Size 765 / <2.99 GiB
|
|
||||||
VG UUID 7xcN3Z-o9Ca-iXl2-5eao-iA4e-cEVJ-YgSajr
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 10
|
|
||||||
|
|
||||||
> Создайте LV размером 100 Мб, указав его расположение на PV с `RAID0`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo lvcreate --size=100MB test_vg /dev/md1
|
|
||||||
Logical volume "lvol0" created.
|
|
||||||
|
|
||||||
sudo lvdisplay
|
|
||||||
--- Logical volume ---
|
|
||||||
LV Path /dev/test_vg/lvol0
|
|
||||||
LV Name lvol0
|
|
||||||
VG Name test_vg
|
|
||||||
LV UUID 1fJJLO-zJeY-924D-O9gn-N1Cz-fyQ6-mnA7Z3
|
|
||||||
LV Write Access read/write
|
|
||||||
LV Creation host, time vagrant, 2022-03-02 02:55:17 +0000
|
|
||||||
LV Status available
|
|
||||||
# open 0
|
|
||||||
LV Size 100.00 MiB
|
|
||||||
Current LE 25
|
|
||||||
Segments 1
|
|
||||||
Allocation inherit
|
|
||||||
Read ahead sectors auto
|
|
||||||
- currently set to 4096
|
|
||||||
Block device 253:1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 11
|
|
||||||
|
|
||||||
> Создайте `mkfs.ext4` ФС на получившемся `LV`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo mkfs.ext4 /dev/test_vg/lvol0
|
|
||||||
mke2fs 1.45.5 (07-Jan-2020)
|
|
||||||
Creating filesystem with 25600 4k blocks and 25600 inodes
|
|
||||||
|
|
||||||
Allocating group tables: done
|
|
||||||
Writing inode tables: done
|
|
||||||
Creating journal (1024 blocks): done
|
|
||||||
Writing superblocks and filesystem accounting information: done
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 12
|
|
||||||
|
|
||||||
> Смонтируйте этот раздел в любую директорию.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir /tmp/new
|
|
||||||
sudo mount /dev/test_vg/lvol0 /tmp/new
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 13
|
|
||||||
|
|
||||||
> Поместите туда тестовый файл.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo wget https://mirror.yandex.ru/ubuntu/ls-lR.gz -O /tmp/new/test.gz
|
|
||||||
|
|
||||||
--2022-03-02 03:04:07-- https://mirror.yandex.ru/ubuntu/ls-lR.gz
|
|
||||||
Resolving mirror.yandex.ru (mirror.yandex.ru)... 213.180.204.183, 2a02:6b8::183
|
|
||||||
Connecting to mirror.yandex.ru (mirror.yandex.ru)|213.180.204.183|:443... connected.
|
|
||||||
HTTP request sent, awaiting response... 200 OK
|
|
||||||
Length: 22388361 (21M) [application/octet-stream]
|
|
||||||
Saving to: ‘/tmp/new/test.gz’
|
|
||||||
|
|
||||||
2022-03-02 03:04:09 (9.33 MB/s) - ‘/tmp/new/test.gz’ saved [22388361/22388361]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 14
|
|
||||||
|
|
||||||
> Прикрепите вывод `lsblk`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo lsblk
|
|
||||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
|
||||||
loop0 7:0 0 55.4M 1 loop /snap/core18/2128
|
|
||||||
loop2 7:2 0 70.3M 1 loop /snap/lxd/21029
|
|
||||||
loop3 7:3 0 55.5M 1 loop /snap/core18/2284
|
|
||||||
loop4 7:4 0 43.6M 1 loop /snap/snapd/14978
|
|
||||||
loop5 7:5 0 61.9M 1 loop /snap/core20/1361
|
|
||||||
loop6 7:6 0 67.9M 1 loop /snap/lxd/22526
|
|
||||||
sda 8:0 0 64G 0 disk
|
|
||||||
├─sda1 8:1 0 1M 0 part
|
|
||||||
├─sda2 8:2 0 1G 0 part /boot
|
|
||||||
└─sda3 8:3 0 63G 0 part
|
|
||||||
└─ubuntu--vg-ubuntu--lv 253:0 0 31.5G 0 lvm /
|
|
||||||
sdb 8:16 0 2.5G 0 disk
|
|
||||||
├─sdb1 8:17 0 2G 0 part
|
|
||||||
│ └─md0 9:0 0 2G 0 raid1
|
|
||||||
└─sdb2 8:18 0 511M 0 part
|
|
||||||
└─md1 9:1 0 1017M 0 raid0
|
|
||||||
└─test_vg-lvol0 253:1 0 100M 0 lvm /tmp/new
|
|
||||||
sdc 8:32 0 2.5G 0 disk
|
|
||||||
├─sdc1 8:33 0 2G 0 part
|
|
||||||
│ └─md0 9:0 0 2G 0 raid1
|
|
||||||
└─sdc2 8:34 0 511M 0 part
|
|
||||||
└─md1 9:1 0 1017M 0 raid0
|
|
||||||
└─test_vg-lvol0 253:1 0 100M 0 lvm /tmp/new
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 15
|
|
||||||
|
|
||||||
> Протестируйте целостность файла
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo gzip -t /tmp/new/test.gz
|
|
||||||
echo $?
|
|
||||||
|
|
||||||
0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 16
|
|
||||||
|
|
||||||
> Используя `pvmove`, переместите содержимое PV с `RAID0` на `RAID1`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo pvmove /dev/md1 /dev/md0
|
|
||||||
/dev/md1: Moved: 16.00%
|
|
||||||
/dev/md1: Moved: 100.00%
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 17
|
|
||||||
|
|
||||||
> Сделайте `--fail` на устройство в вашем `RAID1` md.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo mdadm --fail /dev/md0 /dev/sdb1
|
|
||||||
mdadm: set /dev/sdb1 faulty in /dev/md0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 18
|
|
||||||
|
|
||||||
> Подтвердите выводом `dmesg`, что `RAID1` работает в деградированном состоянии
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo dmesg | tail -n 5
|
|
||||||
[ 2711.025093] 02:44:35.853387 timesync vgsvcTimeSyncWorker: Radical guest time change: 81 954 170 807 000ns (GuestNow=1 646 189 075 853 355 000 ns GuestLast=1 646 107 121 682 548 000 ns fSetTimeLastLoop=true )
|
|
||||||
[ 3814.237420] EXT4-fs (dm-1): mounted filesystem with ordered data mode. Opts: (null)
|
|
||||||
[ 3814.237429] ext4 filesystem being mounted at /tmp/new supports timestamps until 2038 (0x7fffffff)
|
|
||||||
[ 4328.371203] md/raid1:md0: Disk failure on sdb1, disabling device.
|
|
||||||
md/raid1:md0: Operation continuing on 1 devices.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 19
|
|
||||||
|
|
||||||
> Протестируйте целостность файла, несмотря на "сбойный" диск он должен продолжать быть доступен
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo gzip -t /tmp/new/test.gz
|
|
||||||
echo $?
|
|
||||||
0
|
|
||||||
```
|
|
||||||
@@ -1,231 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-06-net/README.md)
|
|
||||||
по теме "3.6. Компьютерные сети, лекция 1".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Работа c HTTP через телнет.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
telnet stackoverflow.com 80
|
|
||||||
Trying 151.101.1.69...
|
|
||||||
Connected to stackoverflow.com.
|
|
||||||
Escape character is '^]'.
|
|
||||||
GET /questions HTTP/1.0
|
|
||||||
HOST: stackoverflow.com
|
|
||||||
|
|
||||||
HTTP/1.1 301 Moved Permanently
|
|
||||||
cache-control: no-cache, no-store, must-revalidate
|
|
||||||
location: https://stackoverflow.com/questions
|
|
||||||
x-request-guid: 345ccd64-092f-4bed-a6bb-f55d978ab74a
|
|
||||||
feature-policy: microphone 'none'; speaker 'none'
|
|
||||||
content-security-policy: upgrade-insecure-requests; frame-ancestors 'self' https://stackexchange.com
|
|
||||||
Accept-Ranges: bytes
|
|
||||||
Date: Wed, 09 Mar 2022 02:50:15 GMT
|
|
||||||
Via: 1.1 varnish
|
|
||||||
Connection: close
|
|
||||||
X-Served-By: cache-hhn4072-HHN
|
|
||||||
X-Cache: MISS
|
|
||||||
X-Cache-Hits: 0
|
|
||||||
X-Timer: S1646794215.885878,VS0,VE156
|
|
||||||
Vary: Fastly-SSL
|
|
||||||
X-DNS-Prefetch-Control: off
|
|
||||||
Set-Cookie: prov=a65f8cdf-ae94-33aa-2d32-b4ba53feba61; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:00 GMT; path=/; HttpOnly
|
|
||||||
```
|
|
||||||
|
|
||||||
В ответ пришёл статус код `301`, который означает постоянное перемещение с запрашиваемой страницы.
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Повторите задание 1 в браузере, используя консоль разработчика F12.
|
|
||||||
|
|
||||||
Код ответа при заходе на сайт `http://stackoverflow.com`: `Status Code: 307 Internal Redirect`.
|
|
||||||
Наиболее долгих по загрузке запрос - это запрос на загрузку самой страницы после редиректа (`https://stackoverflow.com/`).
|
|
||||||
Скриншот консоли браузера:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Какой IP адрес у вас в интернете?
|
|
||||||
|
|
||||||
Чтобы узнать текущий внешний ip-адрес, можно воспользоваться онлайн сервисами, такими как [myip.com](https://www.myip.com/) или [whoer.net](https://whoer.net/).
|
|
||||||
В дополнение к этому, можно использовать только консоль и команду `dig`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dig +short myip.opendns.com @resolver1.opendns.com
|
|
||||||
46.181.144.146
|
|
||||||
|
|
||||||
dig TXT +short o-o.myaddr.l.google.com @ns1.google.com
|
|
||||||
"46.181.144.146"
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: `46.181.144.146`.
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Какому провайдеру принадлежит ваш IP адрес? Какой автономной системе AS?
|
|
||||||
|
|
||||||
```shell
|
|
||||||
whois 46.181.144.146
|
|
||||||
|
|
||||||
<...>
|
|
||||||
|
|
||||||
% Information related to '46.181.128.0/18AS39927'
|
|
||||||
|
|
||||||
route: 46.181.128.0/18
|
|
||||||
descr: Goodline.info
|
|
||||||
origin: AS39927
|
|
||||||
mnt-by: ELT-MNT
|
|
||||||
created: 2010-12-22T11:28:33Z
|
|
||||||
last-modified: 2010-12-22T11:28:33Z
|
|
||||||
source: RIPE
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: оператор - `Goodline.info`, AS - `AS39927`.
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Через какие сети проходит пакет, отправленный с вашего компьютера на адрес 8.8.8.8? Через какие AS?
|
|
||||||
|
|
||||||
По умолчанию утилита `traceroute` не установлена в системе ubuntu. Для её установки достаточно выполнить команду
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt install traceroute
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
traceroute -A 8.8.8.8
|
|
||||||
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
|
|
||||||
1 router.asus.com (192.168.1.1) [*] 5.960 ms 3.192 ms 3.129 ms
|
|
||||||
2 46-181-144-129.shah-95-kmr-cr01-6500.net.elt (46.181.144.129) [AS39927] 6.523 ms 6.484 ms 6.446 ms
|
|
||||||
3 172.16.23.174 (172.16.23.174) [*] 6.577 ms 6.539 ms 6.502 ms
|
|
||||||
4 172-16-22-178.kras-136-kmr-asbr01-asr.net.elt (172.16.22.178) [*] 5.984 ms 10.393 ms 10.354 ms
|
|
||||||
5 host_91_221_180_4.milecom.ru (91.221.180.4) [AS13094] 56.869 ms 56.832 ms 56.796 ms
|
|
||||||
6 108.170.250.34 (108.170.250.34) [AS15169] 54.496 ms 51.426 ms 108.170.250.66 (108.170.250.66) [AS15169] 51.329 ms
|
|
||||||
7 * * *
|
|
||||||
8 108.170.232.251 (108.170.232.251) [AS15169] 72.746 ms 72.14.238.168 (72.14.238.168) [AS15169] 62.523 ms 172.253.65.82 (172.253.65.82) [AS15169] 64.747 ms
|
|
||||||
9 216.239.46.139 (216.239.46.139) [AS15169] 68.148 ms 72.14.236.73 (72.14.236.73) [AS15169] 69.164 ms 172.253.51.241 (172.253.51.241) [AS15169] 69.121 ms
|
|
||||||
10 * * *
|
|
||||||
11 * * *
|
|
||||||
12 * * *
|
|
||||||
13 * * *
|
|
||||||
14 * * *
|
|
||||||
15 * * *
|
|
||||||
16 * * *
|
|
||||||
17 * * *
|
|
||||||
18 * * *
|
|
||||||
19 * dns.google (8.8.8.8) [AS15169] 57.661 ms 56.687 ms
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Повторите задание 5 в утилите mtr. На каком участке наибольшая задержка - delay?
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mtr -w 8.8.8.8
|
|
||||||
Start: 2022-03-09T10:25:09+0700
|
|
||||||
HOST: host Loss% Snt Last Avg Best Wrst StDev
|
|
||||||
1.|-- router.asus.com 0.0% 10 2.9 3.3 2.5 4.6 0.8
|
|
||||||
2.|-- 46-181-144-129.shah-95-kmr-cr01-6500.net.elt 0.0% 10 4.0 4.0 2.5 5.5 1.1
|
|
||||||
3.|-- 172.16.23.174 0.0% 10 4.1 4.4 3.1 6.0 0.9
|
|
||||||
4.|-- 172-16-22-178.kras-136-kmr-asbr01-asr.net.elt 0.0% 10 4.3 4.2 3.5 5.5 0.6
|
|
||||||
5.|-- host_91_221_180_4.milecom.ru 0.0% 10 57.9 55.7 54.5 57.9 1.0
|
|
||||||
6.|-- 108.170.250.146 0.0% 10 55.7 55.4 54.4 56.4 0.7
|
|
||||||
7.|-- 209.85.249.158 50.0% 10 58.7 63.8 58.7 81.0 9.6
|
|
||||||
8.|-- 216.239.57.222 0.0% 10 62.5 62.3 61.5 64.3 0.9
|
|
||||||
9.|-- 142.250.238.181 0.0% 10 66.4 66.0 65.3 66.9 0.5
|
|
||||||
10.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
11.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
12.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
13.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
14.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
15.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
16.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
17.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
18.|-- ??? 100.0 10 0.0 0.0 0.0 0.0 0.0
|
|
||||||
19.|-- dns.google 0.0% 10 58.5 58.5 57.6 60.3 0.8
|
|
||||||
```
|
|
||||||
|
|
||||||
Наибольшая задержка была на 7-ом хопе с худшим показателем в 81ms.
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Какие DNS сервера отвечают за доменное имя `dns.google`? Какие A записи?
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dig dns.google
|
|
||||||
|
|
||||||
; <<>> DiG 9.16.1-Ubuntu <<>> dns.google
|
|
||||||
;; global options: +cmd
|
|
||||||
;; Got answer:
|
|
||||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59679
|
|
||||||
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
|
|
||||||
|
|
||||||
;; OPT PSEUDOSECTION:
|
|
||||||
; EDNS: version: 0, flags:; udp: 65494
|
|
||||||
;; QUESTION SECTION:
|
|
||||||
;dns.google. IN A
|
|
||||||
|
|
||||||
;; ANSWER SECTION:
|
|
||||||
dns.google. 370 IN A 8.8.4.4
|
|
||||||
dns.google. 370 IN A 8.8.8.8
|
|
||||||
|
|
||||||
;; Query time: 8 msec
|
|
||||||
;; SERVER: 127.0.0.53#53(127.0.0.53)
|
|
||||||
;; WHEN: Ср мар 09 10:28:19 +07 2022
|
|
||||||
;; MSG SIZE rcvd: 71
|
|
||||||
```
|
|
||||||
|
|
||||||
Ответ: dns-сервера с ip-адресами `8.8.4.4` и `8.8.8.8`. Оба адреса являются `A`-записями.
|
|
||||||
|
|
||||||
### Задача 9
|
|
||||||
|
|
||||||
> Проверьте PTR записи для IP адресов из задания 7. Какое доменное имя привязано к IP?
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dig -x 8.8.4.4
|
|
||||||
|
|
||||||
; <<>> DiG 9.16.1-Ubuntu <<>> -x 8.8.4.4
|
|
||||||
;; global options: +cmd
|
|
||||||
;; Got answer:
|
|
||||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33111
|
|
||||||
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
|
|
||||||
|
|
||||||
;; OPT PSEUDOSECTION:
|
|
||||||
; EDNS: version: 0, flags:; udp: 65494
|
|
||||||
;; QUESTION SECTION:
|
|
||||||
;4.4.8.8.in-addr.arpa. IN PTR
|
|
||||||
|
|
||||||
;; ANSWER SECTION:
|
|
||||||
4.4.8.8.in-addr.arpa. 53775 IN PTR dns.google.
|
|
||||||
|
|
||||||
;; Query time: 4 msec
|
|
||||||
;; SERVER: 127.0.0.53#53(127.0.0.53)
|
|
||||||
;; WHEN: Ср мар 09 10:33:09 +07 2022
|
|
||||||
;; MSG SIZE rcvd: 73
|
|
||||||
|
|
||||||
dig -x 8.8.8.8
|
|
||||||
|
|
||||||
; <<>> DiG 9.16.1-Ubuntu <<>> -x 8.8.8.8
|
|
||||||
;; global options: +cmd
|
|
||||||
;; Got answer:
|
|
||||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3893
|
|
||||||
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
|
|
||||||
|
|
||||||
;; OPT PSEUDOSECTION:
|
|
||||||
; EDNS: version: 0, flags:; udp: 65494
|
|
||||||
;; QUESTION SECTION:
|
|
||||||
;8.8.8.8.in-addr.arpa. IN PTR
|
|
||||||
|
|
||||||
;; ANSWER SECTION:
|
|
||||||
8.8.8.8.in-addr.arpa. 6386 IN PTR dns.google.
|
|
||||||
|
|
||||||
;; Query time: 4 msec
|
|
||||||
;; SERVER: 127.0.0.53#53(127.0.0.53)
|
|
||||||
;; WHEN: Ср мар 09 10:33:34 +07 2022
|
|
||||||
;; MSG SIZE rcvd: 73
|
|
||||||
```
|
|
||||||
|
Before Width: | Height: | Size: 349 KiB |
@@ -1,133 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-07-net/README.md)
|
|
||||||
по теме "3.7. Компьютерные сети, лекция 2".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Проверьте список доступных сетевых интерфейсов на вашем компьютере. Какие команды есть для этого в Linux и в Windows?
|
|
||||||
|
|
||||||
В Linux можно выполнить команду `ip link`, которая покажет все сетевые интерфейсы, включая виртуальные.
|
|
||||||
Для Windows аналогом данной команды является вызов `ipconfig /all`.
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Какой протокол используется для распознавания соседа по сетевому интерфейсу? Какой пакет и команды есть в Linux для этого?
|
|
||||||
|
|
||||||
Для получения информации о соседнем устройстве используется протокол [LLDP](https://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol).
|
|
||||||
Данный протокол в ОС Linux реализован в утилите `lldpd`.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Какая технология используется для разделения L2 коммутатора на несколько виртуальных сетей? Какой пакет и команды есть в Linux для этого? Приведите пример конфига.
|
|
||||||
|
|
||||||
Технология имеет название [VLAN](https://en.wikipedia.org/wiki/Virtual_LAN).
|
|
||||||
В Linux для управления виртуальными сетями используется пакет `vlan`, а именно утилита `vconfig` (устарела, рекомендуется использовать утилиту `ip route`).
|
|
||||||
|
|
||||||
Вся конфигурация так или иначе хранится в файле `/etc/network/interfaces`, содержимое которого будет выглядеть примерно так
|
|
||||||
|
|
||||||
```
|
|
||||||
auto eth0.1400
|
|
||||||
iface eth0.1400 inet static
|
|
||||||
address 192.168.1.1
|
|
||||||
netmask 255.255.255.0
|
|
||||||
vlan_raw_device eth0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Какие типы агрегации интерфейсов есть в Linux? Какие опции есть для балансировки нагрузки? Приведите пример конфига.
|
|
||||||
|
|
||||||
В конфигурации Linux предусмотрены следующие типы агрегации:
|
|
||||||
* static/manual - ручная статическая настройка
|
|
||||||
* dynamic - динамическая
|
|
||||||
|
|
||||||
Типы балансировки нагрузки:
|
|
||||||
* `balance-rr` - балансировка по принципу [Round-robin](https://en.wikipedia.org/wiki/Round-robin_scheduling).
|
|
||||||
* `active-backup` - один активный интерфейс, в случае выхода из строя которого, трафик перенаправляется на запасной.
|
|
||||||
* `balance-xor` - "эксклюзивный ИЛИ", при котором происходит сопоставление MAC-адреса из запроса к MAC-адресу интерфейса. Эта связь используется в дальнейшем для всех запросов.
|
|
||||||
* `broadcase` - транслирование запроса на все интерфейсы.
|
|
||||||
* `802.3ad` - динамическая политика агрегации по стандарту [IEEE 802.3ad](https://www.ieee802.org/3/hssg/public/apr07/frazier_01_0407.pdf)
|
|
||||||
* `balance-tlb` - балансировка трафика в зависимости от нагрузки интерфейсов.
|
|
||||||
* `balance-alb` - надстройка над `balance-tlb`, убирающая необходимость специальной поддержки со стороны интерфейса.
|
|
||||||
|
|
||||||
Настройка производится в том же файле `/etc/network/interfaces`. Пример конфигурации с балансировкой нагрузки по типу `active-backup`,
|
|
||||||
когда основным является интерфейс `eth0`, а `wlan0` - запасным, который активируется при выходе из строя основного:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Define slaves
|
|
||||||
auto eth0
|
|
||||||
iface eth0 inet manual
|
|
||||||
bond-master bond0
|
|
||||||
bond-primary eth0
|
|
||||||
bond-mode active-backup
|
|
||||||
|
|
||||||
auto wlan0
|
|
||||||
iface wlan0 inet manual
|
|
||||||
wpa-conf /etc/network/wpa.conf
|
|
||||||
bond-master bond0
|
|
||||||
bond-primary eth0
|
|
||||||
bond-mode active-backup
|
|
||||||
|
|
||||||
# Define master
|
|
||||||
auto bond0
|
|
||||||
iface bond0 inet dhcp
|
|
||||||
bond-slaves none
|
|
||||||
bond-primary eth0
|
|
||||||
bond-mode active-backup
|
|
||||||
bond-miimon 100
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Сколько IP адресов в сети с маской `/29` ? Сколько `/29` подсетей можно получить из сети с маской `/24`. Приведите несколько примеров `/29` подсетей внутри сети `10.10.10.0/24`.
|
|
||||||
|
|
||||||
Всего в сети с маской `/29` находятся 8 IP адресов, 2 из которых зарезервированы.
|
|
||||||
|
|
||||||
Всего в сети с маской `/24` могут использоваться 256 IP адреса.
|
|
||||||
Таким образом, если на каждую сеть с маской `/29` нужен пул из 8 адресов,
|
|
||||||
то в оригинальную сеть поместится 256 / 8 = 32 подсети с маской `/29`.
|
|
||||||
|
|
||||||
Примеры подсетей с маской `/29` внутри сети `10.10.10.0/24`:
|
|
||||||
* `10.10.10.1/29`
|
|
||||||
* `10.10.10.9/29`
|
|
||||||
* `10.10.10.19/29`
|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Задача: вас попросили организовать стык между 2-мя организациями. Диапазоны `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` уже заняты. Из какой подсети допустимо взять частные IP адреса? Маску выберите из расчета максимум 40-50 хостов внутри подсети.
|
|
||||||
|
|
||||||
Так как самые ходовые сети, используемые для внутренних сетей, уже заняты, то остаётся только вариант с сетью `100.64.0.0/10`.
|
|
||||||
Если рассчитывать на 40-50 хостов в рамках данной сети, то можно взять подсеть `100.64.0.0/26`,
|
|
||||||
у которой будет диапазон доступных адресов `100.64.0.1 - 100.64.0.62`.
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Как проверить ARP таблицу в Linux, Windows? Как очистить ARP кеш полностью? Как из ARP таблицы удалить только один нужный IP?
|
|
||||||
|
|
||||||
Работа с ARP-таблицами:
|
|
||||||
* linux
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# вывод данных таблицы
|
|
||||||
ip neigh
|
|
||||||
# полная очистка
|
|
||||||
ip neigh flush all
|
|
||||||
# удаление одного ip-адреса
|
|
||||||
ip neigh del <ip-address> lladdr <link-layer address> <device>
|
|
||||||
# пример удаления адреса
|
|
||||||
ip neigh del 192.168.1.3 lladdr 02:01:02:03:04:05 dev eth0
|
|
||||||
```
|
|
||||||
|
|
||||||
* windows
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# вывод данных таблицы
|
|
||||||
arp -a
|
|
||||||
# полная очистка
|
|
||||||
arp -d *
|
|
||||||
# удаление одного ip-адреса
|
|
||||||
arp -d <ip-address>
|
|
||||||
# пример удаление адреса
|
|
||||||
arp -d 192.168.1.3
|
|
||||||
```
|
|
||||||
|
Before Width: | Height: | Size: 40 KiB |
@@ -1 +0,0 @@
|
|||||||
<mxfile host="app.diagrams.net" modified="2022-03-17T03:03:17.629Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36 OPR/83.0.4254.70" etag="NbVIYXF-muBXRySHjtu2" version="14.6.7" type="device"><diagram name="Page-1" id="c37626ed-c26b-45fb-9056-f9ebc6bb27b6">7Vpbc5s6EP41fgzDTVwec23PTM9MZjLT9jx1ZJCBE0BUyLHdX39WRoAExHEcu2566swEtBIrsd+3q13ZM+e6WH9guEr/pjHJZ7YZr2fOzcy2LTMM4SIkm0YS+lYjSFgWy0G94CH7QdonpXSZxaTWBnJKc55VujCiZUkirskwY3SlD1vQXJ+1wgkZCR4inI+lX7KYp1JqmWbf8ZFkSSqnDpDsmOPoMWF0Wcr5SlqSpqfArRo5tE5xTFeKyLmdOdeMUt7cFetrkguzthZrnrt7prdbMiMl3+uByMeeP18Ei9ixHXNxYaFGxRPOl9IOf5WcsJJwuWK+aQ0EqgALaFzBa1RCGOV0CZqvVmnGyUOFIyFcAT1AlvIih5YFt1vbELEEs3m4sYFoRLTIoraDM/rY2V48uKAlv8NFlgtKfSYsxiWWYskfC0x4NbaCNMwTYZysFZG0ygdCC8LZBobIXrdFSJIX+dIwK4UKLeCpwoKOHljSL+l09zjAjYRiT1iQPbZ+DGyVzS3DNBPneE7yq46I1zSnrB9Yc8z4XSbm31qalPGl8Jh+BEiUfh0J+whI1HTJIvLM27qBdHfMEsJfYKqww05EGckxz550r34LOpeLB/Or/z2J2Wd8Yf24nJv+lwt75Dc7EaOMpzShJc5ve+nAMfoxnyitJLD/Es430sR4yakO+0tAknXGv4p7A8nWP0rPzVptbJTGPWEZ2ImwjjBgM6kIte2tKiPs2r26bWujtoYKJ7E8DnMm4XorV+Sj9zSD5fVRI/QNU/nYWgxxTaQrbF5F6lCj9EAtQnowcryBouZ1R4qACnijDKvEgHrX8pE2j+2HO9cFr7trPNw0K+i9qjP1YWGwhXeXl7V7UbFORF5iRFkdUQM8C8hWy6vuNDGu087pFuAsbbScwaSOF8BbtiFQ6VlsP5PBUWwzGSQSn0QQvqd1xjNaQt+cck4LZcBlniWigwv33ndb/ImboCvixCSF1W3QDMfboO8apneiUGtNkMDLubSBxgbv+5K2HRf11jqXMMByq3XfCXeJvKpaog7rfqAjvBpQV0SHzvYRrAGdOQUewBUSrBVlj+0awDDNMvSlzVkrsULbsLzAsAyIDXe2++yD7ytpG5FzgsLP8tXx9ThpTSRtAOFE0uYcIWmb5Kp7aMACm1bbkPUNl/G3CrbLKiUM57VRRTow26hO2O0TEcH91wppWLYiUjZhF8JvnpUwaVuzmceBHiLTIFCNkPeDiTB1KtzHZdSbcc9x1Rj1D/aDbQqFo21qhH444fbeqYoB71D0CxqTQkKfQgJfGxFM19wfFXk1QJ8U3xHRrm7E33GQ9wZej8a4O+4YdxScCHf/ZdzHFZpWvvVllVpVdX2vKan6Ws/01WLPcF9d7s0Oqs52JW8vFmjuNPAKslOnL63sjXWcPTj9sb3BPrFv5WYPMpLucPOFyu2AYmnSinvUS+cgpGdrxw+G/R4Yic7JSBf5hhkqHz3RDfzD+OkMThaG+dCJ6RkejZ5HJGcQ6NxE74Gc3jnJiQJIwGzPD4IQql3fHJLTNWzTRMgMPRRaqN2RX8tVzxxUdz85lrbTKWyN06gaMRbSGa7TVM+BJI3V/EyKRhnVMPEqsjjeHhRP1ep6gX6E7MpxBgZH43LanWCVfaqiyhofsv/eCIDLDCqb7qTibBg4/zcMwoEX+OdG4OAzpQL+G/zpzxHCONR5+jcZEwcIyJnYP51TYbzH+dE5Eve2dGxSI+s9ZEbWWStJV3wR8mzebjuBceB3gkPGWrY1VHXqfGh8yvV77wSuNdqN7ZPtBdDsfwbUQNb/zMq5/Q8=</diagram></mxfile>
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-08-net/README.md)
|
|
||||||
по теме "3.8. Компьютерные сети, лекция 3".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Подключитесь к публичному маршрутизатору в интернет. Найдите маршрут к вашему публичному IP
|
|
||||||
|
|
||||||
```shell
|
|
||||||
telnet route-views.routeviews.org
|
|
||||||
Trying 128.223.51.103...
|
|
||||||
Connected to route-views.routeviews.org.
|
|
||||||
|
|
||||||
<...>
|
|
||||||
|
|
||||||
User Access Verification
|
|
||||||
|
|
||||||
Username: rviews
|
|
||||||
|
|
||||||
route-views>show ip route 46.181.144.146
|
|
||||||
Routing entry for 46.180.0.0/15
|
|
||||||
Known via "bgp 6447", distance 20, metric 0
|
|
||||||
Tag 6939, type external
|
|
||||||
Last update from 64.71.137.241 7w0d ago
|
|
||||||
Routing Descriptor Blocks:
|
|
||||||
* 64.71.137.241, from 64.71.137.241, 7w0d ago
|
|
||||||
Route metric is 0, traffic share count is 1
|
|
||||||
AS Hops 3
|
|
||||||
Route tag 6939
|
|
||||||
MPLS label: none
|
|
||||||
|
|
||||||
route-views>show bgp 46.181.144.146
|
|
||||||
BGP routing table entry for 46.180.0.0/15, version 150820343
|
|
||||||
Paths: (23 available, best #22, table default)
|
|
||||||
Not advertised to any peer
|
|
||||||
Refresh Epoch 1
|
|
||||||
3333 31133 39927, (aggregated by 65423 192.168.21.211)
|
|
||||||
193.0.0.56 from 193.0.0.56 (193.0.0.56)
|
|
||||||
Origin IGP, localpref 100, valid, external, atomic-aggregate
|
|
||||||
path 7FE1040964D8 RPKI State not found
|
|
||||||
rx pathid: 0, tx pathid: 0
|
|
||||||
Refresh Epoch 1
|
|
||||||
8283 1299 39927, (aggregated by 65423 192.168.21.136)
|
|
||||||
94.142.247.3 from 94.142.247.3 (94.142.247.3)
|
|
||||||
Origin IGP, metric 0, localpref 100, valid, external, atomic-aggregate
|
|
||||||
Community: 1299:30000 8283:1 8283:101
|
|
||||||
unknown transitive attribute: flag 0xE0 type 0x20 length 0x18
|
|
||||||
value 0000 205B 0000 0000 0000 0001 0000 205B
|
|
||||||
0000 0005 0000 0001
|
|
||||||
path 7FE0A25887D8 RPKI State not found
|
|
||||||
rx pathid: 0, tx pathid: 0
|
|
||||||
Refresh Epoch 1
|
|
||||||
4901 6079 31133 39927, (aggregated by 65423 192.168.21.211)
|
|
||||||
162.250.137.254 from 162.250.137.254 (162.250.137.254)
|
|
||||||
Origin IGP, localpref 100, valid, external, atomic-aggregate
|
|
||||||
Community: 65000:10100 65000:10300 65000:10400
|
|
||||||
path 7FE154880220 RPKI State not found
|
|
||||||
rx pathid: 0, tx pathid: 0
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Создайте dummy0 интерфейс в Ubuntu. Добавьте несколько статических маршрутов. Проверьте таблицу маршрутизации.
|
|
||||||
|
|
||||||
Создание dummy-интерфейса:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "dummy" | sudo tee -a /etc/modules
|
|
||||||
sudo touch /etc/modprobe.d/dummy.conf
|
|
||||||
echo "options dummy numdummies=1" | sudo tee /etc/modprobe.d/dummy.conf
|
|
||||||
sudo ip link add dummy0 type dummy
|
|
||||||
```
|
|
||||||
|
|
||||||
Добавление маршрутов и вывод таблицы маршрутизации:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo ip route add 10.2.2.2/32 dev eth0
|
|
||||||
sudo ip route add 10.2.2.3/32 via 10.0.2.16
|
|
||||||
ip route
|
|
||||||
default via 10.0.2.2 dev eth0 proto dhcp src 10.0.2.15 metric 100
|
|
||||||
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
|
|
||||||
10.0.2.2 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
|
|
||||||
10.2.2.2 dev eth0 scope link
|
|
||||||
10.2.2.3 via 10.0.2.16 dev eth0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Проверьте открытые TCP порты в Ubuntu, какие протоколы и приложения используют эти порты? Приведите несколько примеров.
|
|
||||||
|
|
||||||
Для вывода открытых TCP-портов используем утилиту `ss` со следующими флагами:
|
|
||||||
* `-t` вывод только TCP-портов
|
|
||||||
* `-l` вывод портов в состоянии `LISTEN`, то есть открытые для прослушивания
|
|
||||||
* `-n` использовать числовое представление портов (например, `:ssh` -> `:22`)
|
|
||||||
*
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ss -tln
|
|
||||||
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
|
|
||||||
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
|
|
||||||
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
|
|
||||||
LISTEN 0 128 [::]:22 [::]:*
|
|
||||||
```
|
|
||||||
|
|
||||||
В данном случае открыты только порты для соединения по `ssh` (порты `:22`) и для [`systemd-resolved`](https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html) (порт `:53`).
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Проверьте используемые UDP сокеты в Ubuntu, какие протоколы и приложения используют эти порты?
|
|
||||||
|
|
||||||
По аналогии с предыдущим заданием используем утилиту `ss`, заменив флаг `-t` на `-u`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ss -ulpn
|
|
||||||
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
|
|
||||||
UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
|
|
||||||
UNCONN 0 0 10.0.2.15%eth0:68 0.0.0.0:*
|
|
||||||
```
|
|
||||||
|
|
||||||
Порт `:53` предназначается для использования [`systemd-resolved`](https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html),
|
|
||||||
а порт `68` используется для получения информации о динамической IP-адресации от DHCP-сервера.
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Используя diagrams.net, создайте L3 диаграмму вашей домашней сети или любой другой сети, с которой вы работали.
|
|
||||||
|
|
||||||
В качестве сети взята стандартная домашняя сеть с wi-fi-роутером.
|
|
||||||
|
|
||||||
Файл [network.xml](network.xml) для открытия в [diagrams.net](https://diagrams.net).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Установите Nginx, настройте в режиме балансировщика TCP или UDP.
|
|
||||||
|
|
||||||
Установка nginx:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt install nginx
|
|
||||||
|
|
||||||
sudo service nginx status
|
|
||||||
● nginx.service - A high performance web server and a reverse proxy server
|
|
||||||
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
|
|
||||||
Active: active (running) since Thu 2022-03-17 03:14:31 UTC; 24s ago
|
|
||||||
Docs: man:nginx(8)
|
|
||||||
Main PID: 1830 (nginx)
|
|
||||||
Tasks: 3 (limit: 1107)
|
|
||||||
Memory: 5.0M
|
|
||||||
CGroup: /system.slice/nginx.service
|
|
||||||
├─1830 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
|
|
||||||
├─1831 nginx: worker process
|
|
||||||
└─1832 nginx: worker process
|
|
||||||
```
|
|
||||||
|
|
||||||
Далее, определим, что есть два ip-адреса, на которые необходимо сделать проксирование и балансировку трафика:
|
|
||||||
* `10.2.2.2`
|
|
||||||
* `10.2.2.3`
|
|
||||||
|
|
||||||
Оба ip-адреса слушают следующие порты: `:25` - upd-трафик, `:80` - tcp-трафик.
|
|
||||||
|
|
||||||
Настроим nginx на прослушивание порта `:80` для обоих типов трафика с дальнейшей балансировкой и проксированием.
|
|
||||||
|
|
||||||
Добавим новый блок конфигурации в файл `/etc/nginx/nginx.conf`:
|
|
||||||
|
|
||||||
```
|
|
||||||
stream {
|
|
||||||
upstream tcp_backend {
|
|
||||||
server 10.2.2.2:80;
|
|
||||||
server 10.2.2.3:80;
|
|
||||||
}
|
|
||||||
|
|
||||||
upstream upd_backend {
|
|
||||||
server 10.2.2.2:25;
|
|
||||||
server 10.2.2.3:25;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
proxy_pass tcp_backend;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80 udp;
|
|
||||||
proxy_pass upd_backend;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Дополнительно, нужно убрать конфигурацию приветственной страницы, которая работает по умолчанию и слушает порт `80`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo rm -f /etc/nginx/sites-enabled/default
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что конфигурация в порядке:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo nginx -t
|
|
||||||
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
|
||||||
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем нужно применить конфигурацию nginx
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo nginx -s reload
|
|
||||||
sudo systemctl status nginx
|
|
||||||
● nginx.service - A high performance web server and a reverse proxy server
|
|
||||||
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
|
|
||||||
Active: active (running) since Mon 2022-03-21 03:37:24 UTC; 6s ago
|
|
||||||
Docs: man:nginx(8)
|
|
||||||
Process: 1364 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
|
|
||||||
Process: 1367 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
|
|
||||||
Main PID: 1376 (nginx)
|
|
||||||
Tasks: 3 (limit: 1107)
|
|
||||||
Memory: 3.3M
|
|
||||||
CGroup: /system.slice/nginx.service
|
|
||||||
├─1376 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
|
|
||||||
├─1377 nginx: worker process
|
|
||||||
└─1378 nginx: worker process
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что nginx принимает соединение на порт `80`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl -v --max-time 5 http://localhost:80
|
|
||||||
* Trying 127.0.0.1:80...
|
|
||||||
* TCP_NODELAY set
|
|
||||||
* Connected to localhost (127.0.0.1) port 80 (#0)
|
|
||||||
> GET / HTTP/1.1
|
|
||||||
> Host: localhost
|
|
||||||
> User-Agent: curl/7.68.0
|
|
||||||
> Accept: */*
|
|
||||||
>
|
|
||||||
* Operation timed out after 5001 milliseconds with 0 bytes received
|
|
||||||
* Closing connection 0
|
|
||||||
curl: (28) Operation timed out after 5001 milliseconds with 0 bytes received
|
|
||||||
```
|
|
||||||
|
|
||||||
В данном случае добавили `--max-time 5`, чтобы быстрее получить ошибку, так как nginx пытается проксировать запрос на несуществующий адрес.
|
|
||||||
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 37 KiB |
@@ -1,282 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-09-security/README.md)
|
|
||||||
по теме "3.9. Элементы безопасности информационных систем".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Установите Bitwarden плагин для браузера. Зарегестрируйтесь и сохраните несколько паролей.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Установите Google authenticator на мобильный телефон. Настройте вход в Bitwarden акаунт через Google authenticator OTP.
|
|
||||||
|
|
||||||
Заместо `Google Authenticator` использовал приложение `Microsoft Authenticator`.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Установите apache2, сгенерируйте самоподписанный сертификат, настройте тестовый сайт для работы по HTTPS.
|
|
||||||
|
|
||||||
Вместо `apache2` будем производить настройку уже установленного в виртуальную машину `nginx` (установка производилась в [дз 3.8](/src/homework/03-sysadmin/3.8/readme.md#Задача 6)).
|
|
||||||
|
|
||||||
Первым шагом необходимо сгенерировать сертификат:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
||||||
-keyout /etc/ssl/private/nginx-selfsigned.key \
|
|
||||||
-out /etc/ssl/certs/nginx-selfsigned.crt \
|
|
||||||
-subj "/C=RU/ST=Moscow/L=Moscow/O=Company Name/OU=Org/CN=site.localhost"
|
|
||||||
|
|
||||||
sudo ls -lah /etc/ssl/private/ | grep nginx
|
|
||||||
-rw------- 1 root root 1.7K Mar 28 03:01 nginx-selfsigned.key
|
|
||||||
|
|
||||||
sudo ls -lah /etc/ssl/certs/ | grep nginx
|
|
||||||
-rw-r--r-- 1 root root 1.4K Mar 28 03:01 nginx-selfsigned.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
Воспользуемся [конфигуратором](https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=modern&openssl=1.1.1k&guideline=5.6),
|
|
||||||
чтобы сгенерировать основу конфигурации для сервера. Получим следующую конфигурацию, которую расположим в файле `/etc/site-available/ssl`:
|
|
||||||
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 443 ssl http2;
|
|
||||||
listen [::]:443 ssl http2;
|
|
||||||
server_name site.localhost;
|
|
||||||
|
|
||||||
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
|
|
||||||
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
|
|
||||||
ssl_session_timeout 1d;
|
|
||||||
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
|
||||||
ssl_session_tickets off;
|
|
||||||
|
|
||||||
# modern configuration
|
|
||||||
ssl_protocols TLSv1.3;
|
|
||||||
ssl_prefer_server_ciphers off;
|
|
||||||
|
|
||||||
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
|
||||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
|
||||||
|
|
||||||
# OCSP stapling
|
|
||||||
ssl_stapling on;
|
|
||||||
ssl_stapling_verify on;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
root /var/www/html;
|
|
||||||
index index.html index.htm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Переведём новую конфигурацию в боевые настройки и проверим, что всё в порядке:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo ln -s /etc/nginx/sites-available/ssl /etc/nginx/sites-enabled/ssl.conf
|
|
||||||
|
|
||||||
sudo nginx -t
|
|
||||||
nginx: [warn] "ssl_stapling" ignored, issuer certificate not found for certificate "/etc/ssl/certs/nginx-selfsigned.crt"
|
|
||||||
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
|
||||||
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
|
||||||
```
|
|
||||||
|
|
||||||
Перезапускаем сервис `nginx`, проверяем его состояние:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo service nginx reload
|
|
||||||
sudo service nginx status
|
|
||||||
service nginx status
|
|
||||||
● nginx.service - A high performance web server and a reverse proxy server
|
|
||||||
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
|
|
||||||
Active: active (running) since Mon 2022-03-28 02:53:00 UTC; 21min ago
|
|
||||||
Docs: man:nginx(8)
|
|
||||||
Process: 2256 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
|
|
||||||
Main PID: 736 (nginx)
|
|
||||||
Tasks: 3 (limit: 1107)
|
|
||||||
Memory: 13.3M
|
|
||||||
CGroup: /system.slice/nginx.service
|
|
||||||
├─ 736 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
|
|
||||||
├─2257 nginx: worker process
|
|
||||||
└─2258 nginx: worker process
|
|
||||||
```
|
|
||||||
|
|
||||||
При помощи `curl`, убедимся, что сервер работает корректно:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl https://site.localhost --resolve 'site.localhost:127.0.0.1'
|
|
||||||
curl: (60) SSL certificate problem: self signed certificate
|
|
||||||
|
|
||||||
# проигнорируем ошибки самоподписного сертификата
|
|
||||||
curl -k https://site.localhost --resolve 'site.localhost:127.0.0.1'
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Welcome to nginx!</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
width: 35em;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Welcome to nginx!</h1>
|
|
||||||
<p>If you see this page, the nginx web server is successfully installed and
|
|
||||||
working. Further configuration is required.</p>
|
|
||||||
|
|
||||||
<p>For online documentation and support please refer to
|
|
||||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
|
||||||
Commercial support is available at
|
|
||||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
|
||||||
|
|
||||||
<p><em>Thank you for using nginx.</em></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
|
|
||||||
> Проверьте на TLS уязвимости произвольный сайт в интернете
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone --depth 1 https://github.com/drwetter/testssl.sh.git
|
|
||||||
cd testssl
|
|
||||||
./testssl.sh -U --sneaky https://metagamerscore.com
|
|
||||||
|
|
||||||
Start 2022-03-28 10:31:09 -->> 217.61.246.126:443 (metagamerscore.com) <<--
|
|
||||||
|
|
||||||
rDNS (217.61.246.126): --
|
|
||||||
Service detected: HTTP
|
|
||||||
|
|
||||||
|
|
||||||
Testing vulnerabilities
|
|
||||||
|
|
||||||
Heartbleed (CVE-2014-0160) not vulnerable (OK), no heartbeat extension
|
|
||||||
CCS (CVE-2014-0224) not vulnerable (OK)
|
|
||||||
Ticketbleed (CVE-2016-9244), experiment. not vulnerable (OK)
|
|
||||||
ROBOT Server does not support any cipher suites that use RSA key transport
|
|
||||||
Secure Renegotiation (RFC 5746) supported (OK)
|
|
||||||
Secure Client-Initiated Renegotiation not vulnerable (OK)
|
|
||||||
CRIME, TLS (CVE-2012-4929) not vulnerable (OK)
|
|
||||||
BREACH (CVE-2013-3587) potentially NOT ok, "gzip" HTTP compression detected. - only supplied "/" tested
|
|
||||||
Can be ignored for static pages or if no secrets in the page
|
|
||||||
POODLE, SSL (CVE-2014-3566) not vulnerable (OK)
|
|
||||||
TLS_FALLBACK_SCSV (RFC 7507) No fallback possible (OK), no protocol below TLS 1.2 offered
|
|
||||||
SWEET32 (CVE-2016-2183, CVE-2016-6329) not vulnerable (OK)
|
|
||||||
FREAK (CVE-2015-0204) not vulnerable (OK)
|
|
||||||
DROWN (CVE-2016-0800, CVE-2016-0703) not vulnerable on this host and port (OK)
|
|
||||||
make sure you don't use this certificate elsewhere with SSLv2 enabled services
|
|
||||||
https://censys.io/ipv4?q=DA0C37574C249C089F819CDC857AFDD834D0ADA90888D97A0B81071AB288732E could help you to find out
|
|
||||||
LOGJAM (CVE-2015-4000), experimental not vulnerable (OK): no DH EXPORT ciphers, no DH key detected with <= TLS 1.2
|
|
||||||
BEAST (CVE-2011-3389) not vulnerable (OK), no SSL3 or TLS1
|
|
||||||
LUCKY13 (CVE-2013-0169), experimental not vulnerable (OK)
|
|
||||||
Winshock (CVE-2014-6321), experimental not vulnerable (OK)
|
|
||||||
RC4 (CVE-2013-2566, CVE-2015-2808) no RC4 ciphers detected (OK)
|
|
||||||
|
|
||||||
|
|
||||||
Done 2022-03-28 10:31:34 [ 27s] -->> 217.61.246.126:443 (metagamerscore.com) <<--
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 5
|
|
||||||
|
|
||||||
> Установите на Ubuntu ssh сервер, сгенерируйте новый приватный ключ. Скопируйте свой публичный ключ на другой сервер. Подключитесь к серверу по SSH-ключу.
|
|
||||||
|
|
||||||
На виртуальной машине уже установлен ssh-сервер и настроен один ssh-ключ для подключения к машине с хоста.
|
|
||||||
Таким образом сгенерируем новый ssh-ключ для пользователя `vagrant` и попробуем подключиться как пользователь `root` через ssh-сервер.
|
|
||||||
|
|
||||||
Генерация приватного и открытого ssh-ключей:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ssh-keygen
|
|
||||||
Generating public/private rsa key pair.
|
|
||||||
Enter file in which to save the key (/home/vagrant/.ssh/id_rsa):
|
|
||||||
Enter passphrase (empty for no passphrase):
|
|
||||||
Enter same passphrase again:
|
|
||||||
Your identification has been saved in /home/vagrant/.ssh/id_rsa
|
|
||||||
Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub
|
|
||||||
The key fingerprint is:
|
|
||||||
SHA256:id08L1eU83CEIr5iolPo2NKg+J7palNIO0o7D7agGuU vagrant@vagrant
|
|
||||||
The key's randomart image is:
|
|
||||||
+---[RSA 3072]----+
|
|
||||||
| ..|
|
|
||||||
| . . .o |
|
|
||||||
| . . .= .|
|
|
||||||
| . o +. . = |
|
|
||||||
|. + .. S +. . .|
|
|
||||||
| B... o o .o . |
|
|
||||||
|*+E* o o .. o |
|
|
||||||
|B*=o* o |
|
|
||||||
|**Xo . |
|
|
||||||
+----[SHA256]-----+
|
|
||||||
```
|
|
||||||
|
|
||||||
Добавим открытый ключ в файл `authorized_keys` для пользователя `root`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat .ssh/id_rsa.pub | sudo tee /root/.ssh/authorized_keys
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что всё работает:
|
|
||||||
```shell
|
|
||||||
ssh -l root 127.0.0.1
|
|
||||||
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-104-generic x86_64)
|
|
||||||
<...>
|
|
||||||
root@vagrant:~#
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 6
|
|
||||||
|
|
||||||
> Переименуйте файлы ключей из задания 5. Настройте файл конфигурации SSH клиента, так чтобы вход на удаленный сервер осуществлялся по имени сервера.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mv ~/.ssh/id_rsa ~/.ssh/localhost_key
|
|
||||||
mv ~/.ssh/id_rsa.pub ~/.ssh/localhost_key.pub
|
|
||||||
```
|
|
||||||
|
|
||||||
Добавим новую конфигурацию в файл `~/.ssh/config`:
|
|
||||||
|
|
||||||
```
|
|
||||||
host local-root
|
|
||||||
hostname 127.0.0.1
|
|
||||||
user root
|
|
||||||
identityfile ~/.ssh/localhost_key
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что всё работает:
|
|
||||||
```shell
|
|
||||||
ssh local-root
|
|
||||||
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-104-generic x86_64)
|
|
||||||
<...>
|
|
||||||
root@vagrant:~#
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 7
|
|
||||||
|
|
||||||
> Соберите дамп трафика утилитой tcpdump в формате pcap, 100 пакетов. Откройте файл pcap в Wireshark.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo tcpdump -c 100 -w dump.pcap
|
|
||||||
|
|
||||||
tcpdump -r dump.pcap
|
|
||||||
reading from file dump.pcap, link-type EN10MB (Ethernet)
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
Для просмотра полученного файла в `Wireshark`, установим утилиту на хосте:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt install wireshark
|
|
||||||
```
|
|
||||||
|
|
||||||
Теперь, скопируем файл из виртуальной машины на хост, чтобы была возможность открыть его без проблем:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
scp -P 2222 vagrant@127.0.0.1:/home/vagrant/dump.pcap ./dump.pcap
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем запустим графическое отображение утилиты и откроем в ней файл:
|
|
||||||
|
|
||||||

|
|
||||||
|
Before Width: | Height: | Size: 493 KiB |
@@ -1,119 +0,0 @@
|
|||||||
# Linux operating system
|
|
||||||
|
|
||||||
## Streams
|
|
||||||
|
|
||||||
Базовые потоки:
|
|
||||||
* `0` - stdin (`/proc/<pid>/fd/0`)
|
|
||||||
* `1` - stdout (`/proc/<pid>/fd/1`)
|
|
||||||
* `2` - stderr (`/proc/<pid>/fd/2`)
|
|
||||||
|
|
||||||
Для перенаправления потока можно использовать `X>&Y`, где `X` поток, который нужно перенаправить,
|
|
||||||
`Y` - поток, в который нужно направить данные (может быть стандартным файлом).
|
|
||||||
|
|
||||||
## Kernel
|
|
||||||
|
|
||||||
Версия ядра: `uname -r`.
|
|
||||||
Версия дистрибутива: `cat /etc/issue` (debian-based), `cat /etc/redhat-release` (centos-based).
|
|
||||||
|
|
||||||
Посмотреть всю конфигурацию системы: `sysctl -a`.
|
|
||||||
|
|
||||||
Логи системы: `dmesg`, `syslog`.
|
|
||||||
|
|
||||||
## Systemctl
|
|
||||||
|
|
||||||
* `systemctl list-units --all`
|
|
||||||
* `systemctl status <service>`
|
|
||||||
* `systemctl cat <service>` - просмотреть файл настроек сервиса
|
|
||||||
* `systemctl list-dependencies <service>`
|
|
||||||
```shell
|
|
||||||
systemctl list-dependencies docker
|
|
||||||
|
|
||||||
docker.service
|
|
||||||
● ├─containerd.service
|
|
||||||
● ├─docker.socket
|
|
||||||
● ├─system.slice
|
|
||||||
● ├─network-online.target
|
|
||||||
● │ └─NetworkManager-wait-online.service
|
|
||||||
● └─sysinit.target
|
|
||||||
● ├─apparmor.service
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
* `journalctl -f`
|
|
||||||
* `journalctl -f -u docker`
|
|
||||||
|
|
||||||
## Filesystems
|
|
||||||
|
|
||||||
* `stat <file>`
|
|
||||||
|
|
||||||
### File types
|
|
||||||
|
|
||||||
* regular file (`ls -la` - `-`)
|
|
||||||
* directory (`ls -la` - `d`)
|
|
||||||
* hardlink (`ls -la` - `l`)
|
|
||||||
|
|
||||||
1 файл - 1 hardlink
|
|
||||||
1 директрория - минимум 2 hardlink (у пустой директории - 2, +1 за каждую директорию внутри)
|
|
||||||
|
|
||||||
* symlink (`ls -la` - `l`)
|
|
||||||
* pipe (`ls -la` - `p`)
|
|
||||||
|
|
||||||
Перенаправление потоков, только однонаправленный
|
|
||||||
`mkfifo <pipe>`
|
|
||||||
|
|
||||||
* socket (`ls -la` - `s`)
|
|
||||||
|
|
||||||
Двунаправленный поток, производительнее, чем pipe. Используется для взаимодействия между процессами.
|
|
||||||
|
|
||||||
### File access
|
|
||||||
|
|
||||||
`chown`, `chmod`, `umask`
|
|
||||||
|
|
||||||
Права по умолчанию:
|
|
||||||
* `file`: `666 - umask`
|
|
||||||
* `dir`: `777 - umask`
|
|
||||||
|
|
||||||
Дополнительные права доступа:
|
|
||||||
* `sticky` - создание доступно всем, удаление только файлы пользователя
|
|
||||||
* `setuid`
|
|
||||||
* `setgid`
|
|
||||||
|
|
||||||
`lsattr`/`chattr`
|
|
||||||
|
|
||||||
### Raid
|
|
||||||
|
|
||||||
`mdadm`
|
|
||||||
|
|
||||||
### LVM
|
|
||||||
|
|
||||||
`lvs`, `vgs`, `vgdisplay`, `pvdisplay`
|
|
||||||
|
|
||||||
### Partitions
|
|
||||||
|
|
||||||
`fdisk -l`/`fdisk`, `sfdisk`
|
|
||||||
|
|
||||||
### Filesystems
|
|
||||||
|
|
||||||
`mkfs`, `mount`, `/etc/fstab`
|
|
||||||
|
|
||||||
## Network
|
|
||||||
|
|
||||||
* `ping <domain/ip>`
|
|
||||||
* `whois <ip>`
|
|
||||||
* `whois -h whois.radb.net <ip>`
|
|
||||||
* `bgpq3 -J <AS>`
|
|
||||||
* `traceroute -An <ip>`
|
|
||||||
* `mtr -zn <ip>`
|
|
||||||
* `dig +trace @8.8.8.8 <domain>`
|
|
||||||
* `dig -x <ip>`
|
|
||||||
* `telnet <domain/ip> <port>`
|
|
||||||
* `ipcalc <network ip>/<mask>`
|
|
||||||
|
|
||||||
### SSH
|
|
||||||
|
|
||||||
* `ssh-copy-id user@server` - добавление ssh-ключа на сервер для пользователя
|
|
||||||
* `ssh-keygen -F server` - проверка ssh-сертификатов сервера
|
|
||||||
* `ssh-keygen -R server` - удаление записи сервера из `known_hosts`
|
|
||||||
|
|
||||||
### Web-servers
|
|
||||||
|
|
||||||
* ssl config generation: https://ssl-config.mozilla.org/
|
|
||||||
2
src/homework/04-script/4.1/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
/curl.log
|
|
||||||
/error.log
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
a=1
|
|
||||||
b=2
|
|
||||||
c=a+b
|
|
||||||
d=$a+$b
|
|
||||||
e=$(($a+$b))
|
|
||||||
|
|
||||||
echo a=$a b=$b c=$c d=$d e=$e
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
while ((1==1))
|
|
||||||
do
|
|
||||||
curl https://localhost:4757
|
|
||||||
|
|
||||||
if (($? != 0))
|
|
||||||
then
|
|
||||||
date > curl.log;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
serverPort=80
|
|
||||||
servers=("192.168.0.1" "173.194.222.113" "87.250.250.242")
|
|
||||||
|
|
||||||
for i in {1..5}
|
|
||||||
do
|
|
||||||
for server in ${servers[@]}
|
|
||||||
do
|
|
||||||
curl --connect-timeout 3 --max-time 5 http://${server}:${serverPort}
|
|
||||||
curlResult=$?
|
|
||||||
echo "$(date) curl result for ${server} is ${curlResult}" >> curl.log;
|
|
||||||
done
|
|
||||||
done
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
serverPort=80
|
|
||||||
servers=("192.168.0.1" "173.194.222.113" "87.250.250.242")
|
|
||||||
|
|
||||||
for i in {1..5}
|
|
||||||
do
|
|
||||||
isError=0
|
|
||||||
for server in ${servers[@]}
|
|
||||||
do
|
|
||||||
curl --connect-timeout 3 --max-time 5 http://${server}:${serverPort}
|
|
||||||
curlResult=$?
|
|
||||||
echo "$(date) curl result for ${server} is ${curlResult}" >> curl.log;
|
|
||||||
if (($curlResult!=0))
|
|
||||||
then
|
|
||||||
echo ${server} > error.log
|
|
||||||
isError=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if (($isError!=0))
|
|
||||||
then
|
|
||||||
echo "going to break"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[04-script-01-bash] сломал хук слишком длинный комментарий
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
сломал хук
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[04-script-01-bash] сломал хук
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
MSG="$1"
|
|
||||||
|
|
||||||
if ! grep -qE "^\[.+\]\s.+\n{0,1}$" "$MSG"
|
|
||||||
then
|
|
||||||
cat "$MSG"
|
|
||||||
echo $'\nYour commit message must match the pattern'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msgStr=$(cat $MSG)
|
|
||||||
msgLen=${#msgStr}
|
|
||||||
if ((msgLen>50))
|
|
||||||
then
|
|
||||||
cat "$MSG"
|
|
||||||
echo $'\nYour commit message is too long'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/04-script-01-bash/README.md)
|
|
||||||
по теме "4.1. Командная оболочка Bash: Практические навыки".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
## Обязательная задача 1
|
|
||||||
|
|
||||||
Есть [скрипт](q1_script.sh):
|
|
||||||
```shell
|
|
||||||
a=1
|
|
||||||
b=2
|
|
||||||
c=a+b
|
|
||||||
d=$a+$b
|
|
||||||
e=$(($a+$b))
|
|
||||||
```
|
|
||||||
|
|
||||||
Какие значения переменным `c`,`d`,`e` будут присвоены? Почему?
|
|
||||||
|
|
||||||
| Переменная | Значение | Обоснование |
|
|
||||||
|------------|----------|--------------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| `c` | "a+b" | Присвоение обычной строки "a+b" без каких-либо преобразований, так как нет никаких спец-символов. |
|
|
||||||
| `d` | "1+2" | Конкатенация значений переменных `a` и `b` с символом "+", так как не заданы условия для произведения операции сложения. |
|
|
||||||
| `e` | "3" | Сложение значений переменных `a` и `b` используя арифметику целых чисел. |
|
|
||||||
|
|
||||||
|
|
||||||
## Обязательная задача 2
|
|
||||||
На нашем локальном сервере упал сервис и мы написали скрипт, который постоянно проверяет его доступность, записывая дату проверок до тех пор, пока сервис не станет доступным (после чего скрипт должен завершиться). В скрипте допущена ошибка, из-за которой выполнение не может завершиться, при этом место на Жёстком Диске постоянно уменьшается. Что необходимо сделать, чтобы его исправить:
|
|
||||||
```shell
|
|
||||||
while ((1==1)
|
|
||||||
do
|
|
||||||
curl https://localhost:4757
|
|
||||||
if (($? != 0))
|
|
||||||
then
|
|
||||||
date >> curl.log
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](q2_script.sh)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
while ((1==1))
|
|
||||||
do
|
|
||||||
curl https://localhost:4757
|
|
||||||
|
|
||||||
if (($? != 0))
|
|
||||||
then
|
|
||||||
date > curl.log;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
## Обязательная задача 3
|
|
||||||
Необходимо написать скрипт, который проверяет доступность трёх IP: `192.168.0.1`, `173.194.222.113`, `87.250.250.242` по `80` порту и записывает результат в файл `log`. Проверять доступность необходимо пять раз для каждого узла.
|
|
||||||
|
|
||||||
### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](q3_script.sh)
|
|
||||||
```shell
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
serverPort=80
|
|
||||||
servers=("192.168.0.1" "173.194.222.113" "87.250.250.242")
|
|
||||||
|
|
||||||
for i in {1..5}
|
|
||||||
do
|
|
||||||
for server in ${servers[@]}
|
|
||||||
do
|
|
||||||
curl --connect-timeout 3 --max-time 5 http://${server}:${serverPort}
|
|
||||||
curlResult=$?
|
|
||||||
echo "$(date) curl result for ${server} is ${curlResult}" >> curl.log;
|
|
||||||
done
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
## Обязательная задача 4
|
|
||||||
Необходимо дописать скрипт из предыдущего задания так, чтобы он выполнялся до тех пор, пока один из узлов не окажется недоступным. Если любой из узлов недоступен - IP этого узла пишется в файл error, скрипт прерывается.
|
|
||||||
|
|
||||||
### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](q4_script.sh)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
serverPort=80
|
|
||||||
servers=("192.168.0.1" "173.194.222.113" "87.250.250.242")
|
|
||||||
|
|
||||||
for i in {1..5}
|
|
||||||
do
|
|
||||||
isError=0
|
|
||||||
for server in ${servers[@]}
|
|
||||||
do
|
|
||||||
curl --connect-timeout 3 --max-time 5 http://${server}:${serverPort}
|
|
||||||
curlResult=$?
|
|
||||||
echo "$(date) curl result for ${server} is ${curlResult}" >> curl.log;
|
|
||||||
if (($curlResult!=0))
|
|
||||||
then
|
|
||||||
echo ${server} > error.log
|
|
||||||
isError=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if (($isError!=0))
|
|
||||||
then
|
|
||||||
echo "going to break"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
## Дополнительное задание (со звездочкой*) - необязательно к выполнению
|
|
||||||
|
|
||||||
Мы хотим, чтобы у нас были красивые сообщения для коммитов в репозиторий. Для этого нужно написать локальный хук для git, который будет проверять,
|
|
||||||
что сообщение в коммите содержит код текущего задания в квадратных скобках и количество символов в сообщении не превышает 30.
|
|
||||||
Пример сообщения: \[04-script-01-bash\] сломал хук.
|
|
||||||
|
|
||||||
### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](q5_script.sh)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
MSG="$1"
|
|
||||||
|
|
||||||
if ! grep -qE "^\[.+\]\s.+\n{0,1}$" "$MSG"
|
|
||||||
then
|
|
||||||
cat "$MSG"
|
|
||||||
echo $'\nYour commit message must match the pattern'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msgStr=$(cat $MSG)
|
|
||||||
msgLen=${#msgStr}
|
|
||||||
if ((msgLen>50))
|
|
||||||
then
|
|
||||||
cat "$MSG"
|
|
||||||
echo $'\nYour commit message is too long'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
Протестировал запуск скрипта следующими способами:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# несоответствие паттерну
|
|
||||||
./q5_script.sh q5_example_bad_pattern.txt
|
|
||||||
# несоответствие длины
|
|
||||||
./q5_script.sh q5_example_bad_lenght.txt
|
|
||||||
# корректное сообщение
|
|
||||||
./q5_script.sh q5_example_good.txt
|
|
||||||
```
|
|
||||||
1
src/homework/04-script/4.2/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
hosts.json
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
a = 1
|
|
||||||
b = '2'
|
|
||||||
c = a + b
|
|
||||||
|
|
||||||
print(a, b, c)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
a = '1'
|
|
||||||
b = '2'
|
|
||||||
c = a + b
|
|
||||||
|
|
||||||
print(a, b, c)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
a = 1
|
|
||||||
b = 2
|
|
||||||
c = a + b
|
|
||||||
|
|
||||||
print(a, b, c)
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
cd_command = "cd ~/netology/sysadm-homeworks"
|
|
||||||
bash_command = [cd_command, "git status"]
|
|
||||||
top_level_command = [cd_command, "git rev-parse --show-toplevel"]
|
|
||||||
top_level = os.popen(' && '.join(top_level_command)).read().replace('\n', '')
|
|
||||||
result_os = os.popen(' && '.join(bash_command)).read()
|
|
||||||
for result in result_os.split('\n'):
|
|
||||||
if result.find('modified') != -1:
|
|
||||||
prepare_result = result.replace('\tmodified: ', '')
|
|
||||||
full_path = top_level + '/' + prepare_result
|
|
||||||
print(full_path)
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
repo_path = sys.argv[1]
|
|
||||||
|
|
||||||
if repo_path == '':
|
|
||||||
print('необходимо указать путь до локального репозитория')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# запускаем под-процесс в рабочей директории (cwd)
|
|
||||||
top_level_command = subprocess.Popen(
|
|
||||||
['git rev-parse --show-toplevel'],
|
|
||||||
cwd=repo_path,
|
|
||||||
shell=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
# ожидаем выполнение под-процесса
|
|
||||||
top_level_command.wait()
|
|
||||||
if top_level_command.returncode != 0:
|
|
||||||
print('директория {} не является git-репозиторием'.format(repo_path))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# на выходе у read() идёт последовательность байт, которые необходимо декодировать в строку
|
|
||||||
top_level_path = top_level_command.stdout.read().decode("utf-8").rstrip()
|
|
||||||
|
|
||||||
bash_command = ['cd ' + top_level_path, "git status"]
|
|
||||||
|
|
||||||
result_os = os.popen(' && '.join(bash_command)).read()
|
|
||||||
|
|
||||||
for result in result_os.split('\n'):
|
|
||||||
if result.find('modified') != -1:
|
|
||||||
prepare_result = result.replace('\tmodified: ', '')
|
|
||||||
full_path = top_level_path + '/' + prepare_result
|
|
||||||
print(full_path)
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import json
|
|
||||||
import io
|
|
||||||
import socket
|
|
||||||
|
|
||||||
filename = 'hosts.json'
|
|
||||||
|
|
||||||
hostsList = {
|
|
||||||
"drive.google.com",
|
|
||||||
"mail.google.com",
|
|
||||||
"google.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
with open(filename, 'r+') as file:
|
|
||||||
jsonStr = file.read()
|
|
||||||
try:
|
|
||||||
jsonObj = json.load(io.StringIO(jsonStr))
|
|
||||||
except BaseException as err:
|
|
||||||
jsonObj = dict({})
|
|
||||||
print('error {}'.format(err))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
file.truncate(0)
|
|
||||||
file.seek(0)
|
|
||||||
|
|
||||||
for hostname in hostsList:
|
|
||||||
ipAddr = socket.gethostbyname(hostname)
|
|
||||||
prevIpAddr = jsonObj.get(hostname)
|
|
||||||
|
|
||||||
if prevIpAddr is None or prevIpAddr == '':
|
|
||||||
prevIpAddr = ipAddr
|
|
||||||
|
|
||||||
print('{} - {}'.format(hostname, ipAddr))
|
|
||||||
if ipAddr != prevIpAddr:
|
|
||||||
print('[ERROR] {} IP mismatch: {} {}'.format(hostname, ipAddr, prevIpAddr))
|
|
||||||
|
|
||||||
jsonObj[hostname] = ipAddr
|
|
||||||
|
|
||||||
file.write(json.dumps(jsonObj))
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/04-script-02-py/README.md)
|
|
||||||
по теме "4.2. Использование Python для решения типовых DevOps задач".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Обязательная задача 1
|
|
||||||
|
|
||||||
Есть скрипт:
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
a = 1
|
|
||||||
b = '2'
|
|
||||||
c = a + b
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Вопросы:
|
|
||||||
| Вопрос | Ответ |
|
|
||||||
|------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| Какое значение будет присвоено переменной `c`? | Переменной не будет присвоено никакое значение, потому что производится сложение целого числа и строки, при этом будет инициировано исключение `TypeError: unsupported operand type(s) for +: 'int' and 'str'` |
|
|
||||||
| Как получить для переменной `c` значение 12? | Для этого необходимо присвоить переменной `a` строковое значение `'1'`, чтобы была произведена конкатенация строк. [script](./q1_2.py) |
|
|
||||||
| Как получить для переменной `c` значение 3? | Для этого необходимо присвоить переменной `b` целочисленное значение `2` (без кавычек). [script](./q1_3.py) |
|
|
||||||
|
|
||||||
### Обязательная задача 2
|
|
||||||
Мы устроились на работу в компанию, где раньше уже был DevOps Engineer. Он написал скрипт, позволяющий узнать, какие файлы модифицированы в репозитории, относительно локальных изменений. Этим скриптом недовольно начальство, потому что в его выводе есть не все изменённые файлы, а также непонятен полный путь к директории, где они находятся. Как можно доработать скрипт ниже, чтобы он исполнял требования вашего руководителя?
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
bash_command = ["cd ~/netology/sysadm-homeworks", "git status"]
|
|
||||||
result_os = os.popen(' && '.join(bash_command)).read()
|
|
||||||
is_change = False
|
|
||||||
for result in result_os.split('\n'):
|
|
||||||
if result.find('modified') != -1:
|
|
||||||
prepare_result = result.replace('\tmodified: ', '')
|
|
||||||
print(prepare_result)
|
|
||||||
break
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](./q2.py)
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
cd_command = "cd ~/netology/sysadm-homeworks"
|
|
||||||
bash_command = [cd_command, "git status"]
|
|
||||||
top_level_command = [cd_command, "git rev-parse --show-toplevel"]
|
|
||||||
top_level = os.popen(' && '.join(top_level_command)).read().replace('\n', '')
|
|
||||||
result_os = os.popen(' && '.join(bash_command)).read()
|
|
||||||
for result in result_os.split('\n'):
|
|
||||||
if result.find('modified') != -1:
|
|
||||||
prepare_result = result.replace('\tmodified: ', '')
|
|
||||||
full_path = top_level + '/' + prepare_result
|
|
||||||
print(full_path)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Вывод скрипта при запуске при тестировании:
|
|
||||||
|
|
||||||
_note_: при запуске скрипта изменил путь до репозитория.
|
|
||||||
```
|
|
||||||
./q2.py
|
|
||||||
/home/dannc/code/learning/netology/readme.md
|
|
||||||
/home/dannc/code/learning/netology/src/homework/04-script/4.2/q1_2.py
|
|
||||||
/home/dannc/code/learning/netology/src/homework/04-script/4.2/q1_3.py
|
|
||||||
/home/dannc/code/learning/netology/src/homework/04-script/4.2/q2.py
|
|
||||||
/home/dannc/code/learning/netology/src/homework/04-script/4.2/readme.md
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Обязательная задача 3
|
|
||||||
1. Доработать скрипт выше так, чтобы он мог проверять не только локальный репозиторий в текущей директории, а также умел воспринимать путь к репозиторию, который мы передаём как входной параметр. Мы точно знаем, что начальство коварное и будет проверять работу этого скрипта в директориях, которые не являются локальными репозиториями.
|
|
||||||
|
|
||||||
#### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](./q3.py)
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
repo_path = sys.argv[1]
|
|
||||||
|
|
||||||
if repo_path == '':
|
|
||||||
print('необходимо указать путь до локального репозитория')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# запускаем под-процесс в рабочей директории (cwd)
|
|
||||||
top_level_command = subprocess.Popen(
|
|
||||||
['git rev-parse --show-toplevel'],
|
|
||||||
cwd=repo_path,
|
|
||||||
shell=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
# ожидаем выполнение под-процесса
|
|
||||||
top_level_command.wait()
|
|
||||||
if top_level_command.returncode != 0:
|
|
||||||
print('директория {} не является git-репозиторием'.format(repo_path))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# на выходе у read() идёт последовательность байт, которые необходимо декодировать в строку
|
|
||||||
top_level_path = top_level_command.stdout.read().decode("utf-8").rstrip()
|
|
||||||
|
|
||||||
bash_command = ['cd ' + top_level_path, "git status"]
|
|
||||||
|
|
||||||
result_os = os.popen(' && '.join(bash_command)).read()
|
|
||||||
|
|
||||||
for result in result_os.split('\n'):
|
|
||||||
if result.find('modified') != -1:
|
|
||||||
prepare_result = result.replace('\tmodified: ', '')
|
|
||||||
full_path = top_level_path + '/' + prepare_result
|
|
||||||
print(full_path)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Вывод скрипта при запуске при тестировании:
|
|
||||||
```
|
|
||||||
./q3.py ~/code/learning/netology
|
|
||||||
/home/dannc/code/learning/netology/src/homework/04-script/4.2/q3.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### Обязательная задача 4
|
|
||||||
Наша команда разрабатывает несколько веб-сервисов, доступных по http.
|
|
||||||
Мы точно знаем, что на их стенде нет никакой балансировки, кластеризации, за DNS прячется конкретный IP сервера,
|
|
||||||
где установлен сервис. Проблема в том, что отдел, занимающийся нашей инфраструктурой очень часто меняет нам сервера,
|
|
||||||
поэтому IP меняются примерно раз в неделю, при этом сервисы сохраняют за собой DNS имена.
|
|
||||||
Это бы совсем никого не беспокоило, если бы несколько раз сервера не уезжали в такой сегмент сети нашей компании,
|
|
||||||
который недоступен для разработчиков. Мы хотим написать скрипт, который опрашивает веб-сервисы, получает их IP,
|
|
||||||
выводит информацию в стандартный вывод в виде: <URL сервиса> - <его IP>.
|
|
||||||
Также, должна быть реализована возможность проверки текущего IP сервиса c его IP из предыдущей проверки.
|
|
||||||
Если проверка будет провалена - оповестить об этом в стандартный вывод сообщением: [ERROR] <URL сервиса> IP mismatch: <старый IP> <Новый IP>.
|
|
||||||
Будем считать, что наша разработка реализовала сервисы: `drive.google.com`, `mail.google.com`, `google.com`.
|
|
||||||
|
|
||||||
#### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](./q4.py)
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import json
|
|
||||||
import io
|
|
||||||
import socket
|
|
||||||
|
|
||||||
filename = 'hosts.json'
|
|
||||||
|
|
||||||
hostsList = {
|
|
||||||
"drive.google.com",
|
|
||||||
"mail.google.com",
|
|
||||||
"google.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
with open(filename, 'r+') as file:
|
|
||||||
jsonStr = file.read()
|
|
||||||
try:
|
|
||||||
jsonObj = json.load(io.StringIO(jsonStr))
|
|
||||||
except BaseException as err:
|
|
||||||
jsonObj = dict({})
|
|
||||||
print('error {}'.format(err))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
file.truncate(0)
|
|
||||||
file.seek(0)
|
|
||||||
|
|
||||||
for hostname in hostsList:
|
|
||||||
ipAddr = socket.gethostbyname(hostname)
|
|
||||||
prevIpAddr = jsonObj.get(hostname)
|
|
||||||
|
|
||||||
if prevIpAddr is None or prevIpAddr == '':
|
|
||||||
prevIpAddr = ipAddr
|
|
||||||
|
|
||||||
print('{} - {}'.format(hostname, ipAddr))
|
|
||||||
if ipAddr != prevIpAddr:
|
|
||||||
print('[ERROR] {} IP mismatch: {} {}'.format(hostname, ipAddr, prevIpAddr))
|
|
||||||
|
|
||||||
jsonObj[hostname] = ipAddr
|
|
||||||
|
|
||||||
file.write(json.dumps(jsonObj))
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Вывод скрипта при запуске при тестировании:
|
|
||||||
|
|
||||||
Предположим, что в какой-то момент времени были следующие значения ip-адресов серверов:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"drive.google.com": "173.194.221.194", "mail.google.com": "142.251.1.18", "google.com": "64.233.162.139"}
|
|
||||||
```
|
|
||||||
|
|
||||||
Тогда запуск команды будет выглядеть следующим образом:
|
|
||||||
|
|
||||||
```
|
|
||||||
./q4.py
|
|
||||||
mail.google.com - 173.194.221.17
|
|
||||||
[ERROR] mail.google.com IP mismatch: 173.194.221.17 142.251.1.18
|
|
||||||
google.com - 64.233.162.100
|
|
||||||
[ERROR] google.com IP mismatch: 64.233.162.100 64.233.162.139
|
|
||||||
drive.google.com - 173.194.221.194
|
|
||||||
```
|
|
||||||
2
src/homework/04-script/4.3/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
hosts.json
|
|
||||||
hosts.yaml
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import json
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
hosts_list = {
|
|
||||||
"drive.google.com",
|
|
||||||
"mail.google.com",
|
|
||||||
"google.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
filename_json = 'hosts.json'
|
|
||||||
filename_yaml = 'hosts.yaml'
|
|
||||||
|
|
||||||
if not os.path.exists(filename_json):
|
|
||||||
os.mknod(filename_json)
|
|
||||||
|
|
||||||
if not os.path.exists(filename_yaml):
|
|
||||||
os.mknod(filename_yaml)
|
|
||||||
|
|
||||||
file_json = None
|
|
||||||
file_yaml = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
file_json = open(filename_json, 'r+')
|
|
||||||
file_yaml = open(filename_yaml, 'r+')
|
|
||||||
|
|
||||||
json_str = file_json.read()
|
|
||||||
try:
|
|
||||||
json_obj = json.load(io.StringIO(json_str))
|
|
||||||
except BaseException as err:
|
|
||||||
json_obj = dict({})
|
|
||||||
print('error: {}'.format(err))
|
|
||||||
|
|
||||||
for hostname in hosts_list:
|
|
||||||
ip_addr = socket.gethostbyname(hostname)
|
|
||||||
prev_ip_addr = json_obj.get(hostname)
|
|
||||||
|
|
||||||
if prev_ip_addr is None or prev_ip_addr == '':
|
|
||||||
prev_ip_addr = ip_addr
|
|
||||||
|
|
||||||
print('{} - {}'.format(hostname, ip_addr))
|
|
||||||
if ip_addr != prev_ip_addr:
|
|
||||||
print('[ERROR] {} IP mismatch: {} {}'.format(hostname, ip_addr, prev_ip_addr))
|
|
||||||
|
|
||||||
json_obj[hostname] = ip_addr
|
|
||||||
|
|
||||||
file_json.truncate(0)
|
|
||||||
file_json.seek(0)
|
|
||||||
file_json.write(json.dumps(json_obj))
|
|
||||||
|
|
||||||
file_yaml.truncate(0)
|
|
||||||
file_yaml.seek(0)
|
|
||||||
file_yaml.write(yaml.dump(json_obj))
|
|
||||||
except BaseException as err:
|
|
||||||
print('error {}'.format(err))
|
|
||||||
finally:
|
|
||||||
if file_json is not None:
|
|
||||||
file_json.close()
|
|
||||||
|
|
||||||
if file_yaml is not None:
|
|
||||||
file_yaml.close()
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/04-script-03-yaml/README.md)
|
|
||||||
по теме "4.3. Языки разметки JSON и YAML".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Обязательная задача 1
|
|
||||||
|
|
||||||
Мы выгрузили JSON, который получили через API запрос к нашему сервису:
|
|
||||||
|
|
||||||
```
|
|
||||||
{ "info" : "Sample JSON output from our service\t",
|
|
||||||
"elements" :[
|
|
||||||
{ "name" : "first",
|
|
||||||
"type" : "server",
|
|
||||||
"ip" : 7175
|
|
||||||
}
|
|
||||||
{ "name" : "second",
|
|
||||||
"type" : "proxy",
|
|
||||||
"ip : 71.78.22.43
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Нужно найти и исправить все ошибки, которые допускает наш сервис.
|
|
||||||
|
|
||||||
Решение:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"info": "Sample JSON output from our service\t",
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"name": "first",
|
|
||||||
"type": "server",
|
|
||||||
"ip": 7175
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "second",
|
|
||||||
"type": "proxy",
|
|
||||||
"ip": "71.78.22.43"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Обязательная задача 2
|
|
||||||
|
|
||||||
В прошлый рабочий день мы создавали скрипт, позволяющий опрашивать веб-сервисы и получать их IP.
|
|
||||||
К уже реализованному функционалу нам нужно добавить возможность записи JSON и YAML файлов, описывающих наши сервисы.
|
|
||||||
Формат записи JSON по одному сервису: `{ "имя сервиса" : "его IP"}`.
|
|
||||||
Формат записи YAML по одному сервису: `- имя сервиса: его IP`.
|
|
||||||
Если в момент исполнения скрипта меняется IP у сервиса - он должен так же поменяться в yml и json файле.
|
|
||||||
|
|
||||||
#### Ваш скрипт:
|
|
||||||
|
|
||||||
[script](./q2.py)
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import json
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
hosts_list = {
|
|
||||||
"drive.google.com",
|
|
||||||
"mail.google.com",
|
|
||||||
"google.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
filename_json = 'hosts.json'
|
|
||||||
filename_yaml = 'hosts.yaml'
|
|
||||||
|
|
||||||
if not os.path.exists(filename_json):
|
|
||||||
os.mknod(filename_json)
|
|
||||||
|
|
||||||
if not os.path.exists(filename_yaml):
|
|
||||||
os.mknod(filename_yaml)
|
|
||||||
|
|
||||||
file_json = None
|
|
||||||
file_yaml = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
file_json = open(filename_json, 'r+')
|
|
||||||
file_yaml = open(filename_yaml, 'r+')
|
|
||||||
|
|
||||||
json_str = file_json.read()
|
|
||||||
try:
|
|
||||||
json_obj = json.load(io.StringIO(json_str))
|
|
||||||
except BaseException as err:
|
|
||||||
json_obj = dict({})
|
|
||||||
print('error: {}'.format(err))
|
|
||||||
|
|
||||||
for hostname in hosts_list:
|
|
||||||
ip_addr = socket.gethostbyname(hostname)
|
|
||||||
prev_ip_addr = json_obj.get(hostname)
|
|
||||||
|
|
||||||
if prev_ip_addr is None or prev_ip_addr == '':
|
|
||||||
prev_ip_addr = ip_addr
|
|
||||||
|
|
||||||
print('{} - {}'.format(hostname, ip_addr))
|
|
||||||
if ip_addr != prev_ip_addr:
|
|
||||||
print('[ERROR] {} IP mismatch: {} {}'.format(hostname, ip_addr, prev_ip_addr))
|
|
||||||
|
|
||||||
json_obj[hostname] = ip_addr
|
|
||||||
|
|
||||||
file_json.truncate(0)
|
|
||||||
file_json.seek(0)
|
|
||||||
file_json.write(json.dumps(json_obj))
|
|
||||||
|
|
||||||
file_yaml.truncate(0)
|
|
||||||
file_yaml.seek(0)
|
|
||||||
file_yaml.write(yaml.dump(json_obj))
|
|
||||||
except BaseException as err:
|
|
||||||
print('error {}'.format(err))
|
|
||||||
finally:
|
|
||||||
if file_json is not None:
|
|
||||||
file_json.close()
|
|
||||||
|
|
||||||
if file_yaml is not None:
|
|
||||||
file_yaml.close()
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Вывод скрипта при запуске при тестировании:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./q2.py
|
|
||||||
error: Expecting value: line 1 column 1 (char 0)
|
|
||||||
mail.google.com - 64.233.162.17
|
|
||||||
google.com - 74.125.205.102
|
|
||||||
drive.google.com - 142.250.150.194
|
|
||||||
```
|
|
||||||
|
|
||||||
#### json-файл(ы), который(е) записал ваш скрипт:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"mail.google.com": "64.233.162.17", "google.com": "74.125.205.102", "drive.google.com": "142.250.150.194"}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### yml-файл(ы), который(е) записал ваш скрипт:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
drive.google.com: 142.250.150.194
|
|
||||||
google.com: 74.125.205.102
|
|
||||||
mail.google.com: 64.233.162.17
|
|
||||||
```
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# Script languages
|
|
||||||
|
|
||||||
## Bash
|
|
||||||
|
|
||||||
* замена значения переменной
|
|
||||||
|
|
||||||
```shell
|
|
||||||
a=1234
|
|
||||||
a=${a/12/FOO}
|
|
||||||
echo $a
|
|
||||||
FOO34
|
|
||||||
```
|
|
||||||
|
|
||||||
* объявление и вывод массива
|
|
||||||
|
|
||||||
```shell
|
|
||||||
arrayInt=(1 2 3 4 5)
|
|
||||||
# первый элемент
|
|
||||||
echo $arrayInt
|
|
||||||
1
|
|
||||||
# все элементы
|
|
||||||
echo ${arrayInt[@]}
|
|
||||||
1 2 3 4 5
|
|
||||||
# конкретный элемент
|
|
||||||
echo ${arrayInt[3]}
|
|
||||||
4
|
|
||||||
# индексы
|
|
||||||
echo ${!arrayInt[@]}
|
|
||||||
# размерность
|
|
||||||
echo ${#arrayInt[@]}
|
|
||||||
# присвоение массива из команды
|
|
||||||
arrayLs=($(ls))
|
|
||||||
# добавление элементов в конец массива
|
|
||||||
arrayInt+=(12 123 13)
|
|
||||||
```
|
|
||||||
|
|
||||||
* Разделитель значений для bash
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo $IFS
|
|
||||||
export IFS=;
|
|
||||||
unset IFS
|
|
||||||
```
|
|
||||||
|
|
||||||
## YAML
|
|
||||||
|
|
||||||
* Типы данных
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
root:
|
|
||||||
emptyValue:
|
|
||||||
booleanTrue: true
|
|
||||||
booleanFalse: false
|
|
||||||
canonTime: 2020-12-15T00:30:44.1Z
|
|
||||||
date: 2020-12-15
|
|
||||||
list:
|
|
||||||
- one
|
|
||||||
- two
|
|
||||||
- three
|
|
||||||
- name: one
|
|
||||||
type: two
|
|
||||||
default: true
|
|
||||||
using: [ localhost, 7.7.7.7 ]
|
|
||||||
```
|
|
||||||
|
|
||||||
* Многострочные значения в ключе
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
root:
|
|
||||||
first:|
|
|
||||||
Этот вид
|
|
||||||
сохранит все переходы на новую строку
|
|
||||||
second:>
|
|
||||||
А этот
|
|
||||||
преобразует каждый переход на новую строку
|
|
||||||
в пробел
|
|
||||||
```
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/virt-homeworks/blob/virt-11/05-virt-01-basics/README.md)
|
|
||||||
по теме "5.1. Основы виртуализации".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Опишите кратко, как вы поняли: в чем основное отличие полной (аппаратной) виртуализации, паравиртуализации и виртуализации на основе ОС.
|
|
||||||
|
|
||||||
Главное отличие данных типов вирутализации в том, как именно ОС внутри виртуальной машины взаимодействует с реальным аппаратным комплексом:
|
|
||||||
1. Полной (аппаратная) виртуализация - это полноценная операционная система, которая имеет непосредственный доступ к "железу".
|
|
||||||
2. Паравиртуализация реализует взаимодействие через прослойку-гипервизор, которая имеет специальное API для гостевой ОС,
|
|
||||||
но при этом обращается к аппаратной части через ядро хостовой операционной системы.
|
|
||||||
3. Виртуализации на основе ОС реализует непосредственное взаимодействие гостевой ОС через системные вызовы ядра хостовой операционной системы
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Выберите один из вариантов использования организации физических серверов, в зависимости от условий использования.
|
|
||||||
>
|
|
||||||
> Организация серверов:
|
|
||||||
> * физические сервера
|
|
||||||
> * паравиртуализация
|
|
||||||
> * виртуализация уровня ОС
|
|
||||||
>
|
|
||||||
> Условия использования:
|
|
||||||
> * Высоконагруженная база данных, чувствительная к отказу
|
|
||||||
> * Различные web-приложения
|
|
||||||
> * Windows системы для использования бухгалтерским отделом
|
|
||||||
> * Системы, выполняющие высокопроизводительные расчеты на GPU
|
|
||||||
>
|
|
||||||
> Опишите, почему вы выбрали к каждому целевому использованию такую организацию.
|
|
||||||
|
|
||||||
1. Высоконагруженная база данных, чувствительная к отказу
|
|
||||||
|
|
||||||
Для данной задачи лучше всего подойдут физические сервера. Это объясняется тем, что любая виртуализация накладывает дополнительные
|
|
||||||
риски на стабильность работы системы. При этом во взаимодействии между гостевой ОС и хостом есть дополнительные расходы,
|
|
||||||
что тоже может быть очень критично в высоконагруженных системах.
|
|
||||||
|
|
||||||
2. Различные web-приложения
|
|
||||||
|
|
||||||
В данном случае лучше всего использовать виртуализацию уровня операционной системы. Это обосновано тем,
|
|
||||||
что по задаче приложения имеют различное назначение (нет уточнений про отказоусточивость, ожидаемую нагрузку, скалируемость и т.п.).
|
|
||||||
При этом они должны запускаться в определённом окружении (желательно одинаковым для каждого приложения),
|
|
||||||
а для безопасности, данные приложения должны быть изолированы. Таким образом вируализация уровня ОС подходит под данную задачу.
|
|
||||||
|
|
||||||
3. Windows системы для использования бухгалтерским отделом
|
|
||||||
|
|
||||||
В данном случае лучше всего будет использовать паравиртуализацию,
|
|
||||||
что обеспечит изолированность систем с минимальной потерей скорости взаимодействия пользователей с системами.
|
|
||||||
|
|
||||||
4. Системы, выполняющие высокопроизводительные расчеты на GPU
|
|
||||||
|
|
||||||
Для данной задачи лучше всего будет использовать физические сервера, так как не все гипервизоры для паравиртуализации имеют поддержку GPU,
|
|
||||||
а некоторые поддерживают GPU только определённых вендоров/моделей. Вирутализация уровня ОС здесь только помешает,
|
|
||||||
так как добавляет дополнительные расходы на взаимодействие виртуальной машины и хоста.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Выберите подходящую систему управления виртуализацией для предложенного сценария. Детально опишите ваш выбор.
|
|
||||||
|
|
||||||
1. 100 виртуальных машин на базе `Linux` и `Windows`, общие задачи, нет особых требований. Преимущественно `Windows` based инфраструктура, требуется реализация программных балансировщиков нагрузки, репликации данных и автоматизированного механизма создания резервных копий.
|
|
||||||
|
|
||||||
Для данного сценария наиболее предпочтительно будет использование решение `Microsoft Hyper-V`. Выбор обсловлен следующими факторами:
|
|
||||||
* `Преимущественно Windows based инфраструктура`, а значит лучшим выбором здесь будет решение, которое нативно умеет поддерживать данную ОС.
|
|
||||||
При этом, `Hyper-V` имеет поддержку и [Linux-систем](https://www.windowscentral.com/how-run-linux-distros-windows-10-using-hyper-v).
|
|
||||||
* "Из коробки" имеет поддержку репликации и миграции виртуальных машин, а значит подходит под требование резервного копирования и балансировки нагрузки.
|
|
||||||
* Так как больше нет никаких особых требований, то в этом случае более низкий порог вхождения для инженеров в данную технологию будет плюсом.
|
|
||||||
|
|
||||||
2. Требуется наиболее производительное бесплатное open source решение для виртуализации небольшой (20-30 серверов) инфраструктуры на базе Linux и Windows виртуальных машин.
|
|
||||||
|
|
||||||
В данном сценарии наиболее подходящей технологией является `Xen`:
|
|
||||||
* `Xen` - это open source решение.
|
|
||||||
* Имеет поддержку гостевых ОС как `Linux`, так и `Windows`. Для каждого типа ОС есть свой оптимальный режим виртуализации.
|
|
||||||
Данные режимы можно использовать одновременно на одном хосте.
|
|
||||||
* Имеет высокую производительность.
|
|
||||||
* Каждая виртуальная машина утилизирует только точно выделенные ресурсы без влияния на производительность других соседних виртуальных машин.
|
|
||||||
Подобная проблема есть в `KVM`, поэтому здесь предпочтение отдаётся `Xen`.
|
|
||||||
|
|
||||||
3. Необходимо бесплатное, максимально совместимое и производительное решение для виртуализации Windows инфраструктуры.
|
|
||||||
|
|
||||||
В данном случае стоит использовать `Microsoft Hyper-V Server`:
|
|
||||||
* Является бесплатной операционной системой
|
|
||||||
* Разработан для нативной поддержки виртуальных машин на базе Windows, а значит имеет максимальную совместимость и производительность для текущих потребностей.
|
|
||||||
|
|
||||||
4. Необходимо рабочее окружение для тестирования программного продукта на нескольких дистрибутивах `Linux`.
|
|
||||||
|
|
||||||
Для данного сценария подойдёт `KVM`. Из плюсов этого выбора можно выделить:
|
|
||||||
* Хорошая поддержка `Linux` в качестве гостевых ОС
|
|
||||||
* Близкая к нативной производительность, что полезно для тестирования, так как минимизирует различные накладные расходы на взаимодействие с виртуальной машиной.
|
|
||||||
* Есть возможность построить мониторинг всех виртуальных машин для тестов на хосте, то есть считывать различные метрики приложений из хостовой ОС.
|
|
||||||
* В моём понимании тестирование продукта - это краткосрочный процесс, который предполагает,
|
|
||||||
что виртуальная машина поднимается на короткий срок, и после окончания тестирования удаляется.
|
|
||||||
Исходя из этого понимания, появляется преимущество в виде создания шаблонов виртуальных машин для тестирования в формате ISO-образа,
|
|
||||||
которые могут использоваться как для развёртывания ВМ внутри стенда, так для использования людьми (например, специалистами QA-отдела или разработки).
|
|
||||||
|
|
||||||
### Задача 4
|
|
||||||
> Опишите возможные проблемы и недостатки гетерогенной среды виртуализации (использования нескольких систем управления виртуализацией одновременно) и что необходимо сделать для минимизации этих рисков и проблем.
|
|
||||||
|
|
||||||
Самая большая проблема гетерогенной среды виртуализации - это высокие расходы на поддержку и управления нескольких систем управления виртуальными машинами одновременно.
|
|
||||||
То есть, для подобного решения необходимо сразу несколько инженеров, которые будут специалистами в своей конкретной области/технологии.
|
|
||||||
|
|
||||||
Ещё одна проблема, которая может возникнуть - проблемы перемещения данных между виртуальными машинами, работающими в разных гипервизорах.
|
|
||||||
|
|
||||||
Для минимизации проблем, в общем случае, необходимо стараться максимально стандартизировать подход к виртуализации внутри компании.
|
|
||||||
|
|
||||||
> Если бы у вас был выбор, то создавали бы вы гетерогенную среду или нет? Мотивируйте ваш ответ примерами.
|
|
||||||
|
|
||||||
Для выбора решения необходимо на этапе построения всей инфраструктуры решить множество вопросов:
|
|
||||||
* определить, какие решения есть на рынке виртуализаций и сделать некие прогнозы на будущее
|
|
||||||
* сделать анализ рынка вакансий, определить "популярность" решений вирутализации
|
|
||||||
* определить конкретные требования к инфрастуктуре: какие системы/сервисы будут разворачиваться на виртуальных машинах,
|
|
||||||
кто будет пользовать данными системами и т.п.
|
|
||||||
* определить требования к безопасности
|
|
||||||
|
|
||||||
Только после ответа на данные вопросы можно решить, использовать ли единое решение для построения виртуализации, либо совместить решения.
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/virt-homeworks/blob/virt-11/05-virt-02-iaac/README.md)
|
|
||||||
по теме "5.2. Применение принципов IaaC в работе с виртуальными машинами".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
> Опишите своими словами основные преимущества применения на практике IaaC паттернов.
|
|
||||||
|
|
||||||
Основные преимущества применения IaaC паттернов:
|
|
||||||
1. Хранение всей конфигурации инфраструктуры под системой контроля версий. Это даёт множество приемуществ:
|
|
||||||
1. Версионирование конфигурации, что позволяет сравнивать версии, видеть развитие, отлавливать ошибки на код-ревью.
|
|
||||||
2. Хранение конфигурации в централизованном хранилище (например, `github`/`gitlab`/`bitbucket`)
|
|
||||||
3. Возможность коллаборации инженеров в работе над конфигурацией. То есть, возможность одновременно вносить доработки
|
|
||||||
в одну часть инфраструктуры одним человеком, и добавлять новые сервисы другим.
|
|
||||||
2. Возможность "прочитать" конфигурацию, чтобы понять, как она работает, а не выяснять это опытным путём.
|
|
||||||
3. Возможность тестирования конфигурации.
|
|
||||||
4. Возможность автоматизировать частично или полностью применение конфигурации к инфраструктуре.
|
|
||||||
|
|
||||||
> Какой из принципов IaaC является основополагающим?
|
|
||||||
|
|
||||||
Основополагающий принцип IaaC - это идемпотентность. То есть, применяя готовую конфигурацию к инфраструктуре
|
|
||||||
(например, развёртывание виртуальных машин) инженер будет получать один и тот же ожидаемый результат, который не будет меняться,
|
|
||||||
сколько бы попыток не было.
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Чем Ansible выгодно отличается от других систем управление конфигурациями?
|
|
||||||
|
|
||||||
Самое главное преимущество `ansible` - это необходимость установки утилиты только на машине,
|
|
||||||
откуда необходимо запустить применение конфигурации. То есть, на физических/виртуальных машинах, где будут происходить действия
|
|
||||||
по настройке никаких дополнительных утилит устанавливать не нужно.
|
|
||||||
|
|
||||||
> Какой, на ваш взгляд, метод работы систем конфигурации более надёжный push или pull?
|
|
||||||
|
|
||||||
Принцип `push` более надёжный, так как для данного метода не нужно держать активным некий сервис,
|
|
||||||
который будет принимать и обрабатывать запросы клиентов на обновление конфигурации.
|
|
||||||
|
|
||||||
При этом построение развёртывания конфигурации по принципу `push` проще, чем построение гибридного подхода,
|
|
||||||
что повышает надёжность на первых этапах построения инфраструктуры.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Установить на личный компьютер:
|
|
||||||
> * VirtualBox
|
|
||||||
> * Vagrant
|
|
||||||
> * Ansible
|
|
||||||
>
|
|
||||||
> Приложить вывод команд установленных версий каждой из программ, оформленный в markdown.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
virtualbox --help
|
|
||||||
Oracle VM VirtualBox VM Selector v6.1.32
|
|
||||||
(C) 2005-2022 Oracle Corporation
|
|
||||||
All rights reserved.
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
vagrant --version
|
|
||||||
Vagrant 2.2.19
|
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible --version
|
|
||||||
ansible [core 2.12.4]
|
|
||||||
config file = /etc/ansible/ansible.cfg
|
|
||||||
configured module search path = ['~/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
|
|
||||||
ansible python module location = /usr/lib/python3/dist-packages/ansible
|
|
||||||
ansible collection location = ~/.ansible/collections:/usr/share/ansible/collections
|
|
||||||
executable location = /usr/bin/ansible
|
|
||||||
python version = 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0]
|
|
||||||
jinja version = 2.10.1
|
|
||||||
libyaml = True
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4 (*)
|
|
||||||
|
|
||||||
> Воспроизвести практическую часть лекции самостоятельно.
|
|
||||||
> Создать виртуальную машину.
|
|
||||||
|
|
||||||
Для создания виртуальной машины используется уже готовый [`Vagrantfile`](/src/vagrant/Vagrantfile),
|
|
||||||
в который дополнительно добавлены команды необходимые для установки `docker`:
|
|
||||||
|
|
||||||
```
|
|
||||||
config.vm.provision "shell", inline: <<-SHELL
|
|
||||||
apt update
|
|
||||||
apt install -y ca-certificates \
|
|
||||||
curl \
|
|
||||||
gnupg \
|
|
||||||
lsb-release
|
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
|
|
||||||
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
||||||
apt update
|
|
||||||
apt install -y docker-ce docker-ce-cli containerd.io
|
|
||||||
usermod -aG docker vagrant
|
|
||||||
SHELL
|
|
||||||
```
|
|
||||||
|
|
||||||
> Зайти внутрь ВМ, убедиться, что Docker установлен с помощью команды `docker ps`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
vagrant ssh
|
|
||||||
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-91-generic x86_64)
|
|
||||||
<...>
|
|
||||||
|
|
||||||
vagrant@vagrant:~$ docker ps -a
|
|
||||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|
||||||
|
|
||||||
vagrant@vagrant:~$ docker run --rm hello-world
|
|
||||||
Unable to find image 'hello-world:latest' locally
|
|
||||||
latest: Pulling from library/hello-world
|
|
||||||
2db29710123e: Pull complete
|
|
||||||
Digest: sha256:10d7d58d5ebd2a652f4d93fdd86da8f265f5318c6a73cc5b6a9798ff6d2b2e67
|
|
||||||
Status: Downloaded newer image for hello-world:latest
|
|
||||||
|
|
||||||
Hello from Docker!
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
*
|
|
||||||
|
|
||||||
!.gitignore
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
FROM nginx:1.21.6-alpine
|
|
||||||
|
|
||||||
COPY site.conf /etc/nginx/conf.d/default.conf
|
|
||||||
COPY index.html /var/www/netology/index.html
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
- hosts: 127.0.0.1
|
|
||||||
gather_facts: no
|
|
||||||
connection: local
|
|
||||||
tasks:
|
|
||||||
- name: create build directory
|
|
||||||
file:
|
|
||||||
path: /tmp/ansible-docker-build
|
|
||||||
state: directory
|
|
||||||
owner: 1000
|
|
||||||
group: 1000
|
|
||||||
mode: '0755'
|
|
||||||
- name: copy Dockerfile
|
|
||||||
copy:
|
|
||||||
src: ./Dockerfile
|
|
||||||
dest: /tmp/ansible-docker-build/Dockerfile
|
|
||||||
owner: 1000
|
|
||||||
group: 1000
|
|
||||||
mode: '0644'
|
|
||||||
- name: copy site.conf
|
|
||||||
copy:
|
|
||||||
src: ./site.conf
|
|
||||||
dest: /tmp/ansible-docker-build/site.conf
|
|
||||||
owner: 1000
|
|
||||||
group: 1000
|
|
||||||
mode: '0644'
|
|
||||||
- name: copy index.html
|
|
||||||
copy:
|
|
||||||
src: ./index.html
|
|
||||||
dest: /tmp/ansible-docker-build/index.html
|
|
||||||
owner: 1000
|
|
||||||
group: 1000
|
|
||||||
mode: '0644'
|
|
||||||
- name: build container image
|
|
||||||
docker_image:
|
|
||||||
name: dannecron/netology-devops-nginx:ansible
|
|
||||||
source: build
|
|
||||||
build:
|
|
||||||
path: /tmp/ansible-docker-build/
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
Hey, Netology
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>I`m DevOps Engineer!</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
- hosts: 127.0.0.1
|
|
||||||
gather_facts: no
|
|
||||||
connection: local
|
|
||||||
tasks:
|
|
||||||
- name: login to hub.docker.com
|
|
||||||
command: docker login
|
|
||||||
- name: push image to hub.docker.com
|
|
||||||
docker_image:
|
|
||||||
name: dannecron/netology-devops-nginx:ansible
|
|
||||||
source: local
|
|
||||||
push: yes
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
root /var/www/netology;
|
|
||||||
index index.html index.htm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/virt-homeworks/blob/virt-11/05-virt-03-docker/README.md)
|
|
||||||
по теме "5.3. Введение. Экосистема. Архитектура. Жизненный цикл Docker контейнера".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Сценарий выполения задачи:
|
|
||||||
>
|
|
||||||
> - создайте свой репозиторий на https://hub.docker.com;
|
|
||||||
> - выберете любой образ, который содержит веб-сервер Nginx;
|
|
||||||
> - создайте свой fork образа;
|
|
||||||
> - реализуйте функциональность:
|
|
||||||
> запуск веб-сервера в фоне с индекс-страницей, содержащей HTML-код ниже:
|
|
||||||
> ```html
|
|
||||||
> <html>
|
|
||||||
> <head>
|
|
||||||
> Hey, Netology
|
|
||||||
> </head>
|
|
||||||
> <body>
|
|
||||||
> <h1>I’m DevOps Engineer!</h1>
|
|
||||||
> </body>
|
|
||||||
> </html>
|
|
||||||
> ```
|
|
||||||
> Опубликуйте созданный форк в своем репозитории и предоставьте ответ в виде ссылки на https://hub.docker.com/username_repo.
|
|
||||||
|
|
||||||
Репозиторий с образом: [https://hub.docker.com/r/dannecron/netology-devops-nginx](https://hub.docker.com/r/dannecron/netology-devops-nginx)
|
|
||||||
|
|
||||||
За основу был взят [официальный образ nginx](https://hub.docker.com/_/nginx). Для решения задачи был сформирован [Dockerfile](./nginx/Dockerfile),
|
|
||||||
а также конфигурация [site.conf](./nginx/site.conf) и [index.html](./nginx/index.html).
|
|
||||||
|
|
||||||
Для сборки образа используем команду из директории [nginx](./nginx):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker build -t dannecron/netology-devops-nginx:latest .
|
|
||||||
[+] Building 6.6s (9/9) FINISHED
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что всё работает. Для этого запустим контейнер из только что созданного образа и сделаем curl-запрос:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run --rm -it -p 18800:80 dannecron/netology-devops-nginx:latest
|
|
||||||
|
|
||||||
curl http://localhost:18800
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
Hey, Netology
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>I`m DevOps Engineer!</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
После этого опубликуем образ:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker push dannecron/netology-devops-nginx:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Посмотрите на сценарий ниже и ответьте на вопрос:
|
|
||||||
> "Подходит ли в этом сценарии использование Docker контейнеров или лучше подойдет виртуальная машина, физическая машина? Может быть возможны разные варианты?"
|
|
||||||
>
|
|
||||||
> Детально опишите и обоснуйте свой выбор.
|
|
||||||
> --
|
|
||||||
>
|
|
||||||
> Сценарий:
|
|
||||||
>
|
|
||||||
> - Высоконагруженное монолитное java веб-приложение;
|
|
||||||
> - Nodejs веб-приложение;
|
|
||||||
> - Мобильное приложение c версиями для Android и iOS;
|
|
||||||
> - Шина данных на базе Apache Kafka;
|
|
||||||
> - Elasticsearch кластер для реализации логирования продуктивного веб-приложения - три ноды elasticsearch, два logstash и две ноды kibana;
|
|
||||||
> - Мониторинг-стек на базе Prometheus и Grafana;
|
|
||||||
> - MongoDB, как основное хранилище данных для java-приложения;
|
|
||||||
> - Gitlab сервер для реализации CI/CD процессов и приватный (закрытый) Docker Registry.
|
|
||||||
|
|
||||||
* Высоконагруженное монолитное java веб-приложение
|
|
||||||
|
|
||||||
В данном случае `docker` будет оптимальным решением, так как не будет требовать каких-то дополнительных настроек JVM, а для запуска достаточно будет установленного docker.
|
|
||||||
В процессе упаковки приложения в образ можно произвести оптимизацию, которая уменьшит размер финального образа,
|
|
||||||
что минимизирует растраты на трафик при деплое и растраты на хранение в registry.
|
|
||||||
Ещё одним плюсом является возможность горизонтального масштабирования приложения без дополнительных настроек самого приложения.
|
|
||||||
|
|
||||||
* Nodejs веб-приложение
|
|
||||||
|
|
||||||
Аналогично, как и для java веб-приложения, docker будет оптимальным решением. Плюсы подхода сохраняются.
|
|
||||||
|
|
||||||
* Мобильное приложение c версиями для Android и iOS
|
|
||||||
|
|
||||||
Само мобильное приложение необходимо запускать только на физическом устройстве, так как мобильные устройства не поддерживают
|
|
||||||
использование `docker` или виртуализацию.
|
|
||||||
|
|
||||||
* Шина данных на базе Apache Kafka
|
|
||||||
|
|
||||||
Шина данных на базе Apache Kafka - это кластерное решение, состоящее как минимум из двух сервисов
|
|
||||||
и очень сильно зависящее от доступности сети.
|
|
||||||
В таком случае будет наиболее оптимально запускать сервисы в виртуальных машинах, чтобы была возможность
|
|
||||||
более гибко конфигурировать локальную сеть для данного кластера, при этом увеличив стабильность работы.
|
|
||||||
|
|
||||||
* Elasticsearch кластер для реализации логирования продуктивного веб-приложения - три ноды elasticsearch, два logstash и две ноды kibana
|
|
||||||
|
|
||||||
Ввиду того, что `elasticsearch` - это своеобразная база данных, нуждающаяся в достаточно тонкой настройке,
|
|
||||||
особенно для большого количества логов, то оптимально будет использовать виртуальные либо физические машины,
|
|
||||||
в зависимости от требований к нагрузке.
|
|
||||||
|
|
||||||
* Мониторинг-стек на базе Prometheus и Grafana
|
|
||||||
|
|
||||||
Так как `Prometheus` - это база данных, то оптимально будет выбрать решение на базе физической машины,
|
|
||||||
чтобы увеличить отказоустойчивость и уменьшить расходы с взаимодействием с физическими дисками.
|
|
||||||
|
|
||||||
При этом само веб-приложение `Grafana` можно развернуть с использованием докера, так как это стандартный сервер для обработки запросов.
|
|
||||||
|
|
||||||
* MongoDB, как основное хранилище данных для java-приложения
|
|
||||||
|
|
||||||
Так как `MongoDB` - это база данных, то оптимально будет выбрать решение на базе физической машины,
|
|
||||||
чтобы увеличить отказоустойчивость и уменьшить расходы с взаимодействием с физическими дисками.
|
|
||||||
|
|
||||||
* Gitlab сервер для реализации CI/CD процессов и приватный (закрытый) Docker Registry
|
|
||||||
|
|
||||||
В данном случае оптимально будет запустить сервер на физической или виртуальной машине. Это обусловлено тем,
|
|
||||||
что `Docker Registry` активно взаимодействует с файловой системой, поэтому необходимо минимизировать издержки на данное взаимодействие.
|
|
||||||
При этом сам `Gitlab` - это стек из множества сервисов, в том числе и база данных `postgresql`,
|
|
||||||
поэтому для более удобной конфигурации и администрирования в данном случае лучше не использовать `docker`.
|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> - Запустите первый контейнер из образа ***centos*** c любым тэгом в фоновом режиме, подключив папку ```/data``` из текущей рабочей директории на хостовой машине в ```/data``` контейнера;
|
|
||||||
> - Запустите второй контейнер из образа ***debian*** в фоновом режиме, подключив папку ```/data``` из текущей рабочей директории на хостовой машине в ```/data``` контейнера;
|
|
||||||
> - Подключитесь к первому контейнеру с помощью ```docker exec``` и создайте текстовый файл любого содержания в ```/data```;
|
|
||||||
> - Добавьте еще один файл в папку ```/data``` на хостовой машине;
|
|
||||||
> - Подключитесь во второй контейнер и отобразите листинг и содержание файлов в ```/data``` контейнера.
|
|
||||||
|
|
||||||
Запуск контейнера с `centos` в фоновом режиме:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run --rm -it -d --name centos-linux -v `pwd`/linux-data:/data centos:7.9.2009 tail -f /dev/null
|
|
||||||
docker ps | grep centos
|
|
||||||
763f82085972 centos:7.9.2009 "tail -f /dev/null" 4 seconds ago Up 3 seconds centos-linux
|
|
||||||
```
|
|
||||||
|
|
||||||
Запуск контейнера с `debian` в фоновом режиме:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run --rm -it -d --name debian-linux -v `pwd`/linux-data:/data debian:11.3-slim tail -f /dev/null
|
|
||||||
docker ps | grep debian
|
|
||||||
ed46ef5be3dc debian:11.3-slim "tail -f /dev/null" 15 seconds ago Up 14 seconds debian-linux
|
|
||||||
```
|
|
||||||
|
|
||||||
Подключаемся к контейнеру `centos-linux` и создадим там текстовый файл:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker exec -it centos-linux bash
|
|
||||||
cd /data/
|
|
||||||
echo "some test text" >> test.txt
|
|
||||||
ls -l
|
|
||||||
total 8
|
|
||||||
-rw-r--r-- 1 root root 15 May 5 03:06 test.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
Создадим ещё один текстовый файл на хост-машине:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "host text test" >> linux-data/host.txt
|
|
||||||
ls -l linux-data
|
|
||||||
total 8
|
|
||||||
-rw-rw-r-- 1 dannc dannc 15 мая 5 10:08 host.txt
|
|
||||||
-rw-r--r-- 1 root root 15 мая 5 10:06 test.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверим, что оба файла находятся в контейнере `debian-linux`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker exec debian-linux bash -c "ls -l /data"
|
|
||||||
total 8
|
|
||||||
-rw-rw-r-- 1 1000 1000 15 May 5 03:08 host.txt
|
|
||||||
-rw-r--r-- 1 root root 15 May 5 03:06 test.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
### Задача 4 (*)
|
|
||||||
|
|
||||||
> Соберите Docker образ с Ansible, загрузите на Docker Hub и пришлите ссылку вместе с остальными ответами к задачам.
|
|
||||||
|
|
||||||
За основу возьмём [`Dockerfile`](./nginx/Dockerfile) для `nginx` из [задачи 1](#задача-1).
|
|
||||||
|
|
||||||
Создадим новый `playbook` в файле [build.yml](./nginx/build.yml). Добавим туда несколько действий:
|
|
||||||
|
|
||||||
1. создание временной директории.
|
|
||||||
2. копирование `Dockerfile`, конфигурации и `index.html` в данную директорию.
|
|
||||||
3. сборка образа.
|
|
||||||
|
|
||||||
Проверим, что всё работает и образ собирается:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook build.yml
|
|
||||||
<...>
|
|
||||||
docker image list | grep ansible
|
|
||||||
dannecron/netology-devops-nginx ansible 58df80189129 17 seconds ago 23.4MB
|
|
||||||
```
|
|
||||||
|
|
||||||
Для публикации в публичный регстри выделим отдельный `playbook`: [publish.yml](./nginx/publish.yml), в котром будет два шага:
|
|
||||||
|
|
||||||
1. авторизация в `hub.docker.com`.
|
|
||||||
2. публикация образа.
|
|
||||||
|
|
||||||
Проверим, что всё работает:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook publish.yml
|
|
||||||
<...>
|
|
||||||
```
|
|
||||||
|
|
||||||
Образ доступен по ссылке [hub.docker.com](https://hub.docker.com/layers/208296992/dannecron/netology-devops-nginx/ansible/images/sha256-e007739a276cbc1f556b674b1ec142360afe4fa35364f3a8b464e74786da4e3d?context=repo)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
inventory
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
[defaults]
|
|
||||||
inventory=./inventory
|
|
||||||
deprecation_warnings=False
|
|
||||||
command_warnings=False
|
|
||||||
ansible_port=22
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
[nodes:children]
|
|
||||||
manager
|
|
||||||
|
|
||||||
[manager]
|
|
||||||
node01.netology.cloud ansible_host=
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- hosts: nodes
|
|
||||||
become: yes
|
|
||||||
become_user: root
|
|
||||||
remote_user: centos
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Create directory for ssh-keys
|
|
||||||
file: state=directory mode=0700 dest=/root/.ssh/
|
|
||||||
|
|
||||||
- name: Adding rsa-key in /root/.ssh/authorized_keys
|
|
||||||
copy: src=~/.ssh/id_rsa.pub dest=/root/.ssh/authorized_keys owner=root mode=0600
|
|
||||||
ignore_errors: yes
|
|
||||||
|
|
||||||
- name: Checking DNS
|
|
||||||
command: host -t A google.com
|
|
||||||
|
|
||||||
- name: Installing tools
|
|
||||||
yum: >
|
|
||||||
pkg={{ item }}
|
|
||||||
state=present
|
|
||||||
update_cache=yes
|
|
||||||
with_items:
|
|
||||||
- git
|
|
||||||
- curl
|
|
||||||
|
|
||||||
- name: Add docker repository
|
|
||||||
command: yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
|
||||||
|
|
||||||
- name: Installing docker package
|
|
||||||
yum: >
|
|
||||||
pkg={{ item }}
|
|
||||||
state=present
|
|
||||||
update_cache=yes
|
|
||||||
with_items:
|
|
||||||
- docker-ce
|
|
||||||
- docker-ce-cli
|
|
||||||
- containerd.io
|
|
||||||
|
|
||||||
- name: Enable docker daemon
|
|
||||||
systemd:
|
|
||||||
name: docker
|
|
||||||
state: started
|
|
||||||
enabled: yes
|
|
||||||
|
|
||||||
- name: Install docker-compose
|
|
||||||
raw: $(curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` -o /usr/bin/docker-compose && chmod +x /usr/bin/docker-compose)
|
|
||||||
|
|
||||||
- name: Synchronization
|
|
||||||
copy:
|
|
||||||
src: stack/
|
|
||||||
dest: "/opt/stack/"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
become: true
|
|
||||||
|
|
||||||
- name: Pull all images in compose
|
|
||||||
command: docker-compose -f /opt/stack/docker-compose.yaml pull
|
|
||||||
|
|
||||||
- name: Up all services in compose
|
|
||||||
command: docker-compose -f /opt/stack/docker-compose.yaml up -d
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ADMIN_USER=admin
|
|
||||||
ADMIN_PASSWORD=admin
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
route:
|
|
||||||
receiver: 'slack'
|
|
||||||
|
|
||||||
receivers:
|
|
||||||
- name: 'slack'
|
|
||||||
slack_configs:
|
|
||||||
- send_resolved: true
|
|
||||||
text: "{{ .CommonAnnotations.description }}"
|
|
||||||
username: 'Prometheus'
|
|
||||||
channel: '#<channel-name>'
|
|
||||||
api_url: 'https://hooks.slack.com/services/<webhook-id>'
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
:9090 {
|
|
||||||
basicauth / {$ADMIN_USER} {$ADMIN_PASSWORD}
|
|
||||||
proxy / prometheus:9090 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
:9093 {
|
|
||||||
basicauth / {$ADMIN_USER} {$ADMIN_PASSWORD}
|
|
||||||
proxy / alertmanager:9093 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
:9091 {
|
|
||||||
basicauth / {$ADMIN_USER} {$ADMIN_PASSWORD}
|
|
||||||
proxy / pushgateway:9091 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
:3000 {
|
|
||||||
proxy / grafana:3000 {
|
|
||||||
transparent
|
|
||||||
websocket
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
version: '2.1'
|
|
||||||
|
|
||||||
networks:
|
|
||||||
monitoring:
|
|
||||||
driver: bridge
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
prometheus_data: {}
|
|
||||||
grafana_data: {}
|
|
||||||
|
|
||||||
services:
|
|
||||||
|
|
||||||
prometheus:
|
|
||||||
image: prom/prometheus:v2.17.1
|
|
||||||
container_name: prometheus
|
|
||||||
volumes:
|
|
||||||
- ./prometheus:/etc/prometheus
|
|
||||||
- prometheus_data:/prometheus
|
|
||||||
command:
|
|
||||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
|
||||||
- '--storage.tsdb.path=/prometheus'
|
|
||||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
|
||||||
- '--web.console.templates=/etc/prometheus/consoles'
|
|
||||||
- '--storage.tsdb.retention.time=15d'
|
|
||||||
- '--web.enable-lifecycle'
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
alertmanager:
|
|
||||||
image: prom/alertmanager:v0.20.0
|
|
||||||
container_name: alertmanager
|
|
||||||
volumes:
|
|
||||||
- ./alertmanager:/etc/alertmanager
|
|
||||||
command:
|
|
||||||
- '--config.file=/etc/alertmanager/config.yml'
|
|
||||||
- '--storage.path=/alertmanager'
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
nodeexporter:
|
|
||||||
image: prom/node-exporter:v0.18.1
|
|
||||||
container_name: nodeexporter
|
|
||||||
volumes:
|
|
||||||
- /proc:/host/proc:ro
|
|
||||||
- /sys:/host/sys:ro
|
|
||||||
- /:/rootfs:ro
|
|
||||||
command:
|
|
||||||
- '--path.procfs=/host/proc'
|
|
||||||
- '--path.rootfs=/rootfs'
|
|
||||||
- '--path.sysfs=/host/sys'
|
|
||||||
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
cadvisor:
|
|
||||||
image: gcr.io/google-containers/cadvisor:v0.34.0
|
|
||||||
container_name: cadvisor
|
|
||||||
volumes:
|
|
||||||
- /:/rootfs:ro
|
|
||||||
- /var/run:/var/run:rw
|
|
||||||
- /sys:/sys:ro
|
|
||||||
- /var/lib/docker:/var/lib/docker:ro
|
|
||||||
- /cgroup:/cgroup:ro
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
grafana:
|
|
||||||
image: grafana/grafana:7.4.2
|
|
||||||
container_name: grafana
|
|
||||||
volumes:
|
|
||||||
- grafana_data:/var/lib/grafana
|
|
||||||
- ./grafana/provisioning:/etc/grafana/provisioning
|
|
||||||
environment:
|
|
||||||
- GF_SECURITY_ADMIN_USER=${ADMIN_USER:-admin}
|
|
||||||
- GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin}
|
|
||||||
- GF_USERS_ALLOW_SIGN_UP=false
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
pushgateway:
|
|
||||||
image: prom/pushgateway:v1.2.0
|
|
||||||
container_name: pushgateway
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
caddy:
|
|
||||||
image: stefanprodan/caddy
|
|
||||||
container_name: caddy
|
|
||||||
ports:
|
|
||||||
- "0.0.0.0:3000:3000"
|
|
||||||
- "0.0.0.0:9090:9090"
|
|
||||||
- "0.0.0.0:9093:9093"
|
|
||||||
- "0.0.0.0:9091:9091"
|
|
||||||
volumes:
|
|
||||||
- ./caddy:/etc/caddy
|
|
||||||
environment:
|
|
||||||
- ADMIN_USER=${ADMIN_USER:-admin}
|
|
||||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin}
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- monitoring
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
version: '2.1'
|
|
||||||
|
|
||||||
services:
|
|
||||||
|
|
||||||
nodeexporter:
|
|
||||||
image: prom/node-exporter:v0.18.1
|
|
||||||
container_name: nodeexporter
|
|
||||||
volumes:
|
|
||||||
- /proc:/host/proc:ro
|
|
||||||
- /sys:/host/sys:ro
|
|
||||||
- /:/rootfs:ro
|
|
||||||
command:
|
|
||||||
- '--path.procfs=/host/proc'
|
|
||||||
- '--path.rootfs=/rootfs'
|
|
||||||
- '--path.sysfs=/host/sys'
|
|
||||||
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
|
|
||||||
restart: unless-stopped
|
|
||||||
network_mode: host
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
cadvisor:
|
|
||||||
image: gcr.io/google-containers/cadvisor:v0.34.0
|
|
||||||
container_name: cadvisor
|
|
||||||
volumes:
|
|
||||||
- /:/rootfs:ro
|
|
||||||
- /var/run:/var/run:rw
|
|
||||||
- /sys:/sys:ro
|
|
||||||
- /var/lib/docker/:/var/lib/docker:ro
|
|
||||||
- /cgroup:/cgroup:ro
|
|
||||||
restart: unless-stopped
|
|
||||||
network_mode: host
|
|
||||||
labels:
|
|
||||||
org.label-schema.group: "monitoring"
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
apiVersion: 1
|
|
||||||
|
|
||||||
providers:
|
|
||||||
- name: 'Prometheus'
|
|
||||||
orgId: 1
|
|
||||||
folder: ''
|
|
||||||
type: file
|
|
||||||
disableDeletion: false
|
|
||||||
editable: true
|
|
||||||
allowUiUpdates: true
|
|
||||||
options:
|
|
||||||
path: /etc/grafana/provisioning/dashboards
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
apiVersion: 1
|
|
||||||
|
|
||||||
datasources:
|
|
||||||
- name: Prometheus
|
|
||||||
type: prometheus
|
|
||||||
access: proxy
|
|
||||||
orgId: 1
|
|
||||||
url: http://prometheus:9090
|
|
||||||
basicAuth: false
|
|
||||||
isDefault: true
|
|
||||||
editable: true
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
groups:
|
|
||||||
- name: targets
|
|
||||||
rules:
|
|
||||||
- alert: monitor_service_down
|
|
||||||
expr: up == 0
|
|
||||||
for: 30s
|
|
||||||
labels:
|
|
||||||
severity: critical
|
|
||||||
annotations:
|
|
||||||
summary: "Monitor service non-operational"
|
|
||||||
description: "Service {{ $labels.instance }} is down."
|
|
||||||
|
|
||||||
- name: host
|
|
||||||
rules:
|
|
||||||
- alert: high_cpu_load
|
|
||||||
expr: node_load1 > 1.5
|
|
||||||
for: 30s
|
|
||||||
labels:
|
|
||||||
severity: warning
|
|
||||||
annotations:
|
|
||||||
summary: "Server under high load"
|
|
||||||
description: "Docker host is under high load, the avg load 1m is at {{ $value}}. Reported by instance {{ $labels.instance }} of job {{ $labels.job }}."
|
|
||||||
|
|
||||||
- alert: high_memory_load
|
|
||||||
expr: (sum(node_memory_MemTotal_bytes) - sum(node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes) ) / sum(node_memory_MemTotal_bytes) * 100 > 85
|
|
||||||
for: 30s
|
|
||||||
labels:
|
|
||||||
severity: warning
|
|
||||||
annotations:
|
|
||||||
summary: "Server memory is almost full"
|
|
||||||
description: "Docker host memory usage is {{ humanize $value}}%. Reported by instance {{ $labels.instance }} of job {{ $labels.job }}."
|
|
||||||
|
|
||||||
- alert: high_storage_load
|
|
||||||
expr: (node_filesystem_size_bytes{fstype="aufs"} - node_filesystem_free_bytes{fstype="aufs"}) / node_filesystem_size_bytes{fstype="aufs"} * 100 > 85
|
|
||||||
for: 30s
|
|
||||||
labels:
|
|
||||||
severity: warning
|
|
||||||
annotations:
|
|
||||||
summary: "Server storage is almost full"
|
|
||||||
description: "Docker host storage usage is {{ humanize $value}}%. Reported by instance {{ $labels.instance }} of job {{ $labels.job }}."
|
|
||||||
|
|
||||||
- name: containers
|
|
||||||
rules:
|
|
||||||
#- alert: jenkins_down
|
|
||||||
# expr: absent(container_memory_usage_bytes{name="jenkins"})
|
|
||||||
# for: 30s
|
|
||||||
# labels:
|
|
||||||
# severity: critical
|
|
||||||
# annotations:
|
|
||||||
# summary: "Jenkins down"
|
|
||||||
# description: "Jenkins container is down for more than 30 seconds."
|
|
||||||
|
|
||||||
#- alert: jenkins_high_cpu
|
|
||||||
# expr: sum(rate(container_cpu_usage_seconds_total{name="jenkins"}[1m])) / count(node_cpu_seconds_total{mode="system"}) * 100 > 10
|
|
||||||
# for: 30s
|
|
||||||
# labels:
|
|
||||||
# severity: warning
|
|
||||||
# annotations:
|
|
||||||
# summary: "Jenkins high CPU usage"
|
|
||||||
# description: "Jenkins CPU usage is {{ humanize $value}}%."
|
|
||||||
|
|
||||||
#- alert: jenkins_high_memory
|
|
||||||
# expr: sum(container_memory_usage_bytes{name="jenkins"}) > 1200000000
|
|
||||||
# for: 30s
|
|
||||||
# labels:
|
|
||||||
# severity: warning
|
|
||||||
# annotations:
|
|
||||||
# summary: "Jenkins high memory usage"
|
|
||||||
# description: "Jenkins memory consumption is at {{ humanize $value}}."
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
global:
|
|
||||||
scrape_interval: 15s
|
|
||||||
evaluation_interval: 15s
|
|
||||||
|
|
||||||
# Attach these labels to any time series or alerts when communicating with
|
|
||||||
# external systems (federation, remote storage, Alertmanager).
|
|
||||||
external_labels:
|
|
||||||
monitor: 'prometheus'
|
|
||||||
|
|
||||||
# Load and evaluate rules in this file every 'evaluation_interval' seconds.
|
|
||||||
rule_files:
|
|
||||||
- "alert.rules"
|
|
||||||
|
|
||||||
# A scrape configuration containing exactly one endpoint to scrape.
|
|
||||||
scrape_configs:
|
|
||||||
- job_name: 'nodeexporter'
|
|
||||||
scrape_interval: 5s
|
|
||||||
static_configs:
|
|
||||||
- targets: ['nodeexporter:9100']
|
|
||||||
|
|
||||||
- job_name: 'cadvisor'
|
|
||||||
scrape_interval: 5s
|
|
||||||
static_configs:
|
|
||||||
- targets: ['cadvisor:8080']
|
|
||||||
|
|
||||||
- job_name: 'prometheus'
|
|
||||||
scrape_interval: 10s
|
|
||||||
static_configs:
|
|
||||||
- targets: ['localhost:9090']
|
|
||||||
|
|
||||||
- job_name: 'pushgateway'
|
|
||||||
scrape_interval: 10s
|
|
||||||
honor_labels: true
|
|
||||||
static_configs:
|
|
||||||
- targets: ['pushgateway:9091']
|
|
||||||
|
|
||||||
- job_name: 'alertmanager'
|
|
||||||
scrape_interval: 10s
|
|
||||||
honor_labels: true
|
|
||||||
static_configs:
|
|
||||||
- targets: ['alertmanager:9093']
|
|
||||||
|
|
||||||
- job_name: 'grafana'
|
|
||||||
scrape_interval: 10s
|
|
||||||
honor_labels: true
|
|
||||||
static_configs:
|
|
||||||
- targets: ['grafana:3000']
|
|
||||||
|
|
||||||
|
|
||||||
alerting:
|
|
||||||
alertmanagers:
|
|
||||||
- scheme: http
|
|
||||||
static_configs:
|
|
||||||
- targets:
|
|
||||||
- 'alertmanager:9093'
|
|
||||||
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 244 KiB |
@@ -1 +0,0 @@
|
|||||||
centos-7-base.json
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"builders": [
|
|
||||||
{
|
|
||||||
"disk_type": "network-nvme",
|
|
||||||
"folder_id": "",
|
|
||||||
"image_description": "build by packer",
|
|
||||||
"image_family": "centos",
|
|
||||||
"image_name": "centos-7-base",
|
|
||||||
"source_image_family": "centos-7",
|
|
||||||
"ssh_username": "centos",
|
|
||||||
"subnet_id": "",
|
|
||||||
"token": "",
|
|
||||||
"type": "yandex",
|
|
||||||
"use_ipv4_nat": true,
|
|
||||||
"zone": "ru-central1-a"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"provisioners": [
|
|
||||||
{
|
|
||||||
"inline": [
|
|
||||||
"sudo yum -y update",
|
|
||||||
"sudo yum -y install bridge-utils bind-utils iptables curl net-tools tcpdump rsync telnet openssh-server"
|
|
||||||
],
|
|
||||||
"type": "shell"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
Выполнение [домашнего задания](https://github.com/netology-code/virt-homeworks/blob/virt-11/05-virt-04-docker-compose/README.md)
|
|
||||||
по теме "5.4. Оркестрация группой Docker контейнеров на примере Docker Compose".
|
|
||||||
|
|
||||||
## Q/A
|
|
||||||
|
|
||||||
### Задача 1
|
|
||||||
|
|
||||||
> Создать собственный образ операционной системы с помощью Packer.
|
|
||||||
>
|
|
||||||
> Для получения зачета, вам необходимо предоставить:
|
|
||||||
> - Скриншот страницы, как на слайде из презентации (слайд 37).
|
|
||||||
|
|
||||||
Пошаговая инструкция работы с yandex-облаком:
|
|
||||||
1. Установка `yc`: `curl -sSL https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash`
|
|
||||||
2. Инициализация конфигурации: `yc init`
|
|
||||||
3. Проверка, что всё работает:
|
|
||||||
```shell
|
|
||||||
yc compute image list
|
|
||||||
+----+------+--------+-------------+--------+
|
|
||||||
| ID | NAME | FAMILY | PRODUCT IDS | STATUS |
|
|
||||||
+----+------+--------+-------------+--------+
|
|
||||||
+----+------+--------+-------------+--------+
|
|
||||||
```
|
|
||||||
4. Создание сети: `yc vpc network create --name net`
|
|
||||||
5. Создание подсети: `yc vpc subnet create --name my-subnet-a --zone ru-central1-a --range 10.1.2.0/24 --network-name net --description "test subnet for test net"`
|
|
||||||
6. Копирование примера конфигурации packer [centos-7-base.example.json](./packer/centos-7-base.example.json) в `centos-7-base.json`.
|
|
||||||
7. Затем нужно заполнить недостающие поля в конфигурации.
|
|
||||||
8. Запуск валидации конфигурации
|
|
||||||
```shell
|
|
||||||
packer validate packer/centos-7-base.json
|
|
||||||
The configuration is valid.
|
|
||||||
```
|
|
||||||
9. Запуск сборки образа `packer build packer/centos-7-base.json`
|
|
||||||
10. Удаление подсети: `yc vpc subnet delete --name my-subnet-a`
|
|
||||||
11. Удаление сети: `yc vpc network delete --name net`
|
|
||||||
|
|
||||||
**Результат**:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Задача 2
|
|
||||||
|
|
||||||
> Создать вашу первую виртуальную машину в Яндекс.Облаке.
|
|
||||||
>
|
|
||||||
> Для получения зачета, вам необходимо предоставить:
|
|
||||||
> - Скриншот страницы свойств созданной ВМ
|
|
||||||
|
|
||||||
1. Копирование секретов для `terraform` из [variables.tf.example](./terraform/variables.tf.example) в `variables.tf`
|
|
||||||
2. Затем нужно изменить поля в конфигурации.
|
|
||||||
3. Инициализировать конфигурацию: `terraform init` (не работает без vpn, при получении данных отдаётся 403 статус код)
|
|
||||||
4. Просмотреть конфигурацию `terraform plan`
|
|
||||||
5. Применить конфигурацию к облаку `terraform apply -auto-approve`
|
|
||||||
|
|
||||||
**Результат**:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Задача 3
|
|
||||||
|
|
||||||
> Создать ваш первый готовый к боевой эксплуатации компонент мониторинга, состоящий из стека микросервисов.
|
|
||||||
>
|
|
||||||
> Для получения зачета, вам необходимо предоставить:
|
|
||||||
> - Скриншот работающего веб-интерфейса Grafana с текущими метриками
|
|
||||||
|
|
||||||
1. Копирование inventory файла для `ansible` из [inventory.example](./ansible/inventory.example) в `inventory`
|
|
||||||
2. Запуск `ansible`: `cd ansible && ansible-playbook provision.yml`
|
|
||||||
|
|
||||||
**Результат**:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Clean up
|
|
||||||
|
|
||||||
Удаление всей инфраструктуры:
|
|
||||||
|
|
||||||
1. Удаление ВМ, сетей: `terraform destroy -auto-approve`
|
|
||||||
2. Удаление образа ОС: `yc compute image delete --id fd8oponkic4t99ecuk8k`
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
variables.tf
|
|
||||||
|
|
||||||
# Local .terraform directories
|
|
||||||
**/.terraform/*
|
|
||||||
|
|
||||||
# .tfstate files
|
|
||||||
*.tfstate
|
|
||||||
*.tfstate.*
|
|
||||||
|
|
||||||
# Crash log files
|
|
||||||
crash.log
|
|
||||||
crash.*.log
|
|
||||||
|
|
||||||
# Exclude all .tfvars files, which are likely to contain sentitive data, such as
|
|
||||||
# password, private keys, and other secrets. These should not be part of version
|
|
||||||
# control as they are data points which are potentially sensitive and subject
|
|
||||||
# to change depending on the environment.
|
|
||||||
#
|
|
||||||
*.tfvars
|
|
||||||
|
|
||||||
# Ignore override files as they are usually used to override resources locally and so
|
|
||||||
# are not checked in
|
|
||||||
override.tf
|
|
||||||
override.tf.json
|
|
||||||
*_override.tf
|
|
||||||
*_override.tf.json
|
|
||||||
|
|
||||||
# Include override files you do wish to add to version control using negated pattern
|
|
||||||
#
|
|
||||||
# !example_override.tf
|
|
||||||
|
|
||||||
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
|
||||||
# example: *tfplan*
|
|
||||||
|
|
||||||
# Ignore CLI configuration files
|
|
||||||
.terraformrc
|
|
||||||
terraform.rc
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# This file is maintained automatically by "terraform init".
|
|
||||||
# Manual edits may be lost in future updates.
|
|
||||||
|
|
||||||
provider "registry.terraform.io/yandex-cloud/yandex" {
|
|
||||||
version = "0.74.0"
|
|
||||||
hashes = [
|
|
||||||
"h1:WE0V59Nb+oj8gN02X7Xt5ZuP+Z+dP3lLaQgChj+8t1g=",
|
|
||||||
"zh:01914a42590934918a312324fcf8b0b342da113da76c13bc00d40b9d3c0a78d9",
|
|
||||||
"zh:0ae93ec70084677f0026c44513c99252dde3be31435c4d1ef5259c8ab5bde225",
|
|
||||||
"zh:59acf5f27d378069d7332549c1645e03de2a2ff9208e02e1546491d276031e23",
|
|
||||||
"zh:6662ab75109138675de0060957ce259c96c141e87617bc211dd80f1213d69419",
|
|
||||||
"zh:86143792b6395e582b2363ac052675e51741bb9b09dcdabc3f5512f501d49fe5",
|
|
||||||
"zh:883a06e44b64764459c1d0b37f24b52134a9fb95d7332f95b2b3c2271b76a958",
|
|
||||||
"zh:96ca7255602e1f38b42515533bac2e77313163638ef6e68c08a7772ab2515ed6",
|
|
||||||
"zh:9bad5d9a023aa238f34db6a05c1ea67f19f2c27fe640be76ec77d850e8cbecf6",
|
|
||||||
"zh:aebf8480d0cccbca57a085ccabb5af23d0e35a8d6e54b1bef15ae6432cfdf229",
|
|
||||||
"zh:c7114896af26237cd01395c10f81a670752cc103d6ce602e88f81f205987e617",
|
|
||||||
"zh:c84819a708453cc321746eba5fc4bab972e3735607b6533b3d9bab79c3f0d196",
|
|
||||||
"zh:ee82069747c38737e88f01007de0a1180770c14de26c13b79c9cc340204237fc",
|
|
||||||
"zh:f53439d40f328b0e4800d8ed00f18bc39b2b03ac3d776b0c7b497722d7f7f0b1",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# Network
|
|
||||||
resource "yandex_vpc_network" "default" {
|
|
||||||
name = "net"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "yandex_vpc_subnet" "default" {
|
|
||||||
name = "subnet"
|
|
||||||
zone = "ru-central1-a"
|
|
||||||
network_id = "${yandex_vpc_network.default.id}"
|
|
||||||
v4_cidr_blocks = ["192.168.101.0/24"]
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
resource "yandex_compute_instance" "node01" {
|
|
||||||
name = "node01"
|
|
||||||
zone = "ru-central1-a"
|
|
||||||
hostname = "node01.netology.cloud"
|
|
||||||
allow_stopping_for_update = true
|
|
||||||
|
|
||||||
resources {
|
|
||||||
cores = 8
|
|
||||||
memory = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_disk {
|
|
||||||
initialize_params {
|
|
||||||
image_id = "${var.centos-7-base}"
|
|
||||||
name = "root-node01"
|
|
||||||
type = "network-nvme"
|
|
||||||
size = "50"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
network_interface {
|
|
||||||
subnet_id = "${yandex_vpc_subnet.default.id}"
|
|
||||||
nat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata = {
|
|
||||||
ssh-keys = "centos:${file("~/.ssh/id_rsa.pub")}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
output "internal_ip_address_node01_yandex_cloud" {
|
|
||||||
value = "${yandex_compute_instance.node01.network_interface.0.ip_address}"
|
|
||||||
}
|
|
||||||
|
|
||||||
output "external_ip_address_node01_yandex_cloud" {
|
|
||||||
value = "${yandex_compute_instance.node01.network_interface.0.nat_ip_address}"
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Provider
|
|
||||||
terraform {
|
|
||||||
required_providers {
|
|
||||||
yandex = {
|
|
||||||
source = "yandex-cloud/yandex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
provider "yandex" {
|
|
||||||
token = var.yandex_cloud_token
|
|
||||||
cloud_id = var.yandex_cloud_id
|
|
||||||
folder_id = var.yandex_folder_id
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Заменить на ID своего облака
|
|
||||||
# https://console.cloud.yandex.ru/cloud?section=overview
|
|
||||||
variable "yandex_cloud_id" {
|
|
||||||
default = "b1gu1gt5nqi6lqgu3t7s"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Заменить на Folder своего облака
|
|
||||||
# https://console.cloud.yandex.ru/cloud?section=overview
|
|
||||||
variable "yandex_folder_id" {
|
|
||||||
default = "b1gaec42k169jqpo02f7"
|
|
||||||
}
|
|
||||||
|
|
||||||
# OAuth токен, используемый утилитой yc. Применялся на этапе с packer.
|
|
||||||
variable "yandex_cloud_token" {
|
|
||||||
default = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# Заменить на ID своего образа
|
|
||||||
# ID можно узнать с помощью команды yc compute image list
|
|
||||||
variable "centos-7-base" {
|
|
||||||
default = "fd8ft6norj68lo29qlpi"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
inventory
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
FROM prom/alertmanager:v0.15.3
|
|
||||||
|
|
||||||
COPY conf /etc/alertmanager/
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/etc/alertmanager/docker-entrypoint.sh" ]
|
|
||||||
CMD [ "--config.file=/etc/alertmanager/alertmanager.yml", \
|
|
||||||
"--storage.path=/alertmanager" ]
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
route:
|
|
||||||
receiver: 'slack'
|
|
||||||
|
|
||||||
receivers:
|
|
||||||
- name: 'slack'
|
|
||||||
slack_configs:
|
|
||||||
- send_resolved: true
|
|
||||||
text: "{{ .CommonAnnotations.description }}"
|
|
||||||
#username: <user>#
|
|
||||||
#channel: <channel>#
|
|
||||||
#api_url: <url>#
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
cat /etc/alertmanager/alertmanager.yml |\
|
|
||||||
sed "s@#api_url: <url>#@api_url: '$SLACK_URL'@g" |\
|
|
||||||
sed "s@#channel: <channel>#@channel: '#$SLACK_CHANNEL'@g" |\
|
|
||||||
sed "s@#username: <user>#@username: '$SLACK_USER'@g" > /tmp/alertmanager.yml
|
|
||||||
|
|
||||||
mv /tmp/alertmanager.yml /etc/alertmanager/alertmanager.yml
|
|
||||||
|
|
||||||
set -- /bin/alertmanager "$@"
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
:9090 {
|
|
||||||
basicauth / {$ADMIN_USER} {$ADMIN_PASSWORD}
|
|
||||||
proxy / prometheus:9090 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
:9093 {
|
|
||||||
basicauth / {$ADMIN_USER} {$ADMIN_PASSWORD}
|
|
||||||
proxy / alertmanager:9093 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
:9094 {
|
|
||||||
basicauth / {$ADMIN_USER} {$ADMIN_PASSWORD}
|
|
||||||
proxy / unsee:8080 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
:3000 {
|
|
||||||
proxy / grafana:3000 {
|
|
||||||
transparent
|
|
||||||
websocket
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
version: "3.3"
|
|
||||||
|
|
||||||
networks:
|
|
||||||
net:
|
|
||||||
driver: overlay
|
|
||||||
attachable: true
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
prometheus: {}
|
|
||||||
grafana: {}
|
|
||||||
alertmanager: {}
|
|
||||||
|
|
||||||
configs:
|
|
||||||
caddy_config:
|
|
||||||
file: ./caddy/Caddyfile
|
|
||||||
dockerd_config:
|
|
||||||
file: ./dockerd-exporter/Caddyfile
|
|
||||||
node_rules:
|
|
||||||
file: ./prometheus/rules/swarm_node.rules.yml
|
|
||||||
task_rules:
|
|
||||||
file: ./prometheus/rules/swarm_task.rules.yml
|
|
||||||
|
|
||||||
services:
|
|
||||||
dockerd-exporter:
|
|
||||||
image: stefanprodan/caddy
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
environment:
|
|
||||||
- DOCKER_GWBRIDGE_IP=172.18.0.1
|
|
||||||
configs:
|
|
||||||
- source: dockerd_config
|
|
||||||
target: /etc/caddy/Caddyfile
|
|
||||||
deploy:
|
|
||||||
mode: global
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 128M
|
|
||||||
reservations:
|
|
||||||
memory: 64M
|
|
||||||
|
|
||||||
cadvisor:
|
|
||||||
image: google/cadvisor
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
command: -logtostderr -docker_only
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
- /:/rootfs:ro
|
|
||||||
- /var/run:/var/run
|
|
||||||
- /sys:/sys:ro
|
|
||||||
- /var/lib/docker/:/var/lib/docker:ro
|
|
||||||
deploy:
|
|
||||||
mode: global
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 128M
|
|
||||||
reservations:
|
|
||||||
memory: 64M
|
|
||||||
|
|
||||||
grafana:
|
|
||||||
image: stefanprodan/swarmprom-grafana:5.3.4
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
environment:
|
|
||||||
- GF_SECURITY_ADMIN_USER=${ADMIN_USER:-admin}
|
|
||||||
- GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin}
|
|
||||||
- GF_USERS_ALLOW_SIGN_UP=false
|
|
||||||
#- GF_SERVER_ROOT_URL=${GF_SERVER_ROOT_URL:-localhost}
|
|
||||||
#- GF_SMTP_ENABLED=${GF_SMTP_ENABLED:-false}
|
|
||||||
#- GF_SMTP_FROM_ADDRESS=${GF_SMTP_FROM_ADDRESS:-grafana@test.com}
|
|
||||||
#- GF_SMTP_FROM_NAME=${GF_SMTP_FROM_NAME:-Grafana}
|
|
||||||
#- GF_SMTP_HOST=${GF_SMTP_HOST:-smtp:25}
|
|
||||||
#- GF_SMTP_USER=${GF_SMTP_USER}
|
|
||||||
#- GF_SMTP_PASSWORD=${GF_SMTP_PASSWORD}
|
|
||||||
volumes:
|
|
||||||
- grafana:/var/lib/grafana
|
|
||||||
deploy:
|
|
||||||
mode: replicated
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.role == manager
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 128M
|
|
||||||
reservations:
|
|
||||||
memory: 64M
|
|
||||||
|
|
||||||
alertmanager:
|
|
||||||
image: stefanprodan/swarmprom-alertmanager:v0.14.0
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
environment:
|
|
||||||
- SLACK_URL=${SLACK_URL:-https://hooks.slack.com/services/TOKEN}
|
|
||||||
- SLACK_CHANNEL=${SLACK_CHANNEL:-general}
|
|
||||||
- SLACK_USER=${SLACK_USER:-alertmanager}
|
|
||||||
command:
|
|
||||||
- '--config.file=/etc/alertmanager/alertmanager.yml'
|
|
||||||
- '--storage.path=/alertmanager'
|
|
||||||
volumes:
|
|
||||||
- alertmanager:/alertmanager
|
|
||||||
deploy:
|
|
||||||
mode: replicated
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.role == manager
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 128M
|
|
||||||
reservations:
|
|
||||||
memory: 64M
|
|
||||||
|
|
||||||
unsee:
|
|
||||||
image: cloudflare/unsee:v0.8.0
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
environment:
|
|
||||||
- "ALERTMANAGER_URIS=default:http://alertmanager:9093"
|
|
||||||
deploy:
|
|
||||||
mode: replicated
|
|
||||||
replicas: 1
|
|
||||||
|
|
||||||
node-exporter:
|
|
||||||
image: stefanprodan/swarmprom-node-exporter:v0.16.0
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
environment:
|
|
||||||
- NODE_ID={{.Node.ID}}
|
|
||||||
volumes:
|
|
||||||
- /proc:/host/proc:ro
|
|
||||||
- /sys:/host/sys:ro
|
|
||||||
- /:/rootfs:ro
|
|
||||||
- /etc/hostname:/etc/nodename
|
|
||||||
command:
|
|
||||||
- '--path.sysfs=/host/sys'
|
|
||||||
- '--path.procfs=/host/proc'
|
|
||||||
- '--collector.textfile.directory=/etc/node-exporter/'
|
|
||||||
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
|
|
||||||
- '--no-collector.ipvs'
|
|
||||||
deploy:
|
|
||||||
mode: global
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 128M
|
|
||||||
reservations:
|
|
||||||
memory: 64M
|
|
||||||
|
|
||||||
prometheus:
|
|
||||||
image: stefanprodan/swarmprom-prometheus:v2.5.0
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
command:
|
|
||||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
|
||||||
- '--storage.tsdb.path=/prometheus'
|
|
||||||
- '--storage.tsdb.retention=${PROMETHEUS_RETENTION:-24h}'
|
|
||||||
volumes:
|
|
||||||
- prometheus:/prometheus
|
|
||||||
configs:
|
|
||||||
- source: node_rules
|
|
||||||
target: /etc/prometheus/swarm_node.rules.yml
|
|
||||||
- source: task_rules
|
|
||||||
target: /etc/prometheus/swarm_task.rules.yml
|
|
||||||
deploy:
|
|
||||||
mode: replicated
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.role == manager
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 2048M
|
|
||||||
reservations:
|
|
||||||
memory: 128M
|
|
||||||
|
|
||||||
caddy:
|
|
||||||
image: stefanprodan/caddy
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
- "9090:9090"
|
|
||||||
- "9093:9093"
|
|
||||||
- "9094:9094"
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
environment:
|
|
||||||
- ADMIN_USER=${ADMIN_USER:-admin}
|
|
||||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin}
|
|
||||||
configs:
|
|
||||||
- source: caddy_config
|
|
||||||
target: /etc/caddy/Caddyfile
|
|
||||||
deploy:
|
|
||||||
mode: replicated
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.role == manager
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 128M
|
|
||||||
reservations:
|
|
||||||
memory: 64M
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 1s
|
|
||||||
retries: 5
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
:9323 {
|
|
||||||
proxy / {$DOCKER_GWBRIDGE_IP}:9323 {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
errors stderr
|
|
||||||
tls off
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
FROM grafana/grafana:5.3.4
|
|
||||||
# https://hub.docker.com/r/grafana/grafana/tags/
|
|
||||||
|
|
||||||
COPY datasources /etc/grafana/provisioning/datasources/
|
|
||||||
COPY swarmprom_dashboards.yml /etc/grafana/provisioning/dashboards/
|
|
||||||
COPY dashboards /etc/grafana/dashboards/
|
|
||||||
|
|
||||||
ENV GF_SECURITY_ADMIN_PASSWORD=admin \
|
|
||||||
GF_SECURITY_ADMIN_USER=admin \
|
|
||||||
GF_PATHS_PROVISIONING=/etc/grafana/provisioning/
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
apiVersion: 1
|
|
||||||
|
|
||||||
deleteDatasources:
|
|
||||||
- name: Prometheus
|
|
||||||
|
|
||||||
datasources:
|
|
||||||
- name: Prometheus
|
|
||||||
type: prometheus
|
|
||||||
access: proxy
|
|
||||||
url: http://prometheus:9090
|
|
||||||
isDefault: true
|
|
||||||
version: 1
|
|
||||||
editable: true
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
apiVersion: 1
|
|
||||||
|
|
||||||
providers:
|
|
||||||
- name: 'default'
|
|
||||||
orgId: 1
|
|
||||||
folder: ''
|
|
||||||
type: file
|
|
||||||
disableDeletion: false
|
|
||||||
editable: true
|
|
||||||
options:
|
|
||||||
path: /etc/grafana/dashboards
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
FROM prom/node-exporter:v0.16.0
|
|
||||||
|
|
||||||
ENV NODE_ID=none
|
|
||||||
|
|
||||||
USER root
|
|
||||||
|
|
||||||
COPY conf /etc/node-exporter/
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/etc/node-exporter/docker-entrypoint.sh" ]
|
|
||||||
CMD [ "/bin/node_exporter" ]
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
NODE_NAME=$(cat /etc/nodename)
|
|
||||||
echo "node_meta{node_id=\"$NODE_ID\", container_label_com_docker_swarm_node_id=\"$NODE_ID\", node_name=\"$NODE_NAME\"} 1" > /etc/node-exporter/node-meta.prom
|
|
||||||
|
|
||||||
set -- /bin/node_exporter "$@"
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
FROM prom/prometheus:v2.5.0
|
|
||||||
# https://hub.docker.com/r/prom/prometheus/tags/
|
|
||||||
|
|
||||||
ENV WEAVE_TOKEN=none
|
|
||||||
|
|
||||||
COPY conf /etc/prometheus/
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/etc/prometheus/docker-entrypoint.sh" ]
|
|
||||||
CMD [ "--config.file=/etc/prometheus/prometheus.yml", \
|
|
||||||
"--storage.tsdb.path=/prometheus" ]
|
|
||||||