193 Commits
fix ... main

Author SHA1 Message Date
5a9342e8ad [graduate work] fixes 2023-04-01 12:55:19 +07:00
916e277dd3 [graduate work] fixes 2023-04-01 12:43:39 +07:00
4f680cf63f [graduate work] complete final stage 5 2023-04-01 12:38:31 +07:00
94ea966dd8 [graduate work] complete stage 3 2023-03-22 15:35:56 +07:00
2a3fa493b2 [graduate work] complete stage 3 2023-03-20 09:45:57 +07:00
c87a0127f8 [graduate work] complete stage 2 2023-03-17 11:12:59 +07:00
e736eb9646 [graduate work] complete stage 1 2023-03-15 10:30:10 +07:00
da0d12a837 gw: some work 2023-03-13 11:05:05 +07:00
913bfc8dab gw: add graduate work task description 2023-03-13 10:09:57 +07:00
d84dfbc6f5 homework 15.3: complete part 1 task 1, partially complete part 2 task 1 2023-02-13 10:45:51 +07:00
819768cb44 homework 15.2: complete all tasks 2023-02-09 10:28:02 +07:00
e197b5e0ff homework 15.2: fix part 2 of task 1 2023-02-08 11:13:27 +07:00
11c7275b96 homework 15.2: partially complete part 2 from task 1 2023-02-07 11:09:16 +07:00
82c8bbcd85 homework 15.2: complete part 1 from task 1 2023-02-06 10:44:57 +07:00
e9b39f0724 homework 15.1: fix task 2023-01-31 09:50:11 +07:00
575e4a080b homework 15.1: partially complete task 1 2023-01-30 11:01:15 +07:00
9c751a66dc fix readme 2023-01-17 10:44:03 +07:00
96cabba22c homework 14.5: complete all tasks 2023-01-17 10:41:50 +07:00
5b9daf3457 homework 14.4: complete all tasks 2023-01-10 09:58:40 +07:00
caad4499bf homework 14.3: complete all tasks 2022-12-29 10:25:38 +07:00
4270c65a26 homework 14.2: complete all tasks 2022-12-27 10:15:07 +07:00
5b51a90b4d homework 14.1: complete all tasks 2022-12-23 10:25:53 +07:00
2e7a604149 fix typo for homeworks 13 directory 2022-12-23 09:46:05 +07:00
b5268a1370 homework 13.5: complete all tasks 2022-12-21 10:57:52 +07:00
038e25150d homework 13.4: fix helm chart, complete second task 2022-12-20 10:59:15 +07:00
c498e391d2 common: add readme for configuration k8s cluster in terraform 2022-12-20 10:58:41 +07:00
5dbfc8a290 homework 13.4: complete first task, partially complete 2 task 2022-12-19 11:03:01 +07:00
6fab2cab4d homework 13.3: complete all tasks 2022-12-14 10:31:43 +07:00
441969f862 homework 13.3: complete connect to db through port-forward 2022-12-13 11:13:53 +07:00
7de8fc4fbb homework 13.3: fix prod back and front deployments from 13.1 2022-12-13 11:01:31 +07:00
8f021f73cc homework 13.3: fix prod database deployment from homework 13.1 2022-12-13 10:58:11 +07:00
db3f828e88 homework 13.3: partially complete task 1 2022-12-09 10:46:15 +07:00
48060d8668 homework 13.2: complete all tasks 2022-12-07 10:41:22 +07:00
9cf0d09a3e homework 13.1: complete task 2 2022-12-05 10:21:05 +07:00
73c76b404c homework 13.1: fix task 1 2022-12-02 10:56:35 +07:00
0a94c5f7b4 homework 13.1: complete task 1
fix and improve project
2022-11-30 10:36:17 +07:00
3939c0a437 homework 13.1: add project 2022-11-29 10:54:09 +07:00
4c4515e096 homework 12.5: complete all tasks 2022-11-22 10:46:15 +07:00
9410f7df20 add terraform config for mini k8s cluster 2022-11-22 10:45:30 +07:00
7f8349661f homework 12.4: complete task 2 2022-11-18 10:26:07 +07:00
1781ad4310 homework 12.4: complete task 1: create kubespray inventory example
also create tf config for task 2
2022-11-16 10:34:05 +07:00
4f4731ccc7 homework 12.3: complete all tasks 2022-11-14 10:12:55 +07:00
71e0b53442 homework 12.2: complete rest tasks 2022-11-09 10:22:11 +07:00
b1b8546066 homework 12.2: complete task 1, partially complete task 2 2022-11-08 10:47:30 +07:00
f686140890 homework 12.1: complete task 2, partially complete task 3 2022-10-31 10:59:16 +07:00
bcf8d900c0 homework 12.1: add link to root readme 2022-10-27 10:47:55 +07:00
a3096ba1b6 homework 12.1: complete task 1, partially complete task 2 2022-10-27 10:47:07 +07:00
5dfc2e7428 homework 11.4: complete homework 2022-10-26 09:45:48 +07:00
61a95ffd50 homework 11.3: complete homework 2022-10-25 16:55:18 +07:00
fb4b18368b homework 11.3: remove todo, add links to brokers 2022-10-25 10:37:10 +07:00
792fe1b401 homework 11.3: complete homework 2022-10-25 10:34:54 +07:00
6aec724e6f homework 11.1: complete homework 2022-10-24 09:50:43 +07:00
3eccbe572e homework 10.6: fix link 2022-10-19 12:53:44 +07:00
c7c34fbbbf homework 10.6: remove todo 2022-10-19 12:53:07 +07:00
8df7811705 homework 10.6: complete all tasks 2022-10-19 12:51:32 +07:00
5fcacd72fe homework 10.5: complete all tasks 2022-10-18 17:39:22 +07:00
cf2c1e633a homework 10.4: complete all tasks 2022-10-17 10:58:59 +07:00
91d0541f99 fix typo 2022-10-05 14:54:33 +07:00
cc1297a674 homework 10.3: complete rest of homework 2022-10-05 14:52:15 +07:00
cf7e8c27f2 homework 10.3: complete 1 task, add partially complete 2 task 2022-10-05 10:48:00 +07:00
6b5f084474 homework 10.2: complete all tasks 2022-09-30 10:19:05 +07:00
17645cb717 homework 10.2: complete tasks 1-2 2022-09-29 10:32:06 +07:00
baa0cb8ca6 homework 10.1: complete task 2 2022-09-23 09:39:42 +07:00
c9168ad6e1 homework 10.1: complete main task 2022-09-21 10:40:24 +07:00
3d932f172e homework 9.6: complete all tasks 2022-09-19 11:47:25 +07:00
4e5bd60702 homework 9.5: complete all tasks 2022-09-12 10:54:25 +07:00
fa0e7533ae homework 9.4: complete 2022-09-07 10:47:01 +07:00
f9f6fd45c5 homework 9.4: fix ansible playbook 2022-09-07 09:32:10 +07:00
3719f701ed homework 9.4: fix ansible playbook, complete some part of homework 2022-09-05 11:00:50 +07:00
bfa45b409c fix playbook for jenkins-agent 2022-09-01 10:37:32 +07:00
6eb86580b9 homework 9.4: fix playbook 2022-08-31 09:54:33 +07:00
605c94642c add homework 9.4, add some preparations 2022-08-30 10:52:53 +07:00
74109940d9 add homework 9.3, complete it 2022-08-24 10:56:14 +07:00
5c973fe83b add homework 9.1, complete it 2022-08-18 10:38:52 +07:00
6dc0b0ec9f homework 8.6: fixes 2022-08-15 10:25:29 +07:00
6d127803da homework 8.6: complete other tasks
move module files to separate dir
2022-08-15 10:23:42 +07:00
4e51fca06b add homework 8.6, complete first part of homework 2022-08-12 10:50:49 +07:00
ba3b1bd592 homework 8.5: finalize 2022-08-08 10:56:06 +07:00
2e574a6137 homework 8.5: trying to use podman inside docker container 2022-08-08 10:38:44 +07:00
b6083748b2 add homework 8.5, complete molecule part 2022-08-05 10:27:41 +07:00
118b94d9a2 homework 8.4: create vector role, complete homework 2022-08-02 10:16:48 +07:00
0115945805 homework 8.4: partially complete 2022-08-01 10:45:28 +07:00
fbece247aa complete homework 8.3 2022-07-28 10:38:29 +07:00
c4ad5d2340 add incomplete homework 8.3 2022-07-27 10:55:01 +07:00
aa356db95c add homework 8.2 2022-07-22 10:58:37 +07:00
6a60a4994a homework 8.1: complete task 12 2022-07-18 09:30:33 +07:00
a77475a313 homework 8.1: partially complete task 2 2022-07-13 19:34:21 +07:00
15e64885aa add homework 8.1, task 1 and partial task 2 2022-07-13 10:36:57 +07:00
f297e4a942 ad homework 7.6 2022-07-07 10:45:51 +07:00
2befd048b1 add homework 7.5 2022-07-01 11:20:00 +07:00
80bba26666 homework 7.4: add missing envs to .env.example 2022-06-28 13:52:16 +07:00
8959c84e46 add homework 7.4 2022-06-28 13:48:50 +07:00
bb13a1061e homework 7.3: add task 2 2022-06-23 15:24:11 +07:00
55f07be3d0 add homework 7.3, complete task 1 2022-06-23 14:11:59 +07:00
d0c2a3e7ab homework 7.2: fix terraform commands 2022-06-21 11:19:18 +07:00
ac52a84f9d homework 7.2: remove note about makefile 2022-06-21 11:17:15 +07:00
f1bad04e52 add link to homework 7.2 to main readme 2022-06-21 11:14:41 +07:00
e4f139a3e2 add homework 7.2 2022-06-21 11:11:39 +07:00
7f4f3b2701 add homework 7.1 2022-06-16 13:30:46 +07:00
2ef3469443 homework 6.6: add additional_notes 2022-06-15 12:04:21 +07:00
93dcd900fd homework 6.6: add tasks 3-4 2022-06-14 10:11:44 +07:00
a7c5bd2e6d homework 6.6 add task 2 2022-06-13 11:06:11 +07:00
cbfe59f7cf add homewort 6.6: task 1 2022-06-13 10:44:00 +07:00
e25749fa66 homework 6.5: add task 3 2022-06-08 17:52:45 +07:00
f0ea7634b9 homework 6.5: add task 2 2022-06-08 10:34:29 +07:00
6eec8fe432 add homework 6.5: task 1 2022-06-08 10:33:39 +07:00
8468fc0c80 homework 6.4: add task 4 2022-06-08 10:33:25 +07:00
c7a639e42c add homework 6.4: tasks 1-3 2022-06-08 10:33:14 +07:00
7870726c8c homework 6.3: add tasks 3-4 2022-06-08 10:32:47 +07:00
d91cf25300 add homework 6.3, tasks 1-2 2022-05-27 10:32:54 +07:00
c5157f19fe homework 6.2: trying to fix anchors 2022-05-25 10:47:17 +07:00
055835d5bd homework 6.2: trying to fix anchors 2022-05-25 10:44:49 +07:00
a99efd3182 homework 6.2: add tasks 3-6 2022-05-25 10:41:54 +07:00
5f8b131742 add homework 6.2 task 1-2 2022-05-23 12:33:35 +07:00
cf6348de9d homework 6.1: add task 4 2022-05-19 09:42:03 +07:00
ce2fdddc9e add homework 6.1, tasks 1-3 2022-05-18 10:37:52 +07:00
991819fa39 homework 5.5: add task 2-3 2022-05-16 10:35:39 +07:00
500c7cac71 add homework 5.5, task 1 2022-05-13 10:04:46 +07:00
c464d8ccbe add homework 5.4 2022-05-11 10:55:12 +07:00
dd9731b3d5 fix all homeworks in 03-sysadmin 2022-05-06 11:28:52 +07:00
6867d8f214 fix homework 3.1 2022-05-06 10:55:57 +07:00
f0ccb8abfc fix homework 1.1 2022-05-06 10:51:58 +07:00
0c2b7164e5 fix homework 2.1 2022-05-06 10:50:35 +07:00
30e6c7d15c homework 5.3: fix typo 2022-05-05 10:52:42 +07:00
668518caa7 homework 5.3: add link to root readme 2022-05-05 10:51:59 +07:00
6c52082e89 homework 5.3: complete tasks 2-4 2022-05-05 10:50:47 +07:00
f41bc70752 add homework 5.3, complete task 1 2022-05-04 10:29:39 +07:00
4db8d0e5cb add homework 5.2 2022-04-27 09:48:56 +07:00
fa0db0f0c9 fix homework 5.1 2022-04-22 10:37:56 +07:00
89a102965c add homework 5.1 2022-04-21 10:46:07 +07:00
eb9e50219b homework 4.3 complete question 2 2022-04-13 14:57:25 +07:00
d08d7fbd23 add homework 4.3 question 2 script 2022-04-13 11:24:46 +07:00
7f1c39c306 add homework 4.3 skeleton 2022-04-12 10:34:35 +07:00
10cd187006 add notes 04-yaml, move homework 4.1 to subdirectory 2022-04-12 10:33:57 +07:00
744437c4d6 homework 4.2: add question 4 2022-04-11 10:33:47 +07:00
4ab000a022 homework 4.2: add question 3 2022-04-08 10:46:48 +07:00
2981f9cab8 homework 4.2: add questions 1-2, move homework to subdir 2022-04-07 10:38:49 +07:00
31fbe09273 homework 4.1: fix question 1 2022-04-07 10:02:56 +07:00
c5a965e2e6 homework 4.1: fix question 2 2022-04-07 09:57:25 +07:00
2f7fd3bee7 reorganize homeworks structure for parts 1-3 2022-04-06 10:23:15 +07:00
e8c9ed8597 add homework 4.2 2022-04-06 10:16:18 +07:00
e03f31515e homework 4.1: add all questions 2022-04-04 12:14:09 +07:00
7ff630ea1b add homework 4.1 2022-04-04 10:10:53 +07:00
095dd4d5e7 fix typos 2022-04-01 10:36:05 +07:00
bdefa134e4 add notes about bash 2022-04-01 10:35:39 +07:00
031663a2d0 homework 3.9: add questions 1-2 2022-03-30 18:26:16 +07:00
e7ab05b3d7 homework 3.9: add questions 5-7 2022-03-30 10:37:46 +07:00
b381b87108 add homework 3.9, questions 3-4 2022-03-28 10:35:15 +07:00
ab5a27d49b add notes about ssh and web-servers 2022-03-25 11:11:31 +07:00
0102e39a28 homework 3.8: complete question 6 2022-03-21 11:05:47 +07:00
65961da59c homework 3.8: add incomplete question 6 2022-03-17 10:39:08 +07:00
1803ea0ee5 homework 3.8: add question 5 2022-03-17 10:10:40 +07:00
9f2416a8e6 homework 3.7: fix questions 5 and 6 2022-03-17 09:40:04 +07:00
66e89b14ba add homework 3.8: add questions 1-4 2022-03-16 10:37:08 +07:00
85cbbfcd49 homework 3.7: add questions 6-7 2022-03-14 09:49:03 +07:00
d09a34019f add homework 3.7, questions 1-5 2022-03-11 09:46:15 +07:00
c415c28414 upd notes 2022-03-10 10:28:58 +07:00
a7d9728049 add homework 3.6 2022-03-09 10:34:47 +07:00
661a776242 add network notes 2022-03-04 10:19:39 +07:00
b65464a793 homework 3.5: add rest questions 2022-03-02 10:20:33 +07:00
b84f3d65c8 add homework 3.5, questions 1-9 2022-03-01 11:00:27 +07:00
b8152b19d7 add notes about filesystems 2022-02-28 10:40:00 +07:00
bfbfbe4741 homework 3.4: add questions 5-7 2022-02-25 10:51:17 +07:00
baeffe48f3 add homework 3.4 with questions 1-4 2022-02-23 12:01:47 +07:00
8b97fa3d96 add some notes 2022-02-22 10:40:17 +07:00
7809040991 homework 3.3: add questions 7-9 2022-02-21 10:10:35 +07:00
e545b8389a homework 3.3: add questions 4-6 2022-02-18 10:24:00 +07:00
78a0ccf4d8 add homework 3.3, questions 1-3 2022-02-16 10:42:12 +07:00
a3b6b95ff7 add homework 3.2 to main readme 2022-02-10 19:15:41 +07:00
29babcee44 homework 3.2 add answers 12-14 2022-02-10 19:14:23 +07:00
ae9d777eb0 homework 3.2 add answers 8-11 2022-02-10 10:49:16 +07:00
076547c1d2 homework 3.2 fix answer 7 2022-02-09 10:41:39 +07:00
9a7cce46fa add homework 3.2 questions 1-7 2022-02-09 10:25:46 +07:00
2272f0eb4c fix answer for question about double square brackets
add script, that proves than answer
2022-02-07 10:22:21 +07:00
46b258727c change homework 3.1 structure 2022-02-03 19:25:54 +07:00
37a74a2cf9 add homework 3.1 2022-02-03 19:23:15 +07:00
e8132417ba add vagrant config 2022-02-03 19:22:08 +07:00
1d4751ae34 update readme 2022-01-31 19:19:42 +07:00
2809e3318f add 2.4 homework 2022-01-31 19:18:17 +07:00
4892793e80 Merge branch 'git-rebase' into main 2022-01-28 10:06:36 +07:00
fc54720d4b Merge branch 'git-merge' into main 2022-01-28 10:03:58 +07:00
5efdd24822 Merge branch 'git-merge' into main 2022-01-28 09:57:52 +07:00
4669b409b9 change rebase.sh 2022-01-28 09:48:49 +07:00
b305eaa877 merge: use shift 2022-01-28 09:47:41 +07:00
f767ec7e6a merge: @ instead * 2022-01-28 09:46:48 +07:00
aa455677ef prepare for merge and rebase 2022-01-28 09:45:20 +07:00
f176fb5cbc add homework 2.3 2022-01-28 09:44:48 +07:00
28992c5067 update readme 2022-01-27 20:06:52 +07:00
fb5a128942 add notes 2022-01-27 19:52:32 +07:00
f5483693e4 add 2.2 homework 2022-01-24 18:15:48 +07:00
65a7af6b36 add 1.1 paragraph name 2022-01-19 19:01:21 +07:00
f5e3eaada3 clean up 2022-01-19 19:00:18 +07:00
93b549bc5c Moved and deleted 2022-01-19 18:59:37 +07:00
498 changed files with 46024 additions and 9 deletions

View File

@@ -2,5 +2,89 @@
## Homeworks
* [1.1](/src/homework/1.1)
* [2.1 Системы контроля версий](/src/homework/2.1)
* [01.1 Введение в DevOps](/src/homework/01-intro/1.1)
* [02.1 Системы контроля версий](/src/homework/02-git/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)

316
src/graduate_work/readme.md Normal file
View File

@@ -0,0 +1,316 @@
## Дипломная работа
Выполнение дипломной работы курса 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.

136
src/graduate_work/tasks.md Normal file
View File

@@ -0,0 +1,136 @@
## Цели
* [Цели](#цели)
* [Этапы выполнения](#этапы-выполнения)
* [Создание облачной инфраструктуры](#создание-облачной-инфраструктуры)
* [Создание 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)

View File

@@ -1,4 +1,15 @@
## Задание №2 - Описание жизненного цикла задачи
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/01-intro-01/README.md)
по теме "Введение в DevOps".
## Q/A
### Задача 1
![task1](./task1.png)
### Задача 2
Описание жизненного цикла задачи:
1. Постановка задачи (менеджер)
2. Оценка задачи (менеджер + разработчик)

View File

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 243 KiB

View File

@@ -1,6 +1,11 @@
## gitignore
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/02-git-01-vcs/README.md)
по теме "Системы контроля версий".
Создана директория [src/terraform](/src/terraform), добавлен файл: [terraform/.gitignore](/src/terraform/.gitignore).
## Q/A
### Задача 1 - gitignore
Создана директория [src/terraform](./terraform), добавлен файл: [terraform/.gitignore](./terraform/.gitignore).
Файлы, которые будут проигнорированы git:

View File

@@ -0,0 +1,8 @@
Выполнение [домашнего задания](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/)

View File

@@ -0,0 +1,9 @@
#!/bin/bash
# display command line options
count=1
while [[ -n "$1" ]]; do
echo "Parameter #$count = $1"
count=$(( $count + 1 ))
shift
done

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# display command line options
count=1
for param in "$@"; do
echo "Next parameter: $param"
count=$(( $count + 1 ))
done
echo "====="

View File

@@ -1 +1,2 @@
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/02-git-01-vcs/README.md) по теме "Системы контроля версий".
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/02-git-03-branching/README.md)
по теме "Ветвления в Git".

View File

@@ -0,0 +1,120 @@
Выполнение [домашнего задания](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`

View File

@@ -0,0 +1,17 @@
# 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`

View File

@@ -0,0 +1,7 @@
#!/bin/bash
[[ -d /tmp ]]
echo $?
[[ -d /tmp/some-dir ]]
echo $?

View File

@@ -0,0 +1,78 @@
Выполнение [домашнего задания](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`?
Ничем, это одна и та же команда.

View File

@@ -0,0 +1,139 @@
Выполнение [домашнего задания](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` будет работать,
так как процесс берёт стандартный поток ввода от текущего пользователя, затем начинает запись с повышенными привилегиями.

View File

@@ -0,0 +1,140 @@
Выполнение [домашнего задания](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/kernel/{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`).

View File

@@ -0,0 +1,234 @@
Выполнение [домашнего задания](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>`.

View File

@@ -0,0 +1,429 @@
Выполнение [домашнего задания](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
```

View File

@@ -0,0 +1,231 @@
Выполнение [домашнего задания](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/`).
Скриншот консоли браузера:
![stackoverflow.png](stackoverflow.png)
### Задача 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
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

View File

@@ -0,0 +1,133 @@
Выполнение [домашнего задания](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
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1 @@
<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>

View File

@@ -0,0 +1,243 @@
Выполнение [домашнего задания](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).
![network.png](network.png)
### Задача 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 пытается проксировать запрос на несуществующий адрес.

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,282 @@
Выполнение [домашнего задания](https://github.com/netology-code/sysadm-homeworks/blob/devsys10/03-sysadmin-09-security/README.md)
по теме "3.9. Элементы безопасности информационных систем".
## Q/A
### Задача 1
> Установите Bitwarden плагин для браузера. Зарегестрируйтесь и сохраните несколько паролей.
![bitwarden](bitwarden.png)
### Задача 2
> Установите Google authenticator на мобильный телефон. Настройте вход в Bitwarden акаунт через Google authenticator OTP.
Заместо `Google Authenticator` использовал приложение `Microsoft Authenticator`.
![birtwarden](bitwarden-2fa.png)
### Задача 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
```
Затем запустим графическое отображение утилиты и откроем в ней файл:
![wireshark](wireshark.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 KiB

View File

@@ -0,0 +1,119 @@
# 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 Normal file
View File

@@ -0,0 +1,2 @@
/curl.log
/error.log

View File

@@ -0,0 +1,9 @@
#!/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

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
while ((1==1))
do
curl https://localhost:4757
if (($? != 0))
then
date > curl.log;
else
break;
fi
done

View File

@@ -0,0 +1,14 @@
#!/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

View File

@@ -0,0 +1,27 @@
#!/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

View File

@@ -0,0 +1 @@
[04-script-01-bash] сломал хук слишком длинный комментарий

View File

@@ -0,0 +1 @@
сломал хук

View File

@@ -0,0 +1 @@
[04-script-01-bash] сломал хук

View File

@@ -0,0 +1,19 @@
#!/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

View File

@@ -0,0 +1,160 @@
Выполнение [домашнего задания](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 Normal file
View File

@@ -0,0 +1 @@
hosts.json

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env python3
a = 1
b = '2'
c = a + b
print(a, b, c)

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env python3
a = '1'
b = '2'
c = a + b
print(a, b, c)

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env python3
a = 1
b = 2
c = a + b
print(a, b, c)

View File

@@ -0,0 +1,13 @@
#!/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)

View File

@@ -0,0 +1,39 @@
#!/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)

View File

@@ -0,0 +1,40 @@
#!/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))

View File

@@ -0,0 +1,206 @@
Выполнение [домашнего задания](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 Normal file
View File

@@ -0,0 +1,2 @@
hosts.json
hosts.yaml

View File

@@ -0,0 +1,65 @@
#!/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()

View File

@@ -0,0 +1,150 @@
Выполнение [домашнего задания](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
```

View File

@@ -0,0 +1,78 @@
# 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:>
А этот
преобразует каждый переход на новую строку
в пробел
```

View File

@@ -0,0 +1,115 @@
Выполнение [домашнего задания](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
> Опишите возможные проблемы и недостатки гетерогенной среды виртуализации (использования нескольких систем управления виртуализацией одновременно) и что необходимо сделать для минимизации этих рисков и проблем.
Самая большая проблема гетерогенной среды виртуализации - это высокие расходы на поддержку и управления нескольких систем управления виртуальными машинами одновременно.
То есть, для подобного решения необходимо сразу несколько инженеров, которые будут специалистами в своей конкретной области/технологии.
Ещё одна проблема, которая может возникнуть - проблемы перемещения данных между виртуальными машинами, работающими в разных гипервизорах.
Для минимизации проблем, в общем случае, необходимо стараться максимально стандартизировать подход к виртуализации внутри компании.
> Если бы у вас был выбор, то создавали бы вы гетерогенную среду или нет? Мотивируйте ваш ответ примерами.
Для выбора решения необходимо на этапе построения всей инфраструктуры решить множество вопросов:
* определить, какие решения есть на рынке виртуализаций и сделать некие прогнозы на будущее
* сделать анализ рынка вакансий, определить "популярность" решений вирутализации
* определить конкретные требования к инфрастуктуре: какие системы/сервисы будут разворачиваться на виртуальных машинах,
кто будет пользовать данными системами и т.п.
* определить требования к безопасности
Только после ответа на данные вопросы можно решить, использовать ли единое решение для построения виртуализации, либо совместить решения.

View File

@@ -0,0 +1,119 @@
Выполнение [домашнего задания](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!
<...>
```

View File

@@ -0,0 +1,3 @@
*
!.gitignore

View File

@@ -0,0 +1,4 @@
FROM nginx:1.21.6-alpine
COPY site.conf /etc/nginx/conf.d/default.conf
COPY index.html /var/www/netology/index.html

View File

@@ -0,0 +1,39 @@
---
- 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/

View File

@@ -0,0 +1,8 @@
<html>
<head>
Hey, Netology
</head>
<body>
<h1>I`m DevOps Engineer!</h1>
</body>
</html>

View File

@@ -0,0 +1,12 @@
---
- 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

View File

@@ -0,0 +1,9 @@
server {
listen 80;
server_name localhost;
location / {
root /var/www/netology;
index index.html index.htm;
}
}

View File

@@ -0,0 +1,215 @@
Выполнение [домашнего задания](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>Im 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)

View File

@@ -0,0 +1 @@
inventory

View File

@@ -0,0 +1,5 @@
[defaults]
inventory=./inventory
deprecation_warnings=False
command_warnings=False
ansible_port=22

View File

@@ -0,0 +1,5 @@
[nodes:children]
manager
[manager]
node01.netology.cloud ansible_host=

View File

@@ -0,0 +1,63 @@
---
- 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

View File

@@ -0,0 +1,2 @@
ADMIN_USER=admin
ADMIN_PASSWORD=admin

View File

@@ -0,0 +1,11 @@
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>'

View File

@@ -0,0 +1,39 @@
: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
}

View File

@@ -0,0 +1,121 @@
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"

View File

@@ -0,0 +1,36 @@
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"

View File

@@ -0,0 +1,12 @@
apiVersion: 1
providers:
- name: 'Prometheus'
orgId: 1
folder: ''
type: file
disableDeletion: false
editable: true
allowUiUpdates: true
options:
path: /etc/grafana/provisioning/dashboards

View File

@@ -0,0 +1,11 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
orgId: 1
url: http://prometheus:9090
basicAuth: false
isDefault: true
editable: true

View File

@@ -0,0 +1,69 @@
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}}."

View File

@@ -0,0 +1,55 @@
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'

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

@@ -0,0 +1 @@
centos-7-base.json

View File

@@ -0,0 +1,27 @@
{
"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"
}
]
}

View File

@@ -0,0 +1,77 @@
Выполнение [домашнего задания](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`
**Результат**:
![cloud-images.png](./assets/cloud-images.png)
### Задача 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`
**Результат**:
![cloud-vm.png](./assets/cloud-vm.png)
### Задача 3
> Создать ваш первый готовый к боевой эксплуатации компонент мониторинга, состоящий из стека микросервисов.
>
> Для получения зачета, вам необходимо предоставить:
> - Скриншот работающего веб-интерфейса Grafana с текущими метриками
1. Копирование inventory файла для `ansible` из [inventory.example](./ansible/inventory.example) в `inventory`
2. Запуск `ansible`: `cd ansible && ansible-playbook provision.yml`
**Результат**:
![grafana.png](./assets/grafana.png)
### Clean up
Удаление всей инфраструктуры:
1. Удаление ВМ, сетей: `terraform destroy -auto-approve`
2. Удаление образа ОС: `yc compute image delete --id fd8oponkic4t99ecuk8k`

View File

@@ -0,0 +1,37 @@
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

View File

@@ -0,0 +1,22 @@
# 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",
]
}

View File

@@ -0,0 +1,11 @@
# 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"]
}

View File

@@ -0,0 +1,29 @@
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")}"
}
}

View File

@@ -0,0 +1,7 @@
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}"
}

View File

@@ -0,0 +1,14 @@
# 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
}

View File

@@ -0,0 +1,22 @@
# Заменить на 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"
}

View File

@@ -0,0 +1 @@
inventory

View File

@@ -0,0 +1,7 @@
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" ]

View File

@@ -0,0 +1,11 @@
route:
receiver: 'slack'
receivers:
- name: 'slack'
slack_configs:
- send_resolved: true
text: "{{ .CommonAnnotations.description }}"
#username: <user>#
#channel: <channel>#
#api_url: <url>#

View File

@@ -0,0 +1,12 @@
#!/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 "$@"

View File

@@ -0,0 +1,40 @@
: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
}

View File

@@ -0,0 +1,206 @@
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

View File

@@ -0,0 +1,8 @@
:9323 {
proxy / {$DOCKER_GWBRIDGE_IP}:9323 {
transparent
}
errors stderr
tls off
}

View File

@@ -0,0 +1,10 @@
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/

Some files were not shown because too many files have changed in this diff Show More