diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..d11bb306 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ +## Goal +What is the purpose of this PR? + +## Changes +What was changed? + +## Testing +How was it tested? + +### Checklist +- [ ] Clear, descriptive PR title +- [ ] Documentation/README updated (if needed) +- [ ] No secrets or large temporary files committed \ No newline at end of file diff --git a/current-state.txt b/current-state.txt new file mode 100644 index 00000000..345c3ef0 --- /dev/null +++ b/current-state.txt @@ -0,0 +1,3 @@ +version: 1.0 +app: myapp +replicas: 3 diff --git a/desired-state.txt b/desired-state.txt new file mode 100644 index 00000000..345c3ef0 --- /dev/null +++ b/desired-state.txt @@ -0,0 +1,3 @@ +version: 1.0 +app: myapp +replicas: 3 diff --git a/healthcheck.sh b/healthcheck.sh new file mode 100644 index 00000000..f429380d --- /dev/null +++ b/healthcheck.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +DESIRED_MD5=$(md5sum desired-state.txt | awk '{print $1}') +CURRENT_MD5=$(md5sum current-state.txt | awk '{print $1}') +TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') + +if [ "$DESIRED_MD5" = "$CURRENT_MD5" ]; then + echo "OK: state is synchronized" + echo "$TIMESTAMP OK desired=$DESIRED_MD5 current=$CURRENT_MD5" >> health.log +else + echo "CRITICAL: drift detected" + echo "$TIMESTAMP CRITICAL desired=$DESIRED_MD5 current=$CURRENT_MD5" >> health.log +fi diff --git a/labs/submission4.md b/labs/submission4.md new file mode 100644 index 00000000..c7c3c31c --- /dev/null +++ b/labs/submission4.md @@ -0,0 +1,180 @@ +# Lab 4 — Submission + +## Task 1 — Operating System Analysis + +--- + +### 1.1 Boot Performance Analysis + +```text +systemd-analyze +Startup finished in 3.212s (userspace) +graphical.target reached after 3.159s in userspace. +``` + +```text +systemd-analyze blame | head -n 10 +6.849s apt-daily-upgrade.service +1.487s landscape-client.service +751ms dev-sdd.device +659ms snapd.seeded.service +513ms snapd.service +383ms wsl-pro.service +``` + +```text +uptime +16:43:28 up 9 min, 1 user, load average: 0.02, 0.06, 0.02 +``` + +```text +w +USER TTY LOGIN@ IDLE WHAT +krasand pts/1 16:34 9:23 -bash +``` + +**Observations:** + +- The system booted in approximately 3 seconds (userspace), which is expected for WSL. +- The longest starting service was `apt-daily-upgrade.service`. +- Load average values are very low, indicating the system is mostly idle. +- Only one active user session is present. + +--- + +### 1.2 Process Forensics + +```text +ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -n 6 +613 1 /usr/bin/python3 ... 0.9 0.0 +217 1 /usr/bin/python3 ... 0.6 0.0 +897 1 /usr/libexec/packagekitd 0.5 0.0 +``` + +```text +ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -n 6 +1 0 /sbin/init 0.3 0.3 +613 1 /usr/bin/python3 ... 0.9 0.0 +``` + +**Top memory-consuming process:** +`/usr/bin/python3` (system service process). + +**Observations:** + +- Memory and CPU usage are minimal. +- The system is not under load. +- Processes consuming memory are mostly background services. + +--- + +### 1.3 Memory Analysis + +```text +free -h +Mem: 3.3Gi total, 440Mi used, 2.8Gi free +Swap: 1.0Gi total, 0B used +``` + +```text +MemTotal: 3459304 kB +MemAvailable: 3008040 kB +SwapTotal: 1048576 kB +``` + +**Observations:** + +- Most memory is available (~2.9Gi). +- Swap is configured but not used. +- The system has sufficient free memory. + +--- + +### 1.4 User Sessions + +```text +who -a +system boot 2026-02-27 16:34 +krasand pts/1 2026-02-27 16:34 +``` + +```text +last -n 5 +reboot system boot 6.6.87.2-microsoft ... +``` + +**Observations:** + +- Only one user session is active. +- Recent system activity shows WSL reboots. +- No unusual login activity detected. + +--- + +## Task 2 — Networking Analysis + +--- + +### 2.1 Network Path Tracing + +```text +traceroute github.com +1 172.26.160.XXX +2 10.240.16.XXX +3 10.250.0.XXX +... +18 r1-fra3-de.as5405.net (94.103.180.24) +19 cust-sid436.fra3-de.as5405.net (45.153.82.37) +``` + +```text +dig github.com + +ANSWER SECTION: +github.com. IN A 140.82.121.4 +``` + +**Observations:** + +- The route includes private internal network hops (10.x.x.x and 172.x.x.x) before reaching public internet routers. +- DNS resolution confirms `github.com` resolves to IP address `140.82.121.4`. + +--- + +### 2.2 Packet Capture (DNS Traffic) + +```text +sudo tcpdump -c 5 -i any 'port 53' -nn + +Out IP 172.26.162.XXX.58057 > 172.26.160.XXX.53: A? google.com. +In IP 172.26.160.XXX.53 > 172.26.162.XXX.58057: A 172.217.19.238 +``` + +**Observations:** + +- The packet capture shows a DNS query for `google.com`. +- The response contains the resolved IP address. +- Local IP addresses were partially masked for privacy. + +--- + +### 2.3 Reverse DNS Lookup + +```text +dig -x 8.8.4.4 + +ANSWER SECTION: +4.4.8.8.in-addr.arpa. PTR dns.google. +``` + +```text +dig -x 1.1.2.2 + +status: NXDOMAIN +``` + +**Observations:** + +- The IP address `8.8.4.4` resolves to `dns.google`, confirming it belongs to Google DNS. +- The IP address `1.1.2.2` does not have a PTR record (NXDOMAIN). +- Reverse DNS depends on whether a PTR record is configured for the IP address. \ No newline at end of file diff --git a/labs/submission5.md b/labs/submission5.md new file mode 100644 index 00000000..b331a7a9 --- /dev/null +++ b/labs/submission5.md @@ -0,0 +1,172 @@ +# Lab 5 --- Virtualization and System Analysis + +## Platform + +Virtual Machine running **Ubuntu 24.04 LTS** inside **Oracle +VirtualBox**. + +------------------------------------------------------------------------ + +# Task 2 --- System Analysis + +## Operating System Information + +### Command + + uname -a + +### Output + + Linux andrey-VirtualBox 6.17.0-14-generic #14~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Jan 15 15:52:10 UTC x86_64 x86_64 x86_64 GNU/Linux + +### Detailed OS information + +Command + + cat /etc/os-release + +Output + + PRETTY_NAME="Ubuntu 24.04.4 LTS" + NAME="Ubuntu" + VERSION_ID="24.04" + VERSION="24.04.4 LTS (Noble Numbat)" + VERSION_CODENAME=noble + ID=ubuntu + ID_LIKE=debian + +### Conclusion + +The system is running **Ubuntu 24.04.4 LTS (Noble Numbat)**. + +------------------------------------------------------------------------ + +# CPU Information + +### Command + + lscpu + +### Key Information + +- Architecture: **x86_64** +- CPU Model: **AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx** +- CPU cores allocated to VM: **2** +- Virtualization type: **full** +- Hypervisor vendor: **KVM** + +### Conclusion + +The virtual machine is using **2 virtual CPU cores provided by the host +machine**. + +------------------------------------------------------------------------ + +# Memory Information + +### Command + + free -h + +### Output + + Mem: 3.8Gi total + Used: 1.0Gi + Free: 1.3Gi + Swap: 3.8Gi + +### Conclusion + +The virtual machine has: + +- **3.8 GB RAM** +- **3.8 GB swap memory** + +Memory usage is relatively low. + +------------------------------------------------------------------------ + +# Storage Information + +### Command + + lsblk + +### Output + + sda 25G disk + └─sda2 25G mounted on / + +### Disk Usage + +Command + + df -h + +Output + + Filesystem Size Used Avail Use% + /dev/sda2 25G 9.5G 14G 41% + +### Conclusion + +The system uses a **25 GB virtual disk**, with **14 GB available free +space**. + +------------------------------------------------------------------------ + +# Network Configuration + +### Command + + ip a + +### Key Information + +Network interface: + + enp0s3 + +IP address: + + 10.0.2.15 + +### Conclusion + +The VM is connected to the network using **VirtualBox NAT networking**. + +------------------------------------------------------------------------ + +# Virtualization Detection + +### Command + + systemd-detect-virt + +### Output + + oracle + +### Conclusion + +The operating system correctly detects that it is running inside +**Oracle VirtualBox virtualization environment**. + +------------------------------------------------------------------------ + +# Final Summary + +This lab demonstrated system inspection inside a virtual machine +environment. + +The analyzed system has: + +- Ubuntu **24.04 LTS** +- **2 virtual CPU cores** +- **\~4 GB RAM** +- **25 GB virtual disk** +- NAT network configuration +- Virtualization platform: **Oracle VirtualBox** + +The system tools successfully detected the virtualization environment +and provided detailed information about system resources. diff --git a/labs/submission6.md b/labs/submission6.md new file mode 100644 index 00000000..30af210e --- /dev/null +++ b/labs/submission6.md @@ -0,0 +1,371 @@ +# Lab 6 — Docker Fundamentals + +## Task 1 — Container Lifecycle & Image Management + +### Existing containers + +```text +docker ps -a + +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +``` + +### Pull Ubuntu image + +```text +docker pull ubuntu:latest +docker images ubuntu + +REPOSITORY TAG IMAGE ID CREATED SIZE +ubuntu latest c35e29c94501 2 weeks ago 78.1MB +``` + +### Run Ubuntu container and inspect it + +```text +docker run -it --name ubuntu_container ubuntu:latest +``` + +Inside the container: + +```text +cat /etc/os-release + +PRETTY_NAME="Ubuntu 24.04.4 LTS" +NAME="Ubuntu" +VERSION_ID="24.04" +VERSION="24.04.4 LTS (Noble Numbat)" +VERSION_CODENAME=noble +ID=ubuntu +ID_LIKE=debian +UBUNTU_CODENAME=noble +``` + +```text +ps aux + +USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND +root 1 0.0 0.0 4112 3328 pts/0 Ss 23:47 0:00 /bin/bash +root 15 0.0 0.0 8540 4352 pts/0 R+ 23:47 0:00 ps aux +``` + +### Save image to tar archive + +```text +docker save -o ubuntu_image.tar ubuntu:latest +ls -lh ubuntu_image.tar + +-rw------- 1 andrey andrey 77M Mar 27 02:48 ubuntu_image.tar +``` + +### Attempt to remove image while container still exists + +```text +docker rmi ubuntu:latest + +Error response from daemon: conflict: unable to remove repository reference "ubuntu:latest" (must force) - container 0bdbca25355e is using its referenced image c35e29c94501bc21680f16e27d3d4769a04f34057d0b8d2ad278b5e4efea5f8d +``` + +### Remove container and then remove image + +```text +docker rm ubuntu_container +docker rmi ubuntu:latest + +ubuntu_container +Untagged: ubuntu:latest +Deleted: sha256:c35e29c94501bc21680f16e27d3d4769a04f34057d0b8d2ad278b5e4efea5f8d +``` + +### Analysis + +The Ubuntu image size is **78.1 MB**, while the exported archive size is **77 MB**. +Docker does not allow removing an image if an existing container still references it. This protects the consistency of container metadata and prevents breaking containers created from that image. +The file `ubuntu_image.tar` stores the Docker image data in portable form, including image layers and metadata, so it can be transferred or loaded on another machine. + +--- + +## Task 2 — Custom Image Creation & Analysis + +### Run nginx and inspect the default page + +```text +docker run -d -p 80:80 --name nginx_container nginx +curl http://localhost +``` + +Default page output: + +```html + + + +Welcome to nginx! +... +

Welcome to nginx!

+... + +``` + +### Custom HTML file + +```html + + +The best + + +

website

+ + +``` + +### Copy the new page into the container + +```text +docker cp index.html nginx_container:/usr/share/nginx/html/ +curl http://localhost +``` + +Updated page output: + +```html + + +The best + + +

website

+ + +``` + +### Commit the modified container into a new image + +```text +docker commit nginx_container my_website:latest +docker images my_website + +REPOSITORY TAG IMAGE ID CREATED SIZE +my_website latest 546b46f55510 Less than a second ago 161MB +``` + +### Remove old container and run new image + +```text +docker rm -f nginx_container +docker run -d -p 80:80 --name my_website_container my_website:latest +curl http://localhost +``` + +Output: + +```html + + +The best + + +

website

+ + +``` + +### Inspect filesystem changes + +```text +docker diff my_website_container + +C /etc +C /etc/nginx +C /etc/nginx/conf.d +C /etc/nginx/conf.d/default.conf +C /run +C /run/nginx.pid +``` + +### Analysis + +The custom page was successfully embedded into a new image called `my_website:latest`. +In `docker diff`, the letter `C` means **changed**. In general: +- `A` = added +- `C` = changed +- `D` = deleted + +`docker commit` creates an image from the current state of a container, but it is not reproducible or easy to track in version control. +A **Dockerfile** is usually better in real projects because it is declarative, repeatable, and easier to review, automate, and maintain. + +--- + +## Task 3 — Container Networking & Service Discovery + +### Create a user-defined bridge network + +```text +docker network create lab_network +docker network ls + +NETWORK ID NAME DRIVER SCOPE +acde0a6bea4a bridge bridge local +5efe57884f34 host host local +a977719bf87a lab_network bridge local +8c5654fe4655 none null local +``` + +### Run two Alpine containers on that network + +```text +docker run -dit --network lab_network --name container1 alpine ash +docker run -dit --network lab_network --name container2 alpine ash +``` + +### Verify connectivity between containers + +```text +docker exec container1 ping -c 3 container2 + +PING container2 (172.18.0.3): 56 data bytes +64 bytes from 172.18.0.3: seq=0 ttl=64 time=1.021 ms +64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.108 ms +64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.088 ms + +--- container2 ping statistics --- +3 packets transmitted, 3 packets received, 0% packet loss +round-trip min/avg/max = 0.088/0.405/1.021 ms +``` + +### Inspect network details + +```text +docker network inspect lab_network +``` + +Relevant part of the output: + +```text +"Subnet": "172.18.0.0/16", +"Gateway": "172.18.0.1" + +"Containers": { + ... + "Name": "container1", + "IPv4Address": "172.18.0.2/16", + ... + "Name": "container2", + "IPv4Address": "172.18.0.3/16" +} +``` + +### Verify Docker DNS name resolution + +```text +docker exec container1 nslookup container2 + +Server: 127.0.0.11 +Address: 127.0.0.11:53 + +Non-authoritative answer: +Name: container2 +Address: 172.18.0.3 +``` + +### Analysis + +The two containers can communicate over the custom bridge network by container name. +Docker provides an internal DNS service for user-defined networks, so `container1` can resolve `container2` automatically. +A user-defined bridge network is better than the default bridge because it provides built-in DNS-based service discovery and better isolation. + +--- + +## Task 4 — Data Persistence with Volumes + +### Create a named volume + +```text +docker volume create app_data +docker volume ls + +DRIVER VOLUME NAME +local app_data +``` + +### Start nginx with the volume mounted + +```text +docker run -d -p 8080:80 -v app_data:/usr/share/nginx/html --name web nginx +curl http://localhost:8080 +``` + +Initial output: + +```html + + + +Welcome to nginx! +... +

Welcome to nginx!

+... + +``` + +### Create a persistent HTML page + +```html +

Persistent Data

+``` + +### Copy the file into the container and verify it + +```text +docker cp index.html web:/usr/share/nginx/html/ +curl http://localhost:8080 +``` + +Output: + +```html +

Persistent Data

+``` + +### Remove the container and start a new one with the same volume + +```text +docker stop web +docker rm web +docker run -d -p 8080:80 -v app_data:/usr/share/nginx/html --name web_new nginx +sleep 3 +curl http://localhost:8080 +``` + +Output after recreation: + +```html +

Persistent Data

+``` + +### Inspect the volume + +```text +docker volume inspect app_data + +[ + { + "CreatedAt": "2026-03-27T02:57:31+03:00", + "Driver": "local", + "Mountpoint": "/var/lib/docker/volumes/app_data/_data", + "Name": "app_data", + "Scope": "local" + } +] +``` + +### Analysis + +The HTML page remained available after deleting the first container and starting a new one with the same volume. This demonstrates persistent storage outside the container lifecycle. + +Docker volumes are useful for application data that must survive container recreation. +Compared to other storage options: +- **Volumes** are managed by Docker and are recommended for persistent application data. +- **Bind mounts** map a host directory directly into a container. +- **Container storage** is ephemeral and is lost when the container is removed. diff --git a/labs/submission7.md b/labs/submission7.md new file mode 100644 index 00000000..384887e8 --- /dev/null +++ b/labs/submission7.md @@ -0,0 +1,293 @@ +# Lab 7 — GitOps Simulation + +## Task 1 — Git State Reconciliation + +### Initial desired state + +`desired-state.txt` + +```text +version: 1.0 +app: myapp +replicas: 3 +``` + +### Initial current state + +`current-state.txt` + +```text +version: 1.0 +app: myapp +replicas: 3 +``` + +### Reconciliation script + +`reconcile.sh` + +```bash +#!/bin/bash + +if cmp -s desired-state.txt current-state.txt; then + echo "States are synchronized." +else + echo "Drift detected." + cp desired-state.txt current-state.txt + echo "Reconciliation completed." +fi +``` + +### Manual drift simulation + +Modified `current-state.txt`: + +```text +version: 2.0 +app: myapp +replicas: 10 +``` + +Difference before reconciliation: + +```text +1c1 +< version: 1.0 +--- +> version: 2.0 +3c3 +< replicas: 3 +--- +> replicas: 10 +``` + +Reconciliation output: + +```text +Drift detected. +Reconciliation completed. +``` + +State after reconciliation: + +```text +version: 1.0 +app: myapp +replicas: 3 +``` + +### Continuous reconciliation loop + +A watch-based loop was started with: + +```bash +watch -n 5 ./reconcile.sh +``` + +Then `current-state.txt` was modified again: + +```text +version: 1.0 +app: myapp +replicas: 3 +replicas: 10 +``` + +The reconciliation loop automatically restored the correct state. Final synchronized state: + +```text +version: 1.0 +app: myapp +replicas: 3 +``` + +### Analysis + +The reconciliation loop continuously compares the current state with the desired state and restores the system when drift is detected. This simulates the core GitOps idea: Git (or the desired-state file in this lab) acts as the single source of truth. + +By automatically correcting changes, reconciliation reduces configuration drift and keeps the system consistent over time. + +### Reflection + +Declarative configuration is preferable to imperative commands in production because it defines **what the final state should be**, rather than **how to reach it**. This makes systems easier to audit, version, reproduce, and automatically recover when unexpected changes occur. + +--- + +## Task 2 — GitOps Health Monitoring + +### Health check script + +`healthcheck.sh` + +```bash +#!/bin/bash + +DESIRED_MD5=$(md5sum desired-state.txt | awk '{print $1}') +CURRENT_MD5=$(md5sum current-state.txt | awk '{print $1}') +TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') + +if [ "$DESIRED_MD5" = "$CURRENT_MD5" ]; then + echo "OK: state is synchronized" + echo "$TIMESTAMP OK desired=$DESIRED_MD5 current=$CURRENT_MD5" >> health.log +else + echo "CRITICAL: drift detected" + echo "$TIMESTAMP CRITICAL desired=$DESIRED_MD5 current=$CURRENT_MD5" >> health.log +fi +``` + +### Healthy state check + +Output of `./healthcheck.sh` when both files matched: + +```text +OK: state is synchronized +``` + +Initial log entry: + +```text +2026-03-27 05:58:54 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +``` + +### Drifted state check + +Drift was introduced with: + +```bash +echo "unapproved-change: true" >> current-state.txt +``` + +Modified state: + +```text +version: 1.0 +app: myapp +replicas: 3 +unapproved-change: true +``` + +Health check output: + +```text +CRITICAL: drift detected +``` + +Log after drift: + +```text +2026-03-27 05:58:54 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:01:41 CRITICAL desired=a15a1a4f965ecd8f9e23a33a6b543155 current=48168ff3ab5ffc0214e81c7e2ee356f5 +``` + +### Recovery after drift + +Reconciliation and health check: + +```text +Drift detected. +Reconciliation completed. +OK: state is synchronized +``` + +Log after recovery: + +```text +2026-03-27 05:58:54 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:01:41 CRITICAL desired=a15a1a4f965ecd8f9e23a33a6b543155 current=48168ff3ab5ffc0214e81c7e2ee356f5 +2026-03-27 06:03:17 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +``` + +### Monitor loop script + +`monitor.sh` + +```bash +#!/bin/bash + +for i in {1..10}; do + echo "Iteration $i" + ./healthcheck.sh + ./reconcile.sh + sleep 3 +done +``` + +### Monitor loop execution + +Before running the monitor, drift was introduced again: + +```text +version: 1.0 +app: myapp +replicas: 3 +replicas: 99 +``` + +Output of `./monitor.sh`: + +```text +Iteration 1 +CRITICAL: drift detected +Drift detected. +Reconciliation completed. +Iteration 2 +OK: state is synchronized +States are synchronized. +Iteration 3 +OK: state is synchronized +States are synchronized. +Iteration 4 +OK: state is synchronized +States are synchronized. +Iteration 5 +OK: state is synchronized +States are synchronized. +Iteration 6 +OK: state is synchronized +States are synchronized. +Iteration 7 +OK: state is synchronized +States are synchronized. +Iteration 8 +OK: state is synchronized +States are synchronized. +Iteration 9 +OK: state is synchronized +States are synchronized. +Iteration 10 +OK: state is synchronized +States are synchronized. +``` + +Final `health.log`: + +```text +2026-03-27 05:58:54 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:01:41 CRITICAL desired=a15a1a4f965ecd8f9e23a33a6b543155 current=48168ff3ab5ffc0214e81c7e2ee356f5 +2026-03-27 06:03:17 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:05:08 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:05:58 CRITICAL desired=a15a1a4f965ecd8f9e23a33a6b543155 current=93d541ce03f5304eec60b2363acf80c9 +2026-03-27 06:06:01 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:04 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:08 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:11 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:14 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:17 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:20 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:23 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +2026-03-27 06:06:27 OK desired=a15a1a4f965ecd8f9e23a33a6b543155 current=a15a1a4f965ecd8f9e23a33a6b543155 +``` + +Final synchronized state: + +```text +version: 1.0 +app: myapp +replicas: 3 +``` + +### Analysis + +Checksums provide a simple and reliable way to detect whether two configuration files are identical. If the MD5 hashes differ, the system can immediately identify that drift has occurred. + +This is conceptually similar to the Sync Status in tools such as ArgoCD and Flux: the desired state is compared with the observed state, and a mismatch is reported as unhealthy or out of sync. diff --git a/labs/test b/labs/test new file mode 100644 index 00000000..2a99ea22 --- /dev/null +++ b/labs/test @@ -0,0 +1 @@ +test commit diff --git a/monitor.sh b/monitor.sh new file mode 100644 index 00000000..946bc35d --- /dev/null +++ b/monitor.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +for i in {1..10}; do + echo "Iteration $i" + ./healthcheck.sh + ./reconcile.sh + sleep 3 +done diff --git a/reconcile.sh b/reconcile.sh new file mode 100644 index 00000000..951858b2 --- /dev/null +++ b/reconcile.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +if cmp -s desired-state.txt current-state.txt; then + echo "States are synchronized." +else + echo "Drift detected." + cp desired-state.txt current-state.txt + echo "Reconciliation completed." +fi