senkin_alexander_lab_2 is ready #7
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="JAVA_MODULE" version="4">
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
53
senkin_alexander_lab_2/README.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Лабораторная работа №2 - Разработка простейшего распределенного приложения
|
||||||
|
|
||||||
|
Цель: изучение техники создания простого распределенного приложения.
|
||||||
|
|
||||||
|
Задачи:
|
||||||
|
|
||||||
|
- Согласно вышему варианту (выбирайте любой) разработать два приложения такие, что результат первого является исходными данными для второго.
|
||||||
|
- Изучить файлы сборки образов docker и разработать их для созданных приложений.
|
||||||
|
- Собрать файл docker-compose.yml для запуска приложений. Разобраться с монтированием каталогов из хост-системы.
|
||||||
|
- Правильно закоммитить результат без лишних файлов.
|
||||||
|
- Оформить pull request по правилам и отправить его на проверку.
|
||||||
|
|
||||||
|
# Разработка двух приложений
|
||||||
|
|
||||||
|
Было решено для первого приложения(worker_1) выбрать 1 вариант - Ищет в каталоге /var/data файл с наибольшим количеством строк и перекладывает его в /var/result/data.txt
|
||||||
|
Для второго приложения(worker_2) выбрать 0 вариант - сохраняет произзведение первого и последнего числа из файла /var/result/data.txt в /var/result/result.txt
|
||||||
|
|
||||||
|
Разработка ведется на языке Go
|
||||||
|
|
||||||
|
![img.png](img.png)
|
||||||
|
|
||||||
|
# Запуск
|
||||||
|
|
||||||
|
Запуск контейнеров производится командой "docker-compose up -d"
|
||||||
|
|
||||||
|
# Работа программы
|
||||||
|
|
||||||
|
- Создание двух деррикторий: worker_1 и worker_2 для реализаций двух программ.
|
||||||
|
- Создание go.mod для обоих программ и реализация этих программ.
|
||||||
|
- Описание Dockerfile для создания образов для обоих программ.
|
||||||
|
- ![img_2.png](img_2.png) ![img_3.png](img_3.png)
|
||||||
|
- Создание двух репозиториев: data, result, для монтирования их в контейнеры, а также заполнение папки data тремя файлами.
|
||||||
|
- ![img_4.png](img_4.png)
|
||||||
|
- Описание docker-compose для запуска контейнеров, реализуется build для создания образов на основе dockerfile и у второго контейнера описавыется зависимость depends_on от первого контейнера, чтобы сначала успевал запуститься первый контейнер, а за ним запускался второй. Также описываются volumes, для монтирование папок data и result в контейнеры.
|
||||||
|
- ![img_5.png](img_5.png)
|
||||||
|
- Сборка и запуска контейнеров.
|
||||||
|
- ![img_6.png](img_6.png)
|
||||||
|
- Проверка в Docker Desktop контейнеров и образов.
|
||||||
|
- ![img_7.png](img_7.png)
|
||||||
|
- ![img_8.png](img_8.png)
|
||||||
|
- Смотрим, что выдает нам первый воркер в консоль. Он говорит, что первый файл с названием file1.txt имеет 4 строки, и это больше, чем в других файлах. Также текст этого файла был скопирован в файл data.txt
|
||||||
|
- ![img_9.png](img_9.png)
|
||||||
|
- Смотрим, что выдает нам второй воркер в консоль. Он говорит, что результат умножения сохранен в файл result.txt, а также выдает нам число, лежащее в этом файле.
|
||||||
|
- ![img_10.png](img_10.png)
|
||||||
|
- Смотрим, что при запуске контейнеров действительно в папке result создалось два файла data.txt и result.txt
|
||||||
|
- ![img_11.png](img_11.png)
|
||||||
|
- Смотрим, что лежит в эти файлах. В файле data.txt действительно лежат числа из file1.txt, а в файле result.txt лежит результат умножения первого на последнее число.
|
||||||
|
- ![img_12.png](img_12.png)
|
||||||
|
- ![img_13.png](img_13.png)
|
||||||
|
|
||||||
|
# Видео
|
||||||
|
|
||||||
|
Видео с разбором лабораторной работы - https://youtu.be/JHDQOQBBPUs
|
4
senkin_alexander_lab_2/data/file1.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
525 785 99856
|
||||||
|
1000 7984 545102
|
||||||
|
513 84651321 564
|
||||||
|
654 6548 321315
|
2
senkin_alexander_lab_2/data/file2.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
42432 54654 5212
|
||||||
|
1524 458 3526
|
3
senkin_alexander_lab_2/data/file3.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
546 546542 21354
|
||||||
|
2548 545 4645
|
||||||
|
546 5473 5464
|
18
senkin_alexander_lab_2/docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
worker1:
|
||||||
|
build:
|
||||||
|
context: /worker_1
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\data:/var/data
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\result:/var/result
|
||||||
|
worker2:
|
||||||
|
build:
|
||||||
|
context: /worker_2
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\data:/var/data
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\result:/var/result
|
||||||
|
depends_on:
|
||||||
|
- worker1
|
||||||
|
|
BIN
senkin_alexander_lab_2/img.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
senkin_alexander_lab_2/img_1.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
senkin_alexander_lab_2/img_10.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
senkin_alexander_lab_2/img_11.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
senkin_alexander_lab_2/img_12.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
senkin_alexander_lab_2/img_13.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
senkin_alexander_lab_2/img_2.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
senkin_alexander_lab_2/img_3.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
senkin_alexander_lab_2/img_4.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
senkin_alexander_lab_2/img_5.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
senkin_alexander_lab_2/img_6.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
senkin_alexander_lab_2/img_7.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
senkin_alexander_lab_2/img_8.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
senkin_alexander_lab_2/img_9.png
Normal file
After Width: | Height: | Size: 13 KiB |
4
senkin_alexander_lab_2/result/data.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
525 785 99856
|
||||||
|
1000 7984 545102
|
||||||
|
513 84651321 564
|
||||||
|
654 6548 321315
|
1
senkin_alexander_lab_2/result/result.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
168690375
|
13
senkin_alexander_lab_2/worker_1/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM golang:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY go.mod .
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY worker_1.go .
|
||||||
|
|
||||||
|
RUN go build -o myapp
|
||||||
|
|
||||||
|
CMD ["/app/myapp"]
|
3
senkin_alexander_lab_2/worker_1/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module DAS_2023_1/senkin_alexander_lab_2/worker_1
|
||||||
|
|
||||||
|
go 1.20
|
71
senkin_alexander_lab_2/worker_1/worker_1.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sourceDir := "/var/data"
|
||||||
|
destinationFile := "/var/result/data.txt"
|
||||||
|
|
||||||
|
if _, err := os.Stat(destinationFile); os.IsNotExist(err) {
|
||||||
|
file, err := os.Create(destinationFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Ошибка при создании файла:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(sourceDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Ошибка при чтении каталога:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxLines int
|
||||||
|
var maxLinesFile string
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if !file.IsDir() {
|
||||||
|
filePath := filepath.Join(sourceDir, file.Name())
|
||||||
|
lines, err := countLines(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Ошибка при подсчете строк в файле %s: %v\n", filePath, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if lines > maxLines {
|
||||||
|
maxLines = lines
|
||||||
|
maxLinesFile = filePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if maxLinesFile != "" {
|
||||||
|
data, err := ioutil.ReadFile(maxLinesFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Ошибка при чтении файла: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(destinationFile, data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Ошибка при записи файла: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Файл %s с наибольшим количеством строк (%d) скопирован в %s\n", maxLinesFile, maxLines, destinationFile)
|
||||||
|
} else {
|
||||||
|
log.Println("Не удалось найти файлы в каталоге /var/data.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func countLines(filePath string) (int, error) {
|
||||||
|
data, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
lines := len(bytes.Split(data, []byte("\n"))) - 1
|
||||||
|
return lines, nil
|
||||||
|
}
|
13
senkin_alexander_lab_2/worker_2/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM golang:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY go.mod .
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY worker_2.go .
|
||||||
|
|
||||||
|
RUN go build -o myapp
|
||||||
|
|
||||||
|
CMD ["/app/myapp"]
|
3
senkin_alexander_lab_2/worker_2/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module DAS_2023_1/senkin_alexander_lab_2/worker_2
|
||||||
|
|
||||||
|
go 1.20
|
89
senkin_alexander_lab_2/worker_2/worker_2.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
dataFilePath := "/var/result/data.txt"
|
||||||
|
resultFilePath := "/var/result/result.txt"
|
||||||
|
|
||||||
|
if _, err := os.Stat(resultFilePath); os.IsNotExist(err) {
|
||||||
|
file, err := os.Create(resultFilePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Ошибка при создании файла:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := os.Stat(dataFilePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Файл data.txt не сущесвует, выполните первую программу перед запуском второй")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(dataFilePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Ошибка при чтении файла %s: %v\n", dataFilePath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content := string(data)
|
||||||
|
|
||||||
|
lines := bufio.NewScanner(strings.NewReader(content))
|
||||||
|
|
||||||
|
first := 0
|
||||||
|
last := 0
|
||||||
|
firstFound := false
|
||||||
|
var numbersFound bool
|
||||||
|
|
||||||
|
for lines.Scan() {
|
||||||
|
line := lines.Text()
|
||||||
|
numbers := strings.Fields(line)
|
||||||
|
if len(numbers) > 0 {
|
||||||
|
// Преобразуем первое и последнее число в числа с плавающей точкой
|
||||||
|
if !firstFound {
|
||||||
|
first, err = strconv.Atoi(numbers[0])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Ошибка при преобразовании первого числа: %v", err)
|
||||||
|
}
|
||||||
|
firstFound = true
|
||||||
|
}
|
||||||
|
last, err = strconv.Atoi(numbers[len(numbers)-1])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Ошибка при преобразовании последнего числа: %v", err)
|
||||||
|
}
|
||||||
|
numbersFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := lines.Err(); err != nil {
|
||||||
|
log.Printf("Ошибка при чтении файла: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !numbersFound {
|
||||||
|
log.Fatalf("Не найдены числа в файле %s", dataFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := first * last
|
||||||
|
outputContent := fmt.Sprintf("%d", result)
|
||||||
|
if err := ioutil.WriteFile(resultFilePath, []byte(outputContent), 0644); err != nil {
|
||||||
|
log.Printf("Ошибка при записи результата в файл: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Результат (%d) сохранен в файл %s\n", result, resultFilePath)
|
||||||
|
|
||||||
|
dataResult, err := ioutil.ReadFile(resultFilePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Ошибка при чтении файла %s: %v\n", resultFilePath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contentResult := string(dataResult)
|
||||||
|
log.Println("Результат, лежащий в файле result - ", contentResult)
|
||||||
|
}
|
18
tasks/senkin-ae/lab_2/docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
worker1:
|
||||||
|
build:
|
||||||
|
context: C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\worker_1
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\data:/var/data
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\result:/var/result
|
||||||
|
worker2:
|
||||||
|
build:
|
||||||
|
context: C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\worker_2
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\data:/var/data
|
||||||
|
- C:\Users\Mamoru\GolandProjects\DAS_2023_1\senkin_alexander_lab_2\result:/var/result
|
||||||
|
depends_on:
|
||||||
|
- worker1
|
||||||
|
|