diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 000000000..dc0709a2e --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,52 @@ +name: GitHub Actions Demo +run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 +on: + push: + workflow_dispatch: + +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + + - name: Check out repository code + uses: actions/checkout@v5 + + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + + - name: List files in the repository + run: | + ls ${{ github.workspace }} + + - name: Gather system information + run: | + echo "## System Information" + echo "### Operating System Details" + cat /etc/os-release + echo "" + echo "### CPU Information" + lscpu | grep "Model name\|CPU(s)" + echo "" + echo "### Memory Information" + free -h + echo "" + echo "### Disk Information" + df -h + echo "" + echo "### Kernel Version" + uname -a + echo "" + echo "### Who am I" + whoami + echo "" + echo "### Current Directory" + pwd + echo "" + echo "### Environment Variables" + env | sort + + - run: echo "🍏 This job's status is ${{ job.status }}." \ No newline at end of file diff --git a/labs/screenshots/.DS_Store b/labs/screenshots/.DS_Store new file mode 100644 index 000000000..5717bb8f5 Binary files /dev/null and b/labs/screenshots/.DS_Store differ diff --git a/labs/screenshots/alerts.png b/labs/screenshots/alerts.png new file mode 100644 index 000000000..0d72ea3a4 Binary files /dev/null and b/labs/screenshots/alerts.png differ diff --git a/labs/screenshots/api_check.png b/labs/screenshots/api_check.png new file mode 100644 index 000000000..d875a806b Binary files /dev/null and b/labs/screenshots/api_check.png differ diff --git a/labs/screenshots/brows_check_out1.png b/labs/screenshots/brows_check_out1.png new file mode 100644 index 000000000..06631191d Binary files /dev/null and b/labs/screenshots/brows_check_out1.png differ diff --git a/labs/screenshots/brows_check_out2.png b/labs/screenshots/brows_check_out2.png new file mode 100644 index 000000000..8c8150b00 Binary files /dev/null and b/labs/screenshots/brows_check_out2.png differ diff --git a/labs/screenshots/brows_check_out3.png b/labs/screenshots/brows_check_out3.png new file mode 100644 index 000000000..d1033eb21 Binary files /dev/null and b/labs/screenshots/brows_check_out3.png differ diff --git a/labs/screenshots/brows_conf1.png b/labs/screenshots/brows_conf1.png new file mode 100644 index 000000000..5afa7bbf1 Binary files /dev/null and b/labs/screenshots/brows_conf1.png differ diff --git a/labs/screenshots/brows_conf2.png b/labs/screenshots/brows_conf2.png new file mode 100644 index 000000000..25bd7b37c Binary files /dev/null and b/labs/screenshots/brows_conf2.png differ diff --git a/labs/screenshots/cpu_based.png b/labs/screenshots/cpu_based.png new file mode 100644 index 000000000..7c1eca691 Binary files /dev/null and b/labs/screenshots/cpu_based.png differ diff --git a/labs/screenshots/dashboard.png b/labs/screenshots/dashboard.png new file mode 100644 index 000000000..281ef3d12 Binary files /dev/null and b/labs/screenshots/dashboard.png differ diff --git a/labs/screenshots/img1.png b/labs/screenshots/img1.png new file mode 100644 index 000000000..658c580d4 Binary files /dev/null and b/labs/screenshots/img1.png differ diff --git a/labs/screenshots/img2.png b/labs/screenshots/img2.png new file mode 100644 index 000000000..19964d935 Binary files /dev/null and b/labs/screenshots/img2.png differ diff --git a/labs/screenshots/img3.png b/labs/screenshots/img3.png new file mode 100644 index 000000000..da43a3e44 Binary files /dev/null and b/labs/screenshots/img3.png differ diff --git a/labs/screenshots/img4.png b/labs/screenshots/img4.png new file mode 100644 index 000000000..dc9bd1be4 Binary files /dev/null and b/labs/screenshots/img4.png differ diff --git a/labs/screenshots/img5.png b/labs/screenshots/img5.png new file mode 100644 index 000000000..13415149a Binary files /dev/null and b/labs/screenshots/img5.png differ diff --git a/labs/screenshots/img6.png b/labs/screenshots/img6.png new file mode 100644 index 000000000..8cab13e3c Binary files /dev/null and b/labs/screenshots/img6.png differ diff --git a/labs/screenshots/img7.png b/labs/screenshots/img7.png new file mode 100644 index 000000000..3fed7437e Binary files /dev/null and b/labs/screenshots/img7.png differ diff --git a/labs/screenshots/io_based.png b/labs/screenshots/io_based.png new file mode 100644 index 000000000..25b2fdd9b Binary files /dev/null and b/labs/screenshots/io_based.png differ diff --git a/labs/screenshots/lab12_1.png b/labs/screenshots/lab12_1.png new file mode 100644 index 000000000..156a101c9 Binary files /dev/null and b/labs/screenshots/lab12_1.png differ diff --git a/labs/screenshots/lab12_2.png b/labs/screenshots/lab12_2.png new file mode 100644 index 000000000..de822d2fa Binary files /dev/null and b/labs/screenshots/lab12_2.png differ diff --git a/labs/screenshots/lab12_3.png b/labs/screenshots/lab12_3.png new file mode 100644 index 000000000..32c21f241 Binary files /dev/null and b/labs/screenshots/lab12_3.png differ diff --git a/labs/screenshots/lab12_4.png b/labs/screenshots/lab12_4.png new file mode 100644 index 000000000..098d21a5c Binary files /dev/null and b/labs/screenshots/lab12_4.png differ diff --git a/labs/screenshots/mem_based.png b/labs/screenshots/mem_based.png new file mode 100644 index 000000000..9c8758211 Binary files /dev/null and b/labs/screenshots/mem_based.png differ diff --git a/labs/screenshots/trivy1.png b/labs/screenshots/trivy1.png new file mode 100644 index 000000000..dbf077aa2 Binary files /dev/null and b/labs/screenshots/trivy1.png differ diff --git a/labs/screenshots/trivy2.png b/labs/screenshots/trivy2.png new file mode 100644 index 000000000..d533b1a74 Binary files /dev/null and b/labs/screenshots/trivy2.png differ diff --git a/labs/screenshots/trivy3.png b/labs/screenshots/trivy3.png new file mode 100644 index 000000000..f06c81baf Binary files /dev/null and b/labs/screenshots/trivy3.png differ diff --git a/labs/screenshots/trivy4.png b/labs/screenshots/trivy4.png new file mode 100644 index 000000000..f1b6f078a Binary files /dev/null and b/labs/screenshots/trivy4.png differ diff --git a/labs/screenshots/trivy5.png b/labs/screenshots/trivy5.png new file mode 100644 index 000000000..05ec8a378 Binary files /dev/null and b/labs/screenshots/trivy5.png differ diff --git a/labs/screenshots/trivy6.png b/labs/screenshots/trivy6.png new file mode 100644 index 000000000..34c79174b Binary files /dev/null and b/labs/screenshots/trivy6.png differ diff --git a/labs/screenshots/zap1.png b/labs/screenshots/zap1.png new file mode 100644 index 000000000..d6a4f0f93 Binary files /dev/null and b/labs/screenshots/zap1.png differ diff --git a/labs/screenshots/zap2.png b/labs/screenshots/zap2.png new file mode 100644 index 000000000..34aa1d158 Binary files /dev/null and b/labs/screenshots/zap2.png differ diff --git a/labs/screenshots/zap3.png b/labs/screenshots/zap3.png new file mode 100644 index 000000000..4a351d1e3 Binary files /dev/null and b/labs/screenshots/zap3.png differ diff --git a/labs/submission1.md b/labs/submission1.md new file mode 100644 index 000000000..62f51f44f --- /dev/null +++ b/labs/submission1.md @@ -0,0 +1,25 @@ +# Lab 1 Submission +## Task 1: SSH Commit Signature Verification + +Commit signing proves who made code changes and that they weren't altered. It uses special digital signatures to confirm that a developer really created those commits and nobody secretly changed them. This stops people from pretending to be other team members, creates trust in team projects, and makes automated software pipelines safer. + +In DevOps workflows, where code moves quickly from writing to deployment, signed commits are important because they keep track of who did what and make sure only trusted changes get deployed. + +#### Screenshots for Task 1: +![SSH Key on GitHub](screenshots/img1.png) +![Verified Commit](screenshots/img3.png) +![Terminal Logs](screenshots/img2.png) + +## Task 2: PR Template & Checklist + +PR templates make team collaboration smoother and more efficient. By providing a standard structure for every pull request, they ensure that all necessary information is included from the start. When everyone uses the same format with sections like Goal, Changes, and Testing, reviewers know exactly where to look for information instead of going through comments or asking repetitive questions. The checklist also prevents common mistakes, like forgetting to update documentation or accidentally including sensitive files. + +Templates saves time and reduces frustration for everyone. New team members can quickly understand what's expected, experienced developers don't waste time on incomplete submissions, and the entire review process becomes more predictable. In fast-paced DevOps workflows where code moves quickly through automated pipelines, these templates create a reliable foundation that helps teams maintain quality while moving fast together. + +Several challenges emerged during setup. I initially found the repository structure confusing: understanding that work flows from the course repo to my fork to a feature branch. SSH key setup also required troubleshooting: I had to re-add my key as a "Signing Key" instead of just for authentication. Finally, I learned PR templates must exist on the main branch before they auto-fill, and they serve as empty forms that users complete when opening each PR. + +#### Screenshots for Task 2: +![Template Existance in Terminal](screenshots/img4.png) +![Template Existance on GitHub](screenshots/img5.png) +![PR template auto-filling the description](screenshots/img6.png) +![PR template filled](screenshots/img7.png) diff --git a/labs/submission10.md b/labs/submission10.md new file mode 100644 index 000000000..3065e3587 --- /dev/null +++ b/labs/submission10.md @@ -0,0 +1,70 @@ +# Lab 10 Submission +## Task 1: Artifact Registries Research +### Services, key features, artifact types, integration capabilities: + +**AWS: Elastic Container Registry (ECR)** + +Amazon ECR is AWS's primary artifact registry service. It is a fully managed service that stores container images and OCI artifacts. The service supports both private and public repositories, providing flexibility for different use cases. Key features include automated vulnerability scanning using Amazon Inspector, lifecycle policies to automatically clean up old images, and cross-region replication. Integration with other AWS services such as ECS, EKS, and Lambda is seamless, and access control is managed through AWS IAM. The pricing model is straightforward: storage and data transfer out to the internet incur costs, with a small free tier available for new users. Common use cases include storing images for microservices on ECS or EKS and sharing public images via the ECR Public Gallery. + +**GCP: Artifact Registry** + +Google Cloud's primary artifact registry service is Artifact Registry, which serves as the successor to the older Google Container Registry (GCR). This service provides a unified solution for multiple package types. Beyond Docker container images, it supports Maven, npm, Python, Go, Apt, and generic artifacts in a single repository, making it more comprehensive than a standard container registry. Key features include IAM for access control, customer-managed encryption keys, and regional or multi-regional storage options. Integration with Cloud Build, Cloud Run, and GKE is seamless. Pricing is based on storage, data egress, and specific operations such as pushing and pulling artifacts. This service is ideal for teams managing diverse package types for applications running within GCP. + +**Azure: Container Registry (ACR)** + +Azure Container Registry is Microsoft's solution for artifact storage. Like AWS ECR, it focuses on OCI-compliant images and artifacts. A notable feature is geo-replication, which automatically synchronizes images across different Azure regions to ensure high availability and faster global pulls. The service also includes ACR Tasks, a built-in capability for building, testing, and patching images directly in the cloud. Security integrates with Azure Active Directory and Azure RBAC for permissions, with vulnerability scanning supported through Microsoft Defender for Cloud. ACR offers tiered pricing (Basic, Standard, Premium) based on storage, throughput, and features such as private link support. Common use cases include integration with Azure Kubernetes Service (AKS) and Azure DevOps. + +### Comparison table: + +| Feature | AWS ECR | GCP Artifact Registry | Azure ACR | +|---------|---------|----------------------|-----------| +| **Service Name** | Elastic Container Registry | Artifact Registry | Azure Container Registry | +| **Primary Artifact Types** | Container Images, OCI Artifacts | Container Images, Maven, npm, Python, Go, Apt | Container Images, Helm Charts, OCI Artifacts | +| **Key Feature** | Deep AWS IAM integration | Multi-format support (unified) | Geo-replication, ACR Tasks | +| **Security** | IAM, Amazon Inspector | IAM, CMEK | Azure AD, RBAC, Defender for Cloud | +| **Pricing Model** | Pay for storage + data egress | Pay for storage + data egress | Tiered tiers (Basic, Standard, Premium) | + +### Analysis: + +For a multi-cloud strategy, I would likely choose Google Cloud's Artifact Registry. My reasoning is that while ECR and ACR are excellent services, they are heavily optimized for their specific cloud ecosystems. If you try to use ECR in a GCP environment, you lose the deep integration benefits and might face higher egress costs. + +Artifact Registry stands out because of its universal format support. If my company uses GCP for compute but also runs CI/CD pipelines that produce npm or Maven packages, Artifact Registry can store all of that in one place, acting as a central hub. This reduces the overhead of managing multiple separate repositories. Additionally, since it is based on open standards like OCI, it would still work well with other clouds or on-premises Kubernetes clusters, avoiding strict vendor lock-in for the artifact storage layer itself. + +## Task 2: Serverless Computing Platform Research + +### Service names, key features and capabilities, supported runtimes and languages, pricing, performance characteristics: + +**AWS: AWS Lambda** + +AWS Lambda is Amazon's primary serverless compute service. It enables code execution without provisioning or managing servers, automatically handling scaling and infrastructure maintenance. Lambda supports multiple programming languages including Node.js, Python, Java, Go, .NET, and Ruby, and also allows custom runtimes packaged as container images. Functions can be triggered by HTTP requests through API Gateway, object changes in S3, messages from SQS or SNS, and scheduled events via CloudWatch Events. Cold start latency varies by runtime, with interpreted languages like Node.js and Python experiencing delays around 200-400 milliseconds, while compiled languages like Java may take several seconds. Provisioned Concurrency is available as a paid feature to keep functions warm and eliminate cold starts. Pricing follows a pay-per-use model based on request count and execution duration measured in GB-seconds. The free tier includes 1 million requests and 400,000 GB-seconds per month. Maximum execution timeout is 15 minutes, with memory configurable up to 10 GB. Common use cases include REST API backends, real-time file processing, event-driven automation, and stream processing. + +**GCP: Google Cloud Functions (2nd Gen)** + +Google Cloud Functions is Google's serverless compute offering, with the 2nd generation built on Cloud Run. This architecture allows each function instance to handle up to 1,000 concurrent requests, which improves efficiency during traffic spikes compared to the one-request-per-instance model used by other providers. Supported runtimes include Node.js, Python, Go, Java, Ruby, PHP, and .NET. Triggers include HTTP requests and events from Cloud Storage, Pub/Sub, Firestore, and other Google Cloud services. Cold start performance is generally under 200 milliseconds for interpreted languages. The minimum instances feature provides a way to keep functions warm without the complex pricing structure of Provisioned Concurrency. Pricing is based on invocation count and compute time, with a free tier offering 2 million invocations and 400,000 GB-seconds per month. Maximum timeout is 60 minutes, and memory can be configured up to 32 GB. Common use cases include API backends, data processing pipelines, and event-driven applications. + +**Azure: Azure Functions** + +Azure Functions is Microsoft's serverless compute service. It offers multiple hosting plans: the Consumption plan for pure pay-per-use, the Premium plan with pre-warmed instances to eliminate cold starts, and Dedicated plans for predictable workloads. Supported languages include C#, Node.js, Python, Java, PowerShell, and TypeScript. Functions can be triggered by HTTP requests, blob storage changes, queue messages, timers, and events from other Azure services. A notable feature is Durable Functions, which enables stateful workflows with patterns like function chaining, fan-out/fan-in, and human approval steps directly in code. Another key capability is bindings, which allow declarative connections to input and output services without writing integration code. Cold starts on the Consumption plan can range from 500 milliseconds to several seconds depending on the runtime, while the Premium plan eliminates cold starts with always-ready instances. Pricing varies by plan, with Consumption following per-execution billing similar to AWS and GCP, and Premium having a baseline hourly cost. Free tier includes 1 million requests per month. Maximum timeout is 10 minutes on Consumption and unlimited on Premium. Common use cases include REST APIs, event-driven processing, and orchestrated workflows. + +### Comparison table: + +| Feature | AWS Lambda | GCP Cloud Functions (2nd Gen) | Azure Functions | +|---------|------------|------------------------------|-----------------| +| **Service Name** | AWS Lambda | Google Cloud Functions | Azure Functions | +| **Supported Languages** | Node.js, Python, Java, Go, .NET, Ruby, custom runtimes | Node.js, Python, Go, Java, Ruby, PHP, .NET | C#, Node.js, Python, Java, PowerShell, TypeScript | +| **Max Timeout** | 15 minutes | 60 minutes | 10 minutes (Consumption) / Unlimited (Premium) | +| **Max Memory** | 10 GB | 32 GB | 1.5 GB (Consumption) / 14 GB (Premium) | +| **Cold Start** | 200-400ms (Node.js), 2-3s (Java) | Under 200ms typical | 500ms-15s (Consumption), eliminated (Premium) | +| **Pricing Model** | Per request + GB-seconds | Per invocation + compute time | Per execution + resource consumption (Consumption) / Hourly (Premium) | +| **Free Tier** | 1M requests + 400K GB-sec | 2M invocations + 400K GB-sec | 1M requests per month | +| **Unique Feature** | Broadest event source integration | 1,000 concurrent requests per instance | Durable Functions for stateful workflows | + +### Analysis: + +For a REST API backend, Google Cloud Functions 2nd Gen would be the recommended choice. The ability to handle up to 1,000 concurrent requests per instance provides better efficiency during traffic spikes and reduces the number of cold starts experienced by users. The 60-minute timeout offers flexibility for endpoints that may require longer processing times. Additionally, the free tier provides 2 million invocations per month, which is double the allocation from competing services, making it cost-effective for development and low-traffic production workloads. + +### Reflection: + +Serverless computing offers several advantages. The primary benefit is operational simplicity, as developers can focus on writing code without managing servers, patching operating systems, or configuring scaling infrastructure. Auto-scaling happens automatically, handling traffic spikes without manual intervention. The pay-per-use pricing model ensures cost efficiency, as resources are only consumed when code executes, eliminating idle server costs. + +However, there are notable disadvantages. Cold starts introduce latency for infrequently invoked functions, which can impact user experience. Vendor lock-in is a significant concern, as serverless applications often rely on provider-specific triggers, APIs, and tooling, making migration between clouds challenging. Execution limits such as timeout and memory constraints may not suit long-running or memory-intensive workloads. Debugging and observability are also more complex compared to traditional server-based architectures, requiring specialized tools for tracing distributed function calls. \ No newline at end of file diff --git a/labs/submission11.md b/labs/submission11.md new file mode 100644 index 000000000..52ff56f99 --- /dev/null +++ b/labs/submission11.md @@ -0,0 +1,187 @@ +# Lab 10 Submission +## Task 1: Build Reproducible Artifacts from Scratch +### Nix Installation + +**Installation Method:** Determinate Systems installer + +**Verification Output:** +``` +arinapetuhova@MacBook-Air-Arina ~ % nix --version +nix (Determinate Nix 3.17.1) 2.33.3 +arinapetuhova@MacBook-Air-Arina ~ % nix run nixpkgs#hello +Hello, world! +``` + +### File: default.nix + +``` +{ pkgs ? import {} }: + +pkgs.buildGoModule { + pname = "app"; + version = "1.0.0"; + src = ./.; + vendorHash = null; + + meta = { + description = "Reproducible Go app built with Nix"; + platforms = pkgs.lib.platforms.all; + }; +} +``` + +**Explanation:** +- `pkgs.buildGoModule`: Nix function that builds Go applications with dependency management. It handles downloading dependencies, vendoring, and compiling Go modules in a reproducible way. +- `pname` and `version`: Package name and version. These combine to form the package identifier (app-1.0.0) in the Nix store path. +- `src = ./.`: Points to the current directory containing the source code (main.go and go.mod). Nix copies this into a sandboxed build environment. +- `vendorHash = null`: Explicitly tells Nix that this Go module has no external dependencies. When set to null, Nix skips the vendoring phase entirely. If there were dependencies, this would contain a SHA256 hash to verify the vendored dependencies match exactly. +- `meta`: Optional metadata describing the package. platforms = pkgs.lib.platforms.all indicates this package can be built on any platform supported by Nix (Linux, macOS, etc.). +- This derivation tells Nix exactly how to build the application in isolation - with no access to network, system libraries, or files outside the declared inputs, ensuring truly reproducible builds. + + +### Build Processes +**Build 1:** + +``` +arinapetuhova@MacBook-Air-Arina app % nix-build +this derivation will be built: + /nix/store/swcxf0001b1jgas27s3zi3j6rndy5rqw-app-1.0.0.drv +building '/nix/store/swcxf0001b1jgas27s3zi3j6rndy5rqw-app-1.0.0.drv'... +Running phase: unpackPhase +unpacking source archive /nix/store/vzvszgdfjahhhwrbbbm26fifp6lcwqj2-app +source root is app +Running phase: patchPhase +Running phase: updateAutotoolsGnuConfigScriptsPhase +Running phase: configurePhase +Running phase: buildPhase +Building subPackage . +Running phase: checkPhase +Running phase: installPhase +Running phase: fixupPhase +checking for references to /nix/var/nix/builds/nix-13493-859994452/ in /nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0... +patching script interpreter paths in /nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0 +stripping (with command strip and flags -S) in /nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0/bin +/nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0 +arinapetuhova@MacBook-Air-Arina app % ./result/bin/app +Built with Nix at compile time +Running at: 2026-03-30T20:05:47+03:00 +arinapetuhova@MacBook-Air-Arina app % readlink result +/nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0 +``` + +**Build 2:** + +``` +arinapetuhova@MacBook-Air-Arina app % rm result +nix-build +readlink result +/nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0 +/nix/store/0j4vjpmafrp1nqgm02sdf71k9hlvqjz1-app-1.0.0 +``` + +### SHA256 hash of the binary +``` +arinapetuhova@MacBook-Air-Arina app % sha256sum ./result/bin/app +dfccaac1f2b92a0b7fdad2bf15bf8224792b402732c9b5f2fe1ecd1744d9900f ./result/bin/app +``` + +### Comparison with Docker +Docker is not reproducible because it includes timestamps in image layers, so even with identical code, each build produces a different hash. Dockerfiles also use mutable tags like `golang:1.22` that can point to different base images over time as updates are released. Additionally, Docker builds have network access, allowing commands to fetch different dependency versions depending on when the build runs. These factors mean two developers building the same Dockerfile on different days will get different images. + +### Analysis +Nix builds are reproducible because they run in complete isolation—no network access, no system files, only explicitly declared dependencies. Every build input (source code, compiler, libraries) is pinned by a cryptographic hash in the Nix store. The same inputs always produce the same outputs because Nix removes non-deterministic elements like timestamps and ensures the build environment is identical every time. This eliminates the "works on my machine" problem entirely. + +### Explanation of the Nix store path format and what each part means +The Nix store path follows this format: `/nix/store/--`. The hash (e.g., `0j4vjpmafrp1nqgm02sdf71k9hlvqjz1`) is a SHA256 hash of all build inputs—source code, dependencies, build scripts, compiler version, and build flags. If any input changes, the hash changes, creating a completely new store path. The `-` part (e.g., app-1.0.0) is just human-readable metadata. This content-addressed system ensures that identical inputs always produce identical store paths, enabling perfect reproducibility and safe sharing of build artifacts. + +## Task 2: Reproducible Docker Images with Nix +### File: docker.nix: +``` +{ pkgs ? import {} }: + +let + app = import ./app { inherit pkgs; }; +in +pkgs.dockerTools.buildLayeredImage { + name = "reproducible-app"; + tag = "latest"; + contents = [ app ]; + config = { + Cmd = [ "${app}/bin/app" ]; + }; +} +``` + +**Explanation:** +- `pkgs.dockerTools.buildLayeredImage`: Nix function that creates efficient, layered Docker images. It builds images in a deterministic way without timestamps or non-reproducible metadata. +- `contents`: Specifies which packages or derivations to include in the image. Here, it includes our Go application (`app`) built from the previous task. +- `config.Cmd`: Defines the default command to run when the container starts. This points to the binary location in the Nix store. +- The derivation ensures that the Docker image is built in isolation with pinned dependencies, making it fully reproducible. + +### Image size comparison +**Reproducible:** +``` +arinapetuhova@MacBook-Air-Arina lab11 % docker images | grep reproducible-app +reproducible-app latest 776674e7ac3a 11 seconds ago 3.24MB +``` + +**Traditional:** +``` +arinapetuhova@MacBook-Air-Arina lab11 % docker images | grep traditional-app +traditional-app latest d6690fafc5cc About a minute ago 522MB +``` + +The Nix-style image is 99.4% smaller than the traditional image. This size reduction comes from: + +- Using FROM scratch (0 MB base image) instead of Alpine Linux +- Including only the statically compiled binary (2.06 MB) without build tools +- No runtime dependencies or package managers in the final image + +### SHA256 hashes +``` +arinapetuhova@MacBook-Air-Arina lab11 % echo "Test1 SHA256:" +docker inspect test1 --format='{{index .RepoDigests 0}}' + +echo "Test2 SHA256:" +docker inspect test2 --format='{{index .RepoDigests 0}}' +Test1 SHA256: +test1@sha256:b2a11e12f5f31b21e17effe15aa55016ad2e63d466d9186b5cfde89ea67e1e5e +Test2 SHA256: +test2@sha256:b2a11e12f5f31b21e17effe15aa55016ad2e63d466d9186b5cfde89ea67e1e5e + +``` + +This proves that the Docker image is truly reproducible - the same inputs always produce the exact same output, regardless of when or where the build runs. + +### Docker history output for both images +**Reproducible:** +``` +arinapetuhova@MacBook-Air-Arina lab11 % docker history reproducible-app:latest +IMAGE CREATED CREATED BY SIZE COMMENT +776674e7ac3a 16 seconds ago ENTRYPOINT ["/app"] 0B buildkit.dockerfile.v0 + 16 seconds ago COPY /app/app /app # buildkit 2.06MB buildkit.dockerfile.v0 +``` + +**Traditional:** +``` +arinapetuhova@MacBook-Air-Arina lab11 % docker history traditional-app:latest +IMAGE CREATED CREATED BY SIZE COMMENT +d6690fafc5cc About a minute ago ENTRYPOINT ["/app"] 0B buildkit.dockerfile.v0 + About a minute ago RUN /bin/sh -c go build -o /app /app/main.go… 36MB buildkit.dockerfile.v0 + About a minute ago COPY app/main.go /app/main.go # buildkit 12.3kB buildkit.dockerfile.v0 + About a minute ago RUN /bin/sh -c apk add --no-cache go # build… 351MB buildkit.dockerfile.v0 + 2 months ago CMD ["/bin/sh"] 0B buildkit.dockerfile.v0 + 2 months ago ADD alpine-minirootfs-3.23.3-aarch64.tar.gz … 9.36MB buildkit.dockerfile.v0 +``` + +### Analysis +Nix-built Docker images are significantly smaller because they use FROM scratch as the base (0 MB) instead of full operating systems like Alpine Linux (9 MB), and include only the statically compiled Go binary (2 MB) without any build tools, package managers, or runtime dependencies. The traditional Docker image, by contrast, includes the entire Alpine OS, the Go compiler, source code, and build artifacts, resulting in a 522 MB image. Nix-style images are more reproducible because they use pinned versions (golang:1.22-alpine), eliminate timestamps in layers, and ensure no network access during the final build stage. Every build with the same inputs produces the identical SHA256 hash, proving that the build process is deterministic and immune to external factors like time, machine state, or network conditions. + +### Layer structure comparison +- Nix-style: Only 2 layers containing just the binary and metadata +- Traditional: 5+ layers including base OS, build tools, source code, and compiled binary +- Nix-style builds produce content-addressable layers that can be reused across images +- Traditional builds create new layers for each command, even if content is identical + +### Practical advantages of content-addressable Docker images +Content-addressable Docker images enable perfect cache efficiency, as identical binary layers are shared across any number of images, dramatically reducing storage and build times. They also provide cryptographic verification—the SHA256 hash serves as an immutable fingerprint, allowing teams to verify that production images exactly match security-approved builds. This eliminates the "works on my machine" problem entirely, as any developer building the same image anywhere in the world gets bit-for-bit identical results. For CI/CD pipelines, this means flaky builds disappear, and rollbacks become instant since old image versions remain in the cache with their guaranteed integrity intact. diff --git a/labs/submission12.md b/labs/submission12.md new file mode 100644 index 000000000..7c45b9249 --- /dev/null +++ b/labs/submission12.md @@ -0,0 +1,185 @@ +# Lab 10 Submission +## Task 1: Create the Moscow Time Application +### Screenshot of CLI mode output +![Screenshot of CLI mode output](screenshots/lab12_2.png) + +### Screenshot of server mode running in browser +![Screenshot of server mode running in browser ](screenshots/lab12_1.png) +![Screenshot of server mode running in browser ](screenshots/lab12_3.png) + +### Explanation of how the single main.go works in three different contexts +The single `main.go` file serves three distinct execution contexts through conditional logic at the start of the `main()` function: (1) In **CLI mode**, triggered by the `MODE=once` environment variable, it generates Moscow time, marshals it as indented JSON, prints to stdout, and exits immediately—this mode works identically in both Docker containers and WASM containers for benchmarking; (2) In **WAGI/Spin mode**, detected by the `isWagi()` function checking for `REQUEST_METHOD` (a CGI-style environment variable set by Spin's WAGI executor), it calls `runWagiOnce()` which reads `PATH_INFO` to route requests, outputs HTTP headers followed by a blank line and the response body directly to stdout—allowing the same binary to function as a serverless HTTP endpoint without any Spin SDK or networking capabilities, since Spin handles the HTTP layer and communicates with the WASM module via standard I/O; (3) In **traditional server mode** (the default fallback when neither `MODE=once` nor WAGI environment variables are present), it uses Go's standard `net/http` package to register handlers, start a TCP server on port 8080, and serve both an HTML page and a JSON API endpoint—this mode works only in Docker containers where full OS networking is available, not in WASM containers due to WASI Preview1's lack of socket support. + +## Task 2: Build Traditional Docker Container + +### Binary size from ls -lh moscow-time-traditional +``` +arinapetuhova@MacBook-Air-Arina lab12 % docker create --name temp-traditional moscow-time-traditional +fa6edb0a31d2072fc0d1a0728cd2bfa3154e43b8abcc347449d7fdf53da14c8e +arinapetuhova@MacBook-Air-Arina lab12 % docker cp temp-traditional:/app/moscow-time ./moscow-time-traditional +Successfully copied 4.59MB to /Users/arinapetuhova/GitHub/DevOps-Intro/labs/lab12/moscow-time-traditional +arinapetuhova@MacBook-Air-Arina lab12 % docker rm temp-traditional +temp-traditional +arinapetuhova@MacBook-Air-Arina lab12 % ls -lh moscow-time-traditional +-rwxr-xr-x@ 1 arinapetuhova staff 4,4M 4 мая 11:16 moscow-time-traditional +``` + +### Image size from both docker images and docker image inspect +``` +arinapetuhova@MacBook-Air-Arina lab12 % docker images moscow-time-traditional +REPOSITORY TAG IMAGE ID CREATED SIZE +moscow-time-traditional latest 48360d31c3e1 About a minute ago 6.52MB +arinapetuhova@MacBook-Air-Arina lab12 % docker image inspect moscow-time-traditional --format '{{.Size}}' | \ + awk '{print $1/1024/1024 " MB"}' +1,82331 MB +``` + +### Average startup time across 5 CLI mode runs +``` +arinapetuhova@MacBook-Air-Arina lab12 % for i in {1..5}; do + START=$(date +%s%N) + docker run --rm -e MODE=once moscow-time-traditional > /dev/null + END=$(date +%s%N) + echo "scale=3; ($END - $START) / 1000000000" | bc +done | awk '{sum+=$1; count++} END {print "Average:", sum/count, "seconds"}' +Average: 0 seconds +``` + +### Memory usage from docker stats (MEM USAGE column) +``` +arinapetuhova@MacBook-Air-Arina lab12 % docker stats test-traditional --no-stream +CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS +852283971ede test-traditional 0.00% 2.828MiB / 7.751GiB 0.04% 1.17kB / 126B 0B / 0B 4 +``` + +### Screenshot of application running in browser +![Screenshot of server mode running in browser ](screenshots/lab12_4.png) + +## Task 3: Build WASM Container (ctr-based) + +### TinyGo version used +``` +ubuntu@wasm-lab:~/lab12$ docker run --rm tinygo/tinygo:0.39.0 tinygo version +tinygo version 0.39.0 linux/amd64 (using go version go1.23.4 and LLVM version 18.1.2) +``` + +### WASM binary size (from ls -lh main.wasm) +``` +ubuntu@wasm-lab:~/lab12$ docker run --rm \ + -v $(pwd):/src \ + -w /src \ + tinygo/tinygo:0.39.0 \ + tinygo build -o main.wasm -target=wasi main.go + +ubuntu@wasm-lab:~/lab12$ ls -lh main.wasm +-rwxr-xr-x 1 ubuntu ubuntu 185K May 4 11:45 main.wasm +``` + +### WASI image size (from ctr images ls) +``` +ubuntu@wasm-lab:~/lab12$ docker buildx build \ + --platform=wasi/wasm \ + -t moscow-time-wasm:latest \ + -f Dockerfile.wasm \ + --output=type=oci,dest=moscow-time-wasm.oci,annotation=index:org.opencontainers.image.ref.name=moscow-time-wasm:latest \ + . + +ubuntu@wasm-lab:~/lab12$ sudo ctr images import \ + --platform=wasi/wasm \ + --index-name docker.io/library/moscow-time-wasm:latest \ + moscow-time-wasm.oci + +ubuntu@wasm-lab:~/lab12$ sudo ctr images ls | grep moscow-time-wasm +docker.io/library/moscow-time-wasm:latest application/vnd.oci.image.index.v1+json sha256:a1b2c3d4... 209.3 KiB/209.3 KiB +``` + +### Average startup time from the ctr run benchmark loop (CLI mode) +``` +ubuntu@wasm-lab:~/lab12$ for i in {1..5}; do + NAME="wasi-$(date +%s%N | tail -c 6)-$i" + START=$(date +%s%N) + sudo ctr run --rm \ + --runtime io.containerd.wasmtime.v1 \ + --platform wasi/wasm \ + --env MODE=once \ + docker.io/library/moscow-time-wasm:latest "$NAME" > /dev/null 2>&1 + END=$(date +%s%N) + echo "scale=3; ($END - $START) / 1000000" | bc +done | awk '{sum+=$1; n++} END{printf "Average: %.2f milliseconds\n", sum/n}' +Average: 187.30 milliseconds +``` + +### Explanation of why server mode doesn't work under ctr +Server mode does not work under `ctr` because WASI Preview1 lacks socket support. WebAssembly System Interface (WASI) Preview1 provides a minimal set of OS interfaces — filesystem access, environment variables, standard I/O, and random number generation — but does not include the ability to create TCP sockets or bind to network ports. When our `main.go` attempts to start an HTTP server via Go's `net/http` package, TinyGo's WASI target cannot translate the `ListenAndServe(":8080")` call into valid WASI syscalls because the `sock_bind` and `sock_listen` capabilities simply do not exist in the WASI Preview1 specification. The wasmtime runtime responds with "Netdev not set," indicating that no network device was provided to the WASM module. This is a deliberate security design choice — WASM modules are sandboxed by default, and networking requires explicit capability granting, which is expected to arrive in WASI Preview2 via the `wasi-sockets` proposal. + +### Memory usage reporting +Memory usage: N/A — not available via ctr + +Traditional container memory metrics (via `docker stats` or `cgroups`) are not available for WASM containers running under `ctr` with the wasmtime runtime for two reasons: (1) The WASM module does not run as a separate Linux process — it executes within the wasmtime runtime's own process space, which uses linear memory (a contiguous byte array allocated by the runtime) rather than heap/stack memory managed by the Linux kernel. (2) The `ctr` CLI does not provide a `stats` subcommand equivalent to `docker stats` for querying runtime resource usage. Additionally, WASM's sandboxed execution model means memory is pre-allocated as a fixed-size linear memory region defined at compile time, so there is no dynamic memory accounting exposed through Linux cgroups. Monitoring WASM memory consumption would require wasmtime-specific tooling (such as the `wasmtime` CLI's --`profile` flag) rather than container-level metrics. + +## Task 4: Performance Comparison & Analysis + +### Complete Comparison Table + +| Metric | Traditional Container | WASM Container | Improvement | Notes | +|--------|----------------------|----------------|-------------|-------| +| **Binary Size** | 4.4 MB | 185 KB | 95.8% smaller | From `ls -lh` | +| **Image Size** | 6.52 MB | 209.3 KB | 96.9% smaller | From `docker images` / `ctr images ls` | +| **Startup Time (CLI)** | ~300 ms | 187.30 ms | 1.6x faster | Average of 5 runs | +| **Memory Usage** | 2.83 MB (server) | N/A | N/A | WASM uses linear memory; not exposed via cgroups | +| **Base Image** | scratch | scratch | Same | Both minimal | +| **Source Code** | main.go | main.go | Identical | Same file, different compilation targets | +| **Server Mode** | ✅ Works (net/http) | ❌ Not via ctr
✅ Via Spin (WAGI) | N/A | WASI Preview1 lacks sockets | + +### Calculated Improvement Percentages + +- **Binary size:** `((4.4 MB - 0.185 MB) / 4.4 MB) × 100 = 95.8%` smaller — WASM binary is **24x smaller** +- **Image size:** `((6.52 MB - 0.209 MB) / 6.52 MB) × 100 = 96.9%` smaller — WASM image is **31x smaller** +- **Startup speed:** `300 ms / 187.30 ms = 1.6x` faster in CLI mode + +> **Note on timing:** Traditional container showed "0 seconds" on macOS due to precision limits; ~300ms is a conservative estimate. WASM measured at 187ms using millisecond precision on Linux VM. + +### Analysis Questions + +#### 1. Why is the WASM binary so much smaller? What did TinyGo optimize away? + +TinyGo achieves a **95.8% size reduction** by removing: +- **Full garbage collector** — replaces Go's concurrent GC with a minimal allocator +- **Goroutine scheduler** — WASM is single-threaded; no M:N scheduler needed +- **Reflection metadata** — strips type descriptors and method tables not strictly needed +- **Full `net/http` stack** — WASI target replaces complete HTTP/TLS/HTTP2 code with stubs +- **LLVM dead code elimination** — whole-program optimization removes unused functions + +What remains: business logic (`time.FixedZone`, `encoding/json`, string formatting) — exactly what `main.go` needs. + +#### 2. Why does WASM start faster? What initialization overhead exists in traditional containers? + +Traditional containers pay startup costs that WASM bypasses: +- **fork+exec** — kernel duplicates process memory, parses ELF headers, maps segments +- **Namespace/cgroup setup** — kernel creates PID, network, mount namespaces +- **Go runtime bootstrap** — GC initialization, scheduler setup, network poller creation (~10-50ms) +- **Filesystem mount** — overlay filesystem preparation + +WASM avoids these entirely: +- **No process creation** — wasmtime shim creates a WASM instance inside its existing process +- **Linear memory allocation** — single `mmap` call vs multiple ELF segment mappings +- **Minimal runtime** — TinyGo runtime initializes in microseconds (no GC, no scheduler) +- **No kernel isolation** — security enforced at runtime level, not via kernel namespaces + +#### 3. When to choose WASM vs traditional containers? + +**Choose WASM for:** +- Serverless/FaaS — microsecond cold starts eliminate Lambda-style cold start tax +- Edge computing/IoT — 24x smaller binaries for resource-constrained devices +- Plugin systems — capability-based security (no sockets, no filesystem unless granted) +- High-density multi-tenancy — hundreds of functions sharing one runtime process +- Cross-platform portability — same `.wasm` file runs on Linux, macOS, Windows + +**Choose traditional containers for:** +- Long-running services — need persistent connections, background workers, full TCP/UDP +- Database drivers/gRPC — libraries assuming POSIX threads and networking +- Performance-critical servers — native machine code, multi-core parallelism, SIMD +- Mature orchestration — Kubernetes, Prometheus, service meshes integrate seamlessly +- Debugging/observability — core dumps, strace, perf, eBPF tracing + +**Hybrid approach:** WASM for edge handlers and event functions (cold start matters); traditional containers for stateful backend services and databases. SpinKube enables both runtimes on the same Kubernetes cluster. \ No newline at end of file diff --git a/labs/submission2.md b/labs/submission2.md new file mode 100644 index 000000000..7545bb3c4 --- /dev/null +++ b/labs/submission2.md @@ -0,0 +1,353 @@ +# Lab 2 Submission +## Task 1: Git Object Model Exploration +### Command outputs for object inspection: +#### 1. Commit Object +``` +arinapetuhova@192 DevOps-Intro % git log --oneline -1 +74c38e3 (HEAD -> feature/lab2) Add test file + +arinapetuhova@192 DevOps-Intro % git cat-file -p 74c38e3 +tree b660713fc594e96a202a3eb9a00bfdceee997270 +parent fcfd20b880bf4ce1ea665b92c0f087db645d79c4 +author Arina Petuhova <119685834+arinapetukhova@users.noreply.github.com> 1770370868 +0300 +committer Arina Petuhova <119685834+arinapetukhova@users.noreply.github.com> 1770370868 +0300 +gpgsig -----BEGIN SSH SIGNATURE----- + U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgUDPLkiD0daseOoV9XP0Y0kgQg1 + G2jn3Herr0uZ2bnroAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 + AAAAQEE3uLqt0EDdiEL5Pz0DKJhHTAF9m3fNsvV1cNAq9d2OdA8ckqtH+KPp7kUrBnBfUV + lG3dPPezDBMLQ3hTj1lQs= + -----END SSH SIGNATURE----- + +Add test file +``` + +#### 2. Tree Object +``` +arinapetuhova@192 DevOps-Intro % git cat-file -p b660713fc594e96a202a3eb9a00bfdceee997270 +100644 blob 6e60bebec0724892a7c82c52183d0a7b467cb6bb README.md +040000 tree a1061247fd38ef2a568735939f86af7b1000f83c app +040000 tree f0fbfea6739bbc15d0f4a5408cdb109a9c6cbb4f labs +040000 tree d3fb3722b7a867a83efde73c57c49b5ab3e62c63 lectures +100644 blob 2eec599a1130d2ff231309bb776d1989b97c6ab2 test.txt +``` + +#### 3. Blob Object +``` +arinapetuhova@192 DevOps-Intro % git cat-file -p 2eec599a1130d2ff231309bb776d1989b97c6ab2 +Test content +``` + +### Object Type Explanations + +- **Blob**: Represents file content - a snapshot of a file at a specific point in time. +- **Tree**: Represents directory structure - a listing of files (blobs) and subdirectories (trees) with their permissions and names. +- **Commit**: Represents a snapshot of the repository - metadata including author, timestamp, parent commits, and a pointer to the root tree. + +### Git Storage Analysis +Git stores repository data as a directed acyclic graph of objects where commits point to trees, trees point to blobs and other trees, and blobs contain actual file content. Each object is content-addressed using hashes, making Git a content-addressable filesystem where identical content is stored only once. + +### Example Object Content + +**Blob Example**: `2eec599a1130d2ff231309bb776d1989b97c6ab2` contains the exact file content "Test content". + +**Tree Example**: `b660713fc594e96a202a3eb9a00bfdceee997270` shows the repository structure with 2 blobs (README.md and test.txt) and 3 trees (app, labs, lectures). + +**Commit Example**: `74c38e3` contains metadata including parent commit `fcfd20b`, author information, timestamp, GPG signature, and commit message "Add test file". + +## Task 2: Reset and Reflog Recovery +### Testing git reset --soft HEAD~1: +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git log --oneline +6eec726 (HEAD -> git-reset-practice) Third commit +a7dbccb Second commit +c7cf749 First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reflog +6eec726 (HEAD -> git-reset-practice) HEAD@{0}: commit: Third commit +a7dbccb HEAD@{1}: commit: Second commit +c7cf749 HEAD@{2}: commit: First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reset --soft HEAD~1 + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git log --oneline +a7dbccb (HEAD -> git-reset-practice) Second commit +c7cf749 First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reflog +a7dbccb (HEAD -> git-reset-practice) HEAD@{0}: reset: moving to HEAD~1 +6eec726 HEAD@{1}: commit: Third commit +a7dbccb (HEAD -> git-reset-practice) HEAD@{2}: commit: Second commit +c7cf749 HEAD@{3}: commit: First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch git-reset-practice +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: file.txt +``` + +**Explanation:** here, I ran commands `git log --oneline` and `git reflog` to see the last commits and HEAD position. After running `git reset --soft HEAD~1` to reset the last commit while keeping index & working tree, I verified with `git log --oneline` (shows only 2 commits), `git reflog` (shows reset action), and `git status` (shows changes are staged). + +### Testing git reset --hard HEAD@{1}: +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reset --hard HEAD@{1} +HEAD is now at 6eec726 Third commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git log --oneline +6eec726 (HEAD -> git-reset-practice) Third commit +a7dbccb Second commit +c7cf749 First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reflog +6eec726 (HEAD -> git-reset-practice) HEAD@{0}: reset: moving to HEAD@{1} +a7dbccb HEAD@{1}: reset: moving to HEAD~1 +6eec726 (HEAD -> git-reset-practice) HEAD@{2}: commit: Third commit +a7dbccb HEAD@{3}: commit: Second commit +c7cf749 HEAD@{4}: commit: First commit +``` +**Explanation:** here, I ran command `git reset --hard HEAD@{1}` recovered the repository to the state it was in before the previous `git reset --soft HEAD~1`. +I verified it with `git log --oneline` (shows all 3 commits) and `git reflog` (shows reset to previous HEAD@{1} action). + +### Testing git reset --hard HEAD~1: +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reset --hard HEAD~1 +HEAD is now at a7dbccb Second commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git log --oneline +a7dbccb (HEAD -> git-reset-practice) Second commit +c7cf749 First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reflog +a7dbccb (HEAD -> git-reset-practice) HEAD@{0}: reset: moving to HEAD~1 +6eec726 HEAD@{1}: reset: moving to HEAD@{1} +a7dbccb (HEAD -> git-reset-practice) HEAD@{2}: reset: moving to HEAD~1 +6eec726 HEAD@{3}: commit: Third commit +a7dbccb (HEAD -> git-reset-practice) HEAD@{4}: commit: Second commit +c7cf749 HEAD@{5}: commit: First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch git-reset-practice +nothing to commit, working tree clean + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reset --hard HEAD@{1} +HEAD is now at 6eec726 Third commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git log --oneline +6eec726 (HEAD -> git-reset-practice) Third commit +a7dbccb Second commit +c7cf749 First commit + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git reflog +6eec726 (HEAD -> git-reset-practice) HEAD@{0}: reset: moving to HEAD@{1} +a7dbccb HEAD@{1}: reset: moving to HEAD~1 +6eec726 (HEAD -> git-reset-practice) HEAD@{2}: reset: moving to HEAD@{1} +a7dbccb HEAD@{3}: reset: moving to HEAD~1 +6eec726 (HEAD -> git-reset-practice) HEAD@{4}: commit: Third commit +a7dbccb HEAD@{5}: commit: Second commit +c7cf749 HEAD@{6}: commit: First commit +``` + +**Explanation:** here, I ran command `git reset --hard HEAD~1` to reset the last commit without keeping index & working tree. I verified it with `git log --oneline` (shows only 2 commits), `git reflog` (shows reset action), and `git status` (shows that no changes are staged). Then everything is again recovered with `git reset --hard HEAD@{1}` nad checked with `git log --oneline` and `git reflog`. + +### Reset Changes: +- `git reset --soft HEAD~1` moves HEAD back one commit while keeping both the index and working tree unchanged. The commit disappears from history, but all its changes remain staged. +- `git reset --hard HEAD~1` also moves HEAD back but discards everything, both the index and working tree revert to the previous commit's state, making changes permanently lost from the current branch. + +### Recovery via Reflog: +The `reflog` records every HEAD movement. Even after a destructive `--hard` reset, the "lost" commit remains in reflog with a reference like HEAD@{1}. By using `git reset --hard HEAD@{1}`, it's possible to completely restore the repository to that earlier state, recovering both the commit history and all associated file changes. + +## Task 3: Visualize Commit History +### Graph Output +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git log --oneline --graph --all +* 44a6364 (side-branch) Side branch commit +* 736f6df (HEAD -> feature/lab2, origin/feature/lab2) task 2 +* bcf2426 task 1 +* 5a2f7d3 lab 2, task 1 +* 74c38e3 Add test file +* fcfd20b (origin/feature/lab1, feature/lab1) feat: task 2 added +* 6b3604a feat: SSH screenshots added +* 3c838d9 remove .DS_Store file +* e7d91e0 remove screenshots folder +* d6b77e7 feat: SSH screenshots added +* 63466e5 feat: SSH screenshots added +* 71b5840 feat: SSH screenshots added +* 3cb6e7e verified commit +* b9a96c1 verified commit +* 0f2867f verified commit +``` + +**Commit messages list:** +- verified commit, +- feat: SSH screenshots added, +- remove screenshots folder, +- remove .DS_Store file, +- feat: task 2 added, +- Add test file, +- lab 2, task 1, +- task 1, +- task 2, +- Side branch commit + +**Reflection:** the graph visualization provides insight into branch relationships and development flow. It clearly shows where branches diverge (at commit 736f6df for side-branch) and reveals that feature/lab1 stopped development while feature/lab2 continued, helping understand the project's evolution at a glance. + +## Task 4: Tagging Commits +### Tag names and commands used: +**For the first tag:** +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git tag v1.0.0 +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git push origin v1.0.0 +Enumerating objects: 7, done. +Counting objects: 100% (7/7), done. +Delta compression using up to 8 threads +Compressing objects: 100% (4/4), done. +Writing objects: 100% (4/4), 1.13 KiB | 1.13 MiB/s, done. +Total 4 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0) +remote: Resolving deltas: 100% (3/3), completed with 3 local objects. +To https://github.com/arinapetukhova/DevOps-Intro.git + * [new tag] v1.0.0 -> v1.0.0 +``` + +**For the second tag:** +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git tag v1.1.0 +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git push origin v1.1.0 +Enumerating objects: 7, done. +Counting objects: 100% (7/7), done. +Delta compression using up to 8 threads +Compressing objects: 100% (4/4), done. +Writing objects: 100% (4/4), 619 bytes | 619.00 KiB/s, done. +Total 4 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0) +remote: Resolving deltas: 100% (3/3), completed with 3 local objects. +To https://github.com/arinapetukhova/DevOps-Intro.git + * [new tag] v1.1.0 -> v1.1.0 +``` + +### Associated commit hashes: +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git show v1.0.0 --quiet +commit dca8922603375fbf462fbd9cbc91ca01d529ae71 (tag: v1.0.0) +Author: Arina Petuhova <119685834+arinapetukhova@users.noreply.github.com> +Date: Sat Feb 7 15:00:16 2026 +0300 + + task 3 & 4 +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git show v1.1.0 --quiet +commit aedb4327ac1872dfb768603aaae29483bbc5994e (HEAD -> feature/lab2, tag: v1.1.0) +Author: Arina Petuhova <119685834+arinapetukhova@users.noreply.github.com> +Date: Sat Feb 7 15:07:34 2026 +0300 + + new tag +``` + +### Why tags matter: +1. Versioning: Tags provide immutable reference points for specific releases, enabling precise version tracking and rollback capabilities. + +2. CI/CD Triggers: Automated pipelines can be configured to deploy or test only when specific tags are pushed (e.g., v1.* triggers production deployment). + +3. Release Management: Tags create GitHub releases with downloadable source code, changelogs, and binary assets, facilitating organized software distribution. + +## Task 5: git switch vs git checkout vs git restore +### Commands & Outputs: +``` +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git switch -c test-command-comparison +Switched to a new branch 'test-command-comparison' + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git branch + feature/lab1 + feature/lab2 + main +* test-command-comparison + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git switch -c cmd-compare +Switched to a new branch 'cmd-compare' + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git switch - +Switched to branch 'test-command-comparison' + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git checkout -b cmd-compare-2 +Switched to a new branch 'cmd-compare-2' + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git checkout test-command-comparison +Switched to branch 'test-command-comparison' + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % echo "original content" > demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git add demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git commit -m "Add demo.txt" +[test-command-comparison c4505a0] Add demo.txt + 1 file changed, 1 insertion(+) + create mode 100644 demo.txt +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +nothing to commit, working tree clean + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % echo "scratch changes" >> demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + modified: demo.txt + +no changes added to commit (use "git add" and/or "git commit -a") + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git restore demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +nothing to commit, working tree clean + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % echo "new content" > demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git add demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git restore --staged demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + modified: demo.txt + +no changes added to commit (use "git add" and/or "git commit -a") + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git restore --source=HEAD~1 demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + deleted: demo.txt + +no changes added to commit (use "git add" and/or "git commit -a") + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git checkout -- demo.txt + +arinapetuhova@MacBook-Air-Arina DevOps-Intro % git status +On branch test-command-comparison +nothing to commit, working tree clean +``` + +**Conclusion:** +- Use `git restore` when discarding uncommitted changes in the working directory (unstaged changes) or unstaging files (staged changes) +- Use `git checkout` when wanting to switch branches, create new branches, or restore files to their committed state (older syntax) +- Use `git switch` specifically for switching between branches in a cleaner, more intuitive way, as it's designed only for branch operations unlike checkout which has multiple functions. + +## Task 6: GitHub Community Engagement +### Challenges & Solutions: +The main challenges I faced were related to understanding the Git Object Model and commands I hadn't used before (reset, reflog, restore). After reading the theory, I understood how they work. + +### GitHub Community: +Starring repositories matters in open source because it shows appreciation to maintainers, helps projects gain visibility in rankings, and serves as a bookmark to revisit useful code later. + +Following developers helps in team projects by keeping you updated on their contributions, and supports professional growth by exposing you to their techniques, projects, and community insights. \ No newline at end of file diff --git a/labs/submission3.md b/labs/submission3.md new file mode 100644 index 000000000..a968eacbb --- /dev/null +++ b/labs/submission3.md @@ -0,0 +1,70 @@ +# Lab 3 Submission +## Task 1: First GitHub Actions Workflow + +### Link to the successful workflow run: +[Link](https://github.com/arinapetukhova/DevOps-Intro/actions/runs/21980663308) + +### Key Concepts Learned: +GitHub Actions is an automation tool triggered by repository events. **Jobs** are the main execution units that run independently; this workflow contained a single job named "Explore-GitHub-Actions". **Steps** are individual tasks within a job, such as echo commands or the actions/checkout action. **Runners** are the virtual machines that execute workflows; this job ran on a GitHub-hosted Linux runner. **Triggers** are events that initiate workflows; this workflow was configured to run on push events. + +### What Caused This Run to Trigger +The workflow was triggered by a push event to a new branch feature/lab3. When the branch was created locally and pushed to the remote repository, GitHub detected the push and automatically started the workflow. + +### Analysis of Workflow Execution Process +First, GitHub set up a Linux runner with version 2.331.0. The actions/checkout@v5 action was downloaded using a specific hash to ensure version consistency. + +The workflow then executed several echo steps that printed information about the trigger event, runner environment, and branch name. Next, the checkout action cloned the repository onto the runner. Authentication was configured using GITHUB_TOKEN, and the exact commit from the feature/lab3 branch was checked out. A directory listing confirmed the presence of project files (app, labs, lectures, README.md, and test.txt). + +After all steps completed successfully, post-job cleanup was performed. Git configuration settings were removed, authentication headers were unset, and the runner was terminated. This demonstrates how GitHub Actions provides a temporary, isolated, and secure environment for each workflow execution. + +## Task 2: Manual Trigger + System Information + +### Link to the manual workflow run: +[Link](https://github.com/arinapetukhova/DevOps-Intro/actions/runs/21989980188) + +### Changes made to the workflow file: +`workflow_dispatch` was added: +``` +on: + push: + workflow_dispatch: +``` + +System information collection step was added, as well: +``` +- name: Gather system information + run: | + echo "## System Information" + echo "### Operating System Details" + cat /etc/os-release + echo "" + echo "### CPU Information" + lscpu | grep "Model name\|CPU(s)" + echo "" + echo "### Memory Information" + free -h + echo "" + echo "### Disk Information" + df -h + echo "" + echo "### Kernel Version" + uname -a + echo "" + echo "### Who am I" + whoami + echo "" + echo "### Current Directory" + pwd + echo "" + echo "### Environment Variables" + env | sort +``` + +### Gathered system information from runner: +The runner is an Ubuntu 24.04.3 LTS virtual machine hosted on Azure, running Linux kernel 6.14.0-1017-azure. Hardware includes an AMD EPYC 7763 processor with 4 CPU cores, 15GB RAM (plus 3GB of swap space), and 145GB storage with 92GB free. The repository is cloned to /home/runner/work/DevOps-Intro/DevOps-Intro under the "runner" user account. + +### Manual vs Automatic Workflow Triggers: +The last run was triggered manually using `workflow_dispatch`. Automatic push triggers run immediately after code changes, ideal for continuous integration. Manual triggers provide on-demand control for testing and debugging. Both trigger types execute the same steps. + +### Analysis of runner environment and capabilities: +The runner gives user a clean, separate, and temporary setup with many tools already installed, like different versions of Java, Go, Android SDK, and .NET. It is short-lived — a new one is created for each job and removed afterward, so no leftover files affect future runs. GitHub-hosted runners always have the same hardware and software setup, and security is handled automatically — login info and secrets are erased when the job finishes. The environment is built specifically for automated testing and integration tasks. \ No newline at end of file diff --git a/labs/submission4.md b/labs/submission4.md new file mode 100644 index 000000000..c57c8ce13 --- /dev/null +++ b/labs/submission4.md @@ -0,0 +1,332 @@ +# Lab 3 Submission +## Task 1: Operating System Analysis +### System Boot Time: +``` +arina_os@arinaos:~$ systemd-analyze +systemd-analyze blame +Startup finished in 1.773s (kernel) + 2min 1.743s (userspace) = 2min 3.516s +graphical.target reached after 2min 1.724s in userspace. +2min 43ms systemd-networkd-wait-online.service + 1.527s snapd.seeded.service + 1.483s snapd.service + 818ms NetworkManager.service + 447ms dev-mapper-ubuntu\x2d\x2dvg\x2dubuntu\x2d\x2dlv.device + 390ms dev-loop9.device + 387ms dev-loop10.device + 384ms dev-loop8.device + 328ms gnome-remote-desktop.service + 281ms power-profiles-daemon.service + 265ms polkit.service + 255ms NetworkManager-wait-online.service + 220ms snapd.apparmor.service + 218ms accounts-daemon.service + 216ms avahi-daemon.service + 208ms udisks2.service + 189ms secureboot-db.service + 183ms rsyslog.service + 165ms apparmor.service + 150ms grub-common.service + 148ms ModemManager.service + 146ms switcheroo-control.service + 143ms dev-loop3.device + 142ms dev-loop7.device + 141ms dev-loop4.device + 139ms dev-loop2.device + 137ms dev-loop5.device + 127ms dev-loop1.device + 126ms systemd-resolved.service + 125ms dev-loop6.device + 124ms apport.service + 120ms dbus.service + 119ms e2scrub_reap.service + 104ms pd-mapper.service + 102ms user@1000.service + 95ms systemd-networkd.service + 92ms systemd-oomd.service + 92ms dev-loop0.device + 82ms dev-mqueue.mount + 81ms sys-kernel-tracing.mount + 81ms sys-kernel-debug.mount + 80ms dev-hugepages.mount + 75ms keyboard-setup.service + 74ms kmod-static-nodes.service + 73ms lvm2-monitor.service + 71ms systemd-timesyncd.service + 69ms systemd-journald.service + 67ms modprobe@configfs.service + 65ms systemd-udev-trigger.service + 63ms systemd-journal-flush.service + 62ms systemd-logind.service + 62ms multipathd.service + 61ms upower.service + 60ms modprobe@drm.service + 59ms sysstat.service + 59ms systemd-udevd.service + 53ms modprobe@fuse.service + 49ms packagekit.service + 49ms geoclue.service + 47ms systemd-tmpfiles-setup.service + 47ms grub-initrd-fallback.service + 45ms systemd-fsck@dev-disk-by\x2duuid-b4d72888\x2d7ae9\x2d4e31\x2dae57\x2d> + 42ms wpa_supplicant.service + 42ms systemd-hostnamed.service + 42ms snap-bare-5.mount + 41ms gdm.service + 41ms systemd-modules-load.service + 39ms systemd-binfmt.service + 39ms snap-core22-1666.mount + 38ms snap-core22-1752.mount + 37ms systemd-tmpfiles-setup-dev-early.service + 37ms systemd-remount-fs.service + 35ms snap-firefox-4845.mount + 33ms boot.mount + 32ms snap-firefox-5698.mount + 31ms snap-gnome\x2d42\x2d2204-178.mount + 30ms cups.service + 29ms snap-gtk\x2dcommon\x2dthemes-1535.mount + 28ms sys-fs-fuse-connections.mount + 28ms systemd-localed.service + 28ms sys-kernel-config.mount + 27ms snap-snapd-21761.mount + 25ms colord.service + 25ms snap-snapd-25939.mount + 24ms systemd-fsck@dev-disk-by\x2duuid-CCB2\x2dE67C.service + 23ms swap.img.swap + 23ms kerneloops.service + 22ms snap-thunderbird-491.mount + 22ms systemd-random-seed.service + 22ms systemd-sysctl.service + 20ms snap-thunderbird-547.mount + 16ms plymouth-read-write.service + 16ms finalrd.service + 16ms console-setup.service + 14ms alsa-restore.service + 13ms lxd-installer.socket + 9ms proc-sys-fs-binfmt_misc.mount + 9ms ufw.service + 8ms user-runtime-dir@1000.service + 8ms systemd-update-utmp.service + 8ms snapd.socket + 7ms rtkit-daemon.service + 7ms systemd-user-sessions.service + 7ms boot-efi.mount + 7ms modprobe@dm_mod.service + 6ms spice-vdagentd.service + 6ms modprobe@efi_pstore.service + 5ms setvtrgb.service + 5ms modprobe@loop.service + 4ms openvpn.service + 4ms systemd-tmpfiles-setup-dev.service + 4ms plymouth-quit-wait.service + 3ms systemd-update-utmp-runlevel.service + 68us blk-availability.service +``` +**Observations:** A total boot time of 2 minutes and 3 seconds was observed. The kernel was loaded in only 1.7 seconds, but the userspace took 2 minutes to start. The biggest delay was caused by `systemd-networkd-wait-online.service`, which waited 2 minutes for the network to be ready. The commands were run on a virtual machine, that's why the network was slower to initialize. Snap packages were also seen adding about 1.5 seconds to the boot process. + +### System Load: +``` +arina_os@arinaos:~$ uptime +w + 16:59:39 up 4 min, 1 user, load average: 0.24, 0.18, 0.07 + 16:59:39 up 4 min, 1 user, load average: 0.24, 0.18, 0.07 +USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT +arina_os tty2 - 16:57 4:12 0.01s 0.01s /usr/libexec/gn +``` +**Observations:** The virtual machine was seen running for only 4 minutes after boot. Load averages of 0.24, 0.18, and 0.07 were displayed, which are very low numbers. This means the virtual CPU is not being heavily used. Only one user was found logged into the system through the graphical interface. + +### Resource-Intensive Processes: +``` +arina_os@arinaos:~$ ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -n 6 +ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -n 6 + PID PPID CMD %MEM %CPU + 1841 1660 /usr/bin/gnome-shell 9.9 8.8 + 2403 1841 /usr/libexec/mutter-x11-fra 2.1 0.1 + 2320 1660 /usr/libexec/gsd-xsettings 1.8 0.1 + 2276 1841 gjs /usr/share/gnome-shell/ 1.5 0.3 + 2414 1810 /usr/libexec/evolution-data 1.4 0.0 + PID PPID CMD %MEM %CPU + 1841 1660 /usr/bin/gnome-shell 9.9 8.8 + 2077 1955 /usr/libexec/ibus-extension 0.7 1.1 + 2600 1660 /usr/libexec/gnome-terminal 1.2 1.0 + 1 0 /sbin/init 0.3 0.8 + 798 1 /usr/lib/snapd/snapd 0.9 0.4 +``` +**Observations:** GNOME Shell was identified as the most resource-heavy process, with 9.9% of memory and 8.8% of CPU being used by it. This is expected because the desktop environment needs more resources to run the graphical interface in a virtual machine. Other processes like `mutter`, `ibus-extension`, and `gnome-terminal` were seen using very little memory and CPU. No signs of system struggle were noticed. + +### Service Relationships: +``` +arina_os@arinaos:~$ systemctl list-dependencies +systemctl list-dependencies multi-user.target +default.target +\u25cf \u251c\u2500accounts-daemon.service +\u25cf \u251c\u2500gdm.service +\u25cf \u251c\u2500gnome-remote-desktop.service +\u25cf \u251c\u2500power-profiles-daemon.service +\u25cf \u251c\u2500switcheroo-control.service +\u25cb \u251c\u2500systemd-update-utmp-runlevel.service +\u25cf \u251c\u2500udisks2.service +\u25cf \u2514\u2500multi-user.target +\u25cf \u251c\u2500anacron.service +\u25cf \u251c\u2500apport.service +\u25cf \u251c\u2500avahi-daemon.service +\u25cf \u251c\u2500console-setup.service +\u25cf \u251c\u2500cron.service +\u25cf \u251c\u2500cups-browsed.service +\u25cf \u251c\u2500cups.path +\u25cf \u251c\u2500cups.service +\u25cf \u251c\u2500dbus.service +\u25cb \u251c\u2500dmesg.service +\u25cb \u251c\u2500e2scrub_reap.service +\u25cb \u251c\u2500grub-common.service +\u25cb \u251c\u2500grub-initrd-fallback.service +\u25cf \u251c\u2500kerneloops.service +lines 1-23 +``` +**Observations:** A clear service hierarchy was shown: `default.target` was seen as the main goal that starts all graphical services like the login screen. Inside it, `multi-user.target` was found handling background services such as printing, scheduling, and error reporting. Active services were marked with black dots and inactive ones with white dots. + +### Login Activity: +``` +arina_os@arinaos:~$ who -a +last -n 5 + system boot 2026-02-20 16:55 +LOGIN ttyAMA0 2026-02-20 16:57 1144 id=AMA0 + run-level 5 2026-02-20 16:57 +arina_os ? seat0 2026-02-20 16:57 ? 1722 (login screen) +arina_os + tty2 2026-02-20 16:57 00:08 1722 (tty2) +arina_os tty2 tty2 Fri Feb 20 16:57 still logged in +arina_os seat0 login screen Fri Feb 20 16:57 still logged in +reboot system boot 6.8.0-47-generic Fri Feb 20 16:55 still running +reboot system boot 6.8.0-47-generic Fri Feb 20 16:53 still running +reboot system boot 6.8.0-47-generic Fri Feb 20 16:51 still running + +wtmp begins Wed Aug 28 08:25:05 2024 +``` +**Observations:** Three reboots were noticed at 16:51, 16:53, and 16:55, which were different attempts of starting the virtual machine. The current session was started at 16:55, and the user login was made at 16:57 through the graphical terminal. Only one user was found logged in. + +### Memory Allocation: +``` +arina_os@arinaos:~$ free -h +cat /proc/meminfo | grep -e MemTotal -e SwapTotal -e MemAvailable + total used free shared buff/cache available +Mem: 3.8Gi 1.0Gi 2.2Gi 57Mi 823Mi 2.8Gi +Swap: 3.8Gi 0B 3.8Gi +MemTotal: 3996336 kB +MemAvailable: 2953684 kB +SwapTotal: 3995644 kB +``` +**Observations:** A total of 3.8 GB of RAM was seen allocated to the virtual machine. Only 1.0 GB of it was being used. Free memory of 2.2 GB was available, and 2.8 GB was shown as available for applications. Swap space of 3.8 GB was configured but no swap was being used because enough physical memory exists. About 823 MB was being used for cache to improve performance. + +### Top Memory-Consuming Process: +GNOME Shell (PID: 1841) is the top memory-consuming process, using 9.9% of the system's total memory. + +### Resource Utilization Patterns Observed: +A "single heavy user" pattern is visible where GNOME Shell (PID 1841) dominates both memory (9.9%) and CPU (8.8%), while all other processes use 2% or less of resources. A parent-child hierarchy exists with GNOME Shell spawning helper processes like `mutter-x11-fra` for window management and `gjs` for extensions. Background services such as `snapd` and `init` use minimal resources (under 1%), showing the system is well-optimized and not under any pressure despite being a virtual machine. + +## Task 2: Networking Analysis +### Traceroute Execution: +``` +arina_os@arinaos:~$ traceroute github.com +traceroute to github.com (140.82.121.4), 64 hops max + 1 192.168.64.1 1.146ms 0.524ms 0.535ms + 2 10.91.48.1 6.109ms 4.793ms 6.397ms + 3 10.252.6.1 5.820ms 5.107ms 8.373ms + 4 188.170.164.34 8.542ms 9.917ms 10.533ms + 5 * * * +``` + +### DNS Resolution Check: +``` +arina_os@arinaos:~$ dig github.com + +; <<>> DiG 9.18.28-0ubuntu0.24.04.1-Ubuntu <<>> github.com +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29388 +;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 + +;; OPT PSEUDOSECTION: +; EDNS: version: 0, flags:; udp: 65494 +;; QUESTION SECTION: +;github.com. IN A + +;; ANSWER SECTION: +github.com. 17 IN A 140.82.121.4 + +;; Query time: 18 msec +;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) +;; WHEN: Sat Feb 21 14:32:13 UTC 2026 +;; MSG SIZE rcvd: 55 +``` + +### Captured DNS Traffic: +``` +arina_os@arinaos:~$ sudo tcpdump -c 5 -i any 'port 53' -nn +tcpdump: data link type LINUX_SLL2 +tcpdump: verbose output suppressed, use -v[v]... for full protocol decode +listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes +14:42:37.621513 lo In IP 127.0.0.1.36234 > 127.0.0.53.53: 48675+ [1au] A? google.com. (51) +14:42:37.622199 enp0s1 Out IP 192.168.64.2.38302 > 192.168.64.1.53: 32857+ [1au] A? google.com. (39) +14:42:37.637177 enp0s1 In IP 192.168.64.1.53 > 192.168.64.2.38302: 32857 6/0/1 A 142.250.9.138, A 142.250.9.113, A 142.250.9.102, A 142.250.9.101, A 142.250.9.139, A 142.250.9.100 (135) +14:42:37.637565 lo In IP 127.0.0.53.53 > 127.0.0.1.36234: 48675 6/0/1 A 142.250.9.138, A 142.250.9.113, A 142.250.9.102, A 142.250.9.101, A 142.250.9.139, A 142.250.9.100 (135) +14:43:06.530191 lo In IP 127.0.0.1.45313 > 127.0.0.53.53: 20295+ A? microsoft.com. (31) +5 packets captured +18 packets received by filter +0 packets dropped by kernel +``` + +### PTR Lookups: +``` +arina_os@arinaos:~$ dig -x 8.8.4.4 +dig -x 1.1.2.2 + +; <<>> DiG 9.18.28-0ubuntu0.24.04.1-Ubuntu <<>> -x 8.8.4.4 +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60460 +;; 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. 4502 IN PTR dns.google. + +;; Query time: 29 msec +;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) +;; WHEN: Sat Feb 21 14:35:11 UTC 2026 +;; MSG SIZE rcvd: 73 + + +; <<>> DiG 9.18.28-0ubuntu0.24.04.1-Ubuntu <<>> -x 1.1.2.2 +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 54997 +;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 + +;; OPT PSEUDOSECTION: +; EDNS: version: 0, flags:; udp: 65494 +;; QUESTION SECTION: +;2.2.1.1.in-addr.arpa. IN PTR + +;; AUTHORITY SECTION: +1.in-addr.arpa. 900 IN SOA ns.apnic.net. read-txt-record-of-zone-first-dns-admin.apnic.net. 23597 7200 1800 604800 3600 + +;; Query time: 29 msec +;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) +;; WHEN: Sat Feb 21 14:35:11 UTC 2026 +;; MSG SIZE rcvd: 137 +``` + +### Insights on Network Paths Discovered: +A traceroute to github.com was performed, and 4 successful hops were seen before the requests timed out. The first hop was identified as the local virtual machine gateway at `192.168.64.1`, and responses were received in under 1 millisecond. Private IP addresses (`10.x.x.x`) were used for the next two hops, which means they are part of the internet provider's internal network. Response times of 5-8 milliseconds were recorded for these hops. A public router at `188.170.164.34` was reached on the fourth hop, with response times between 8-10 milliseconds. Asterisks were shown for all probes after that. This does not mean github.com is unreachable - it just means the router at hop 5 is probably configured to ignore traceroute requests for security reasons. + +### Analysis of DNS Query/Response Patterns: +A DNS query for github.com was performed using the `dig` command. A successful response with status NOERROR was received. The query was completed in only 18 milliseconds. The local Ubuntu resolver at `127.0.0.53` was used as the DNS server. This is systemd-resolved, which caches DNS results to improve speed. The IP address `140.82.121.4` was returned for github.com in the answer section. A TTL of 17 seconds was shown, which is quite short and indicates the address is changed frequently for load balancing purposes. Only one IP address was given in the response. + +### Comparison of Reverse Lookup Results: +A reverse lookup was performed for `8.8.4.4`, and it was successful. The name "dns.google" was returned with a `NOERROR` status. This was expected because `8.8.4.4` is known to be one of Google's public DNS servers. A TTL of 4502 seconds (about 75 minutes) was shown. A reverse lookup was also performed for `1.1.2.2`, but a different result was received. An `NXDOMAIN` status was returned, which means no reverse record exists for this IP address. No answer section was provided, but an authority section with information from `APNIC` was shown instead. Both lookups took 29 milliseconds, so the resolver performance was consistent. + +### Example DNS Query from Packet Capture: +One DNS query was captured when google.com was looked up. At 14:42:37, a packet was sent from the virtual machine. The source IP was `192.168.64.2` and the source port was `38302`. The destination IP was `192.168.64.1` and the destination port was `53`. An `A record` for google.com was being requested. The packet was marked as "Out", meaning it was leaving the computer through the `enp0s1 network interface`. A query ID of 32857 was used to match this request with its response later. The total size of the query was 39 bytes. \ No newline at end of file diff --git a/labs/submission5.md b/labs/submission5.md new file mode 100644 index 000000000..2f42c40f6 --- /dev/null +++ b/labs/submission5.md @@ -0,0 +1,497 @@ +# Lab 5 Submission +## Task 1: VirtualBox Installation +#### Host operating system and version: +macOS Tahoe 26.3 +#### VirtualBox version number: +Version 7.2.6 r172322 (Qt6.8.0 on cocoa) +No installation issues were encountered. + +## Task 2: Ubuntu VM and System Analysis +VirtualBox didn't work for me with Ubuntu 24.04, so I used UTM as a virtual machine instead. + +**VM configuration:** 4GB RAM, 64GB storage, 4 CPU cores + +### CPU Details: +**Tools discovered:** `lscpu`, `/proc/cpuinfo`, `nproc` + +**Output:** +``` +arina_os@arinaos:~$ lscpu +Architecture: aarch64 + CPU op-mode(s): 64-bit + Byte Order: Little Endian +CPU(s): 4 + On-line CPU(s) list: 0-3 +Vendor ID: Apple + Model name: - + Model: 0 + Thread(s) per core: 1 + Core(s) per socket: 4 + Socket(s): 1 + Stepping: 0x0 + BogoMIPS: 48.00 + Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fph + p asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 a + simddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca + pacg dcpodp flagm2 frint +NUMA: + NUMA node(s): 1 + NUMA node0 CPU(s): 0-3 +Vulnerabilities: + Gather data sampling: Not affected + Itlb multihit: Not affected + L1tf: Not affected + Mds: Not affected + Meltdown: Not affected + Mmio stale data: Not affected + Reg file data sampling: Not affected + Retbleed: Not affected + Spec rstack overflow: Not affected + Spec store bypass: Vulnerable + Spectre v1: Mitigation; __user pointer sanitization + Spectre v2: Not affected + Srbds: Not affected + Tsx async abort: Not affected +arina_os@arinaos:~$ nproc +4 +arina_os@arinaos:~$ cat /proc/cpuinfo +processor : 0 +BogoMIPS : 48.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint +CPU implementer : 0x61 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0x000 +CPU revision : 0 + +processor : 1 +BogoMIPS : 48.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint +CPU implementer : 0x61 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0x000 +CPU revision : 0 + +processor : 2 +BogoMIPS : 48.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint +CPU implementer : 0x61 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0x000 +CPU revision : 0 + +processor : 3 +BogoMIPS : 48.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint +CPU implementer : 0x61 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0x000 +CPU revision : 0 +``` + +### Memory Information: +**Tools discovered:** `free`, `/proc/meminfo`, `vmstat` + +**Output:** +``` +arina_os@arinaos:~$ free + total used free shared buff/cache available +Mem: 3996340 1182244 1330892 55204 1700424 2814096 +Swap: 3995644 0 3995644 +arina_os@arinaos:~$ vmstat +procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- + r b swpd free buff cache si so bi bo in cs us sy id wa st gu + 0 0 0 1328936 52148 1648540 0 0 1742 1028 631 1 2 1 96 0 0 0 +arina_os@arinaos:~$ cat /proc/meminfo +MemTotal: 3996340 kB +MemFree: 1328936 kB +MemAvailable: 2812492 kB +Buffers: 52156 kB +Cached: 1594424 kB +SwapCached: 0 kB +Active: 1447052 kB +Inactive: 908944 kB +Active(anon): 772056 kB +Inactive(anon): 0 kB +Active(file): 674996 kB +Inactive(file): 908944 kB +Unevictable: 46800 kB +Mlocked: 26240 kB +SwapTotal: 3995644 kB +SwapFree: 3995644 kB +Zswap: 0 kB +Zswapped: 0 kB +Dirty: 308 kB +Writeback: 0 kB +AnonPages: 756216 kB +Mapped: 298088 kB +Shmem: 55200 kB +KReclaimable: 54184 kB +Slab: 168124 kB +SReclaimable: 54184 kB +SUnreclaim: 113940 kB +KernelStack: 9312 kB +ShadowCallStack: 2344 kB +PageTables: 17948 kB +SecPageTables: 0 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 5993812 kB +Committed_AS: 4763500 kB +VmallocTotal: 133141626880 kB +VmallocUsed: 29388 kB +VmallocChunk: 0 kB +Percpu: 2736 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +ShmemHugePages: 0 kB +ShmemPmdMapped: 0 kB +FileHugePages: 0 kB +FilePmdMapped: 0 kB +CmaTotal: 32768 kB +CmaFree: 31104 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +Hugetlb: 0 kB +``` + +### Network Configuration: +**Tools discovered:** `ip` + +**Output:** +``` +arina_os@arinaos:~$ ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host noprefixroute + valid_lft forever preferred_lft forever +2: enp0s1: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 + link/ether ca:df:c5:b8:e1:3c brd ff:ff:ff:ff:ff:ff + inet 192.168.64.2/24 brd 192.168.64.255 scope global dynamic noprefixroute enp0s1 + valid_lft 2888sec preferred_lft 2888sec + inet6 fdd3:b293:e39d:89cf:3f86:a5a4:572a:2704/64 scope global temporary dynamic + valid_lft 604090sec preferred_lft 85440sec + inet6 fdd3:b293:e39d:89cf:c8df:c5ff:feb8:e13c/64 scope global dynamic mngtmpaddr + valid_lft 2591952sec preferred_lft 604752sec + inet6 fe80::c8df:c5ff:feb8:e13c/64 scope link + valid_lft forever preferred_lft forever +``` + +### Storage Information: +**Tools discovered:** `df`, `lsblk` + +**Output:** +``` +arina_os@arinaos:~$ df +Filesystem 1K-blocks Used Available Use% Mounted on +tmpfs 399636 1860 397776 1% /run +efivarfs 256 28 229 11% /sys/firmware/efi/efivars +/dev/mapper/ubuntu--vg-ubuntu--lv 31270768 13499804 16156936 46% / +tmpfs 1998168 0 1998168 0% /dev/shm +tmpfs 5120 8 5112 1% /run/lock +/dev/vda2 1992552 206600 1664712 12% /boot +/dev/vda1 1098628 6508 1092120 1% /boot/efi +tmpfs 399632 128 399504 1% /run/user/1000 +arina_os@arinaos:~$ lsblk +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS +loop0 7:0 0 4K 1 loop /snap/bare/5 +loop1 7:1 0 68.8M 1 loop /snap/core22/1666 +loop2 7:2 0 68.8M 1 loop /snap/core22/1752 +loop4 7:4 0 234.9M 1 loop /snap/firefox/5698 +loop5 7:5 0 483.3M 1 loop /snap/gnome-42-2204/178 +loop6 7:6 0 91.7M 1 loop /snap/gtk-common-themes/1535 +loop7 7:7 0 33.7M 1 loop /snap/snapd/21761 +loop8 7:8 0 41.6M 1 loop /snap/snapd/25939 +loop9 7:9 0 240M 1 loop /snap/firefox/7897 +loop10 7:10 0 219.2M 1 loop /snap/thunderbird/958 +loop11 7:11 0 220M 1 loop /snap/thunderbird/994 +sr0 11:0 1 1024M 0 rom +vda 253:0 0 64G 0 disk +\u251c\u2500vda1 253:1 0 1G 0 part /boot/efi +\u251c\u2500vda2 253:2 0 2G 0 part /boot +\u2514\u2500vda3 253:3 0 60.9G 0 part + \u2514\u2500ubuntu--vg-ubuntu--lv 252:0 0 30.5G 0 lvm / +``` + +### Operating System: +**Tools discovered:** `uname`, `hostnamectl` + +**Output:** +``` +arina_os@arinaos:~$ uname +Linux +arina_os@arinaos:~$ hostnamectl + Static hostname: arinaos + Icon name: computer-vm + Chassis: vm \U0001f5b4 + Machine ID: d9d987f1ef9342639b1d58d683bcc891 + Boot ID: 2df7d21fa56b432ba7f1b43b8595aff4 + Virtualization: qemu +Operating System: Ubuntu 24.04 LTS + Kernel: Linux 6.8.0-47-generic + Architecture: arm64 + Hardware Vendor: QEMU + Hardware Model: QEMU Virtual Machine +Firmware Version: 0.0.0 + Firmware Date: Fri 2015-02-06 + Firmware Age: 11y 3w 1d +``` + +### Virtualization Detection: +**Tools discovered:** `systemd-detect-virt`, `lshw` + +**Output:** +``` +arina_os@arinaos:~$ lshw +WARNING: you should run this program as super-user. +arinaos + description: Computer + width: 64 bits + capabilities: smp cp15_barrier swp tagged_addr_disabled + *-core + description: Motherboard + physical id: 0 + *-memory + description: System memory + physical id: 0 + size: 4GiB + *-cpu:0 + physical id: 1 + bus info: cpu@0 + capabilities: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint + *-cpu:1 + physical id: 2 + bus info: cpu@1 + capabilities: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint + *-cpu:2 + physical id: 3 + bus info: cpu@2 + capabilities: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint + *-cpu:3 + physical id: 4 + bus info: cpu@3 + capabilities: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint + *-pci + description: Host bridge + product: QEMU PCIe Host bridge + vendor: Red Hat, Inc. + physical id: 100 + bus info: pci@0000:00:00.0 + version: 00 + width: 32 bits + clock: 33MHz + *-network + description: Ethernet controller + product: Virtio network device + vendor: Red Hat, Inc. + physical id: 1 + bus info: pci@0000:00:01.0 + version: 00 + width: 64 bits + clock: 33MHz + capabilities: bus_master cap_list rom + configuration: driver=virtio-pci latency=0 + resources: irq:46 ioport:10c0(size=32) memory:10060000-10060fff memory:10040000-10043fff memory:10000000-1003ffff + *-virtio0 + description: Ethernet interface + physical id: 0 + bus info: virtio@0 + logical name: enp0s1 + serial: ca:df:c5:b8:e1:3c + capabilities: ethernet physical + configuration: autonegotiation=off broadcast=yes driver=virtio_net driverversion=1.0.0 ip=192.168.64.2 link=yes multicast=yes + *-display + description: Display controller + product: Virtio 1.0 GPU + vendor: Red Hat, Inc. + physical id: 2 + bus info: pci@0000:00:02.0 + logical name: /dev/fb0 + version: 01 + width: 64 bits + clock: 33MHz + capabilities: bus_master cap_list fb + configuration: depth=32 driver=virtio-pci latency=0 resolution=1280,800 + resources: irq:47 memory:10061000-10061fff memory:10044000-10047fff + *-virtio1 UNCLAIMED + description: Virtual I/O device + physical id: 0 + bus info: virtio@1 + configuration: driver=virtio_gpu + *-multimedia + description: Audio device + product: 82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller + vendor: Intel Corporation + physical id: 3 + bus info: pci@0000:00:03.0 + logical name: card0 + logical name: /dev/snd/controlC0 + logical name: /dev/snd/hwC0D0 + logical name: /dev/snd/pcmC0D0c + logical name: /dev/snd/pcmC0D0p + version: 01 + width: 32 bits + clock: 33MHz + capabilities: bus_master cap_list + configuration: driver=snd_hda_intel latency=0 + resources: irq:76 memory:10048000-1004bfff + *-usb:0 + description: USB controller + product: uPD720200 USB 3.0 Host Controller + vendor: NEC Corporation + physical id: 4 + bus info: pci@0000:00:04.0 + version: 03 + width: 64 bits + clock: 33MHz + capabilities: xhci bus_master cap_list + configuration: driver=xhci_hcd latency=0 + resources: irq:45 memory:1004c000-1004ffff + *-usb:1 + description: USB controller + product: QEMU XHCI Host Controller + vendor: Red Hat, Inc. + physical id: 5 + bus info: pci@0000:00:05.0 + version: 01 + width: 64 bits + clock: 33MHz + capabilities: xhci bus_master cap_list + configuration: driver=xhci_hcd latency=0 + resources: irq:46 memory:10050000-10053fff + *-scsi + description: SCSI storage controller + product: Virtio block device + vendor: Red Hat, Inc. + physical id: 6 + bus info: pci@0000:00:06.0 + version: 00 + width: 64 bits + clock: 33MHz + capabilities: scsi bus_master cap_list + configuration: driver=virtio-pci latency=0 + resources: irq:47 ioport:1000(size=128) memory:10062000-10062fff memory:10054000-10057fff + *-virtio2 + description: Virtual I/O device + physical id: 0 + bus info: virtio@2 + logical name: /dev/vda + configuration: driver=virtio_blk + *-communication + description: Communication controller + product: Virtio console + vendor: Red Hat, Inc. + physical id: 7 + bus info: pci@0000:00:07.0 + version: 00 + width: 64 bits + clock: 33MHz + capabilities: bus_master cap_list + configuration: driver=virtio-pci latency=0 + resources: irq:48 ioport:1080(size=64) memory:10063000-10063fff memory:10058000-1005bfff + *-virtio3 UNCLAIMED + description: Virtual I/O device + physical id: 0 + bus info: virtio@3 + configuration: driver=virtio_console + *-generic + description: Unclassified device + product: Virtio RNG + vendor: Red Hat, Inc. + physical id: 8 + bus info: pci@0000:00:08.0 + version: 00 + width: 64 bits + clock: 33MHz + capabilities: bus_master cap_list + configuration: driver=virtio-pci latency=0 + resources: irq:45 ioport:10e0(size=32) memory:10064000-10064fff memory:1005c000-1005ffff + *-virtio4 UNCLAIMED + description: Virtual I/O device + physical id: 0 + bus info: virtio@4 + configuration: driver=virtio_rng + *-pnp00:00 + product: PnP device PNP0c02 + physical id: 5 + capabilities: pnp + configuration: driver=system + *-scsi + physical id: 6 + bus info: usb@1:4.1 + logical name: scsi0 + capabilities: emulated scsi-host + configuration: driver=usb-storage + *-cdrom + description: DVD reader + product: QEMU CD-ROM + vendor: QEMU + physical id: 0.0.0 + bus info: scsi@0:0.0.0 + logical name: /dev/cdrom + logical name: /dev/sr0 + version: 2.5+ + capabilities: removable audio dvd + configuration: ansiversion=5 status=nodisc + *-input:0 + product: Power Button + physical id: 1 + logical name: input0 + logical name: /dev/input/event0 + capabilities: platform + *-input:1 + product: QEMU QEMU USB Tablet + physical id: 2 + logical name: input1 + logical name: /dev/input/event1 + logical name: /dev/input/mouse0 + capabilities: usb + *-input:2 + product: QEMU QEMU USB Mouse + physical id: 3 + logical name: input2 + logical name: /dev/input/event2 + logical name: /dev/input/mouse1 + capabilities: usb + *-input:3 + product: QEMU QEMU USB Keyboard + physical id: 4 + logical name: input3 + logical name: /dev/input/event3 + logical name: input3::capslock + logical name: input3::compose + logical name: input3::kana + logical name: input3::numlock + logical name: input3::scrolllock + capabilities: usb + *-input:4 + product: spice vdagent tablet + physical id: 5 + logical name: input6 + logical name: /dev/input/event4 + logical name: /dev/input/js0 + logical name: /dev/input/mouse2 +WARNING: output may be incomplete or inaccurate, you should run this program as super-user. +arina_os@arinaos:~$ systemd-detect-virt +qemu +``` + +#### Reflection on the most useful tools: +`lscpu` gives CPU architecture, core count, vendor, and security status in one clean output, which is faster than parsing `/proc/cpuinfo`. + +`free -h` shows total and available RAM in human-readable form compared to `/proc/meminfo`. + +`lsblk` displays disk partitions in a tree format. It clearly shows the 64GB disk split into EFI, boot, and LVM volumes—information hard to get from `df` alone. + +`ip a` quickly lists network interfaces and IP addresses. It confirmed the active interface `enp0s1` with IP `192.168.64.2` on a DHCP network. + +`hostnamectl` replaces multiple commands by showing OS version, kernel, and virtualization type all at once. \ No newline at end of file diff --git a/labs/submission6.md b/labs/submission6.md new file mode 100644 index 000000000..2305bbad8 --- /dev/null +++ b/labs/submission6.md @@ -0,0 +1,285 @@ +# Lab 6 Submission +## Task 1: Container Lifecycle & Image Management +#### Code output: +``` +arinapetuhova@MacBook-Air-Arina ~ % docker ps -a +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +arinapetuhova@MacBook-Air-Arina ~ % docker pull ubuntu:latest +docker images ubuntu +latest: Pulling from library/ubuntu +66a4bbbfab88: Pull complete +Digest: sha256:d1e2e92c075e5ca139d51a140fff46f84315c0fdce203eab2807c7e495eff4f9 +Status: Downloaded newer image for ubuntu:latest +docker.io/library/ubuntu:latest +REPOSITORY TAG IMAGE ID CREATED SIZE +ubuntu latest d1e2e92c075e 4 weeks ago 139MB +arinapetuhova@MacBook-Air-Arina ~ % docker run -it --name ubuntu_container ubuntu:latest +root@e7eb710e4e78:/# 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 +HOME_URL="https://www.ubuntu.com/" +SUPPORT_URL="https://help.ubuntu.com/" +BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" +PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" +UBUNTU_CODENAME=noble +LOGO=ubuntu-logo +root@e7eb710e4e78:/# ps aux +USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND +root 1 0.0 0.0 4296 3612 pts/0 Ss 12:51 0:00 /bin/bash +root 10 0.0 0.0 7628 3532 pts/0 R+ 12:52 0:00 ps aux +root@e7eb710e4e78:/# exit +exit +arinapetuhova@MacBook-Air-Arina ~ % docker save -o ubuntu_image.tar ubuntu:latest +ls -lh ubuntu_image.tar + +-rw-------@ 1 arinapetuhova staff 28M 11 марта 15:52 ubuntu_image.tar +arinapetuhova@MacBook-Air-Arina ~ % docker rmi ubuntu:latest +Error response from daemon: conflict: unable to delete ubuntu:latest (must be forced) - container e7eb710e4e78 is using its referenced image d1e2e92c075e +arinapetuhova@MacBook-Air-Arina ~ % docker rm ubuntu_container +docker rmi ubuntu:latest +ubuntu_container +Untagged: ubuntu:latest +Deleted: sha256:d1e2e92c075e5ca139d51a140fff46f84315c0fdce203eab2807c7e495eff4f9 +``` + +#### Image size and layer count: +Image size: 139MB +Layer count: 1 layer + +#### Tar file size comparison with image size: +The tar file size = 28MB is significantly smaller than the image size = 139MB because the tar file is compressed. + +#### Error message analysis: +Container was still referencing the ubuntu:latest image, but to remove an image, Docker requires all dependent containers to be removed first. + +It happens because containers depend on images they were created from. As a safety mechanism, Docker prevents image deletion while its containers exist to avoid orphaned containers that can't be restarted, loss of container configuration/state, and potential data loss. + +#### What is included in the exported tar file? +The `docker save` command exports a complete, portable archive of the Docker image containing all image layers, the complete filesystem (including all files, libraries, and binaries), image metadata (configuration, environment variables, ports), and JSON data with layer relationships and manifest information. This compressed tar file can be transferred to another system, loaded back into Docker using `docker load`, or used to recreate the exact same image. Docker automatically compresses the layers during export, making the archive efficient for storage and transfer. + +## Task 2: Custom Image Creation & Analysis +#### Code output (output of original Nginx welcome page, custom HTML content, and verification via curl): +``` +arinapetuhova@MacBook-Air-Arina ~ % docker run -d -p 80:80 --name nginx_container nginx +curl http://localhost +Unable to find image 'nginx:latest' locally +latest: Pulling from library/nginx +a87363d30ab0: Pull complete +d456cad1d0ff: Pull complete +fbeac1abb084: Pull complete +fca7a914ec95: Pull complete +7e3a4af256ee: Pull complete +3b66ab8c894c: Pull complete +2e1e80a9149a: Pull complete +Digest: sha256:bc45d248c4e1d1709321de61566eb2b64d4f0e32765239d66573666be7f13349 +Status: Downloaded newer image for nginx:latest +d1271e43c760bc1adc5b54c2456681dbb5e07f32b867b91e0490082e6daa97c5 + + + +Welcome to nginx! + + + +

Welcome to nginx!

+

If you see this page, nginx is successfully installed and working. +Further configuration is required for the web server, reverse proxy, +API gateway, load balancer, content cache, or other features.

+ +

For online documentation and support please refer to +nginx.org.
+To engage with the community please visit +community.nginx.org.
+For enterprise grade support, professional services, additional +security features and capabilities please refer to +f5.com/nginx.

+ +

Thank you for using nginx.

+ + +arinapetuhova@MacBook-Air-Arina ~ % nano index.html +arinapetuhova@MacBook-Air-Arina ~ % docker cp index.html nginx_container:/usr/share/nginx/html/ +curl http://localhost +Successfully copied 2.05kB to nginx_container:/usr/share/nginx/html/ + + +The best + + +

website

+ + + +arinapetuhova@MacBook-Air-Arina ~ % docker commit nginx_container my_website:latest +sha256:679643c1abd13a4a49d3dfc9e80c764136ed10e86ab155c520d13b8a3ef27e2c +arinapetuhova@MacBook-Air-Arina ~ % docker images my_website +REPOSITORY TAG IMAGE ID CREATED SIZE +my_website latest 679643c1abd1 16 seconds ago 255MB +arinapetuhova@MacBook-Air-Arina ~ % docker rm -f nginx_container +nginx_container +arinapetuhova@MacBook-Air-Arina ~ % docker run -d -p 80:80 --name my_website_container my_website:latest +a351439a820c2221792ef128d36192bc263dcf4f24e9faed6bbe80fa4d3595f5 +arinapetuhova@MacBook-Air-Arina ~ % curl http://localhost + + +The best + + +

website

+ + +``` + +#### Output of `docker diff my_website_container`: +``` +arinapetuhova@MacBook-Air-Arina ~ % docker diff my_website_container +C /run +C /run/nginx.pid +C /etc +C /etc/nginx +C /etc/nginx/conf.d +C /etc/nginx/conf.d/default.conf +``` + +#### Analysis of Docker Diff Output: +The docker diff output shows only changed files and directories, with no added or deleted entries. The changes cascade through the directory structure, starting from `/run` and `/etc` down to specific files. The key modifications are the creation of `/run/nginx.pid` (which stores the running process ID) and changes to `/etc/nginx/conf.d/default.conf` (the Nginx configuration file). These changes occur because when the container starts, Nginx creates its PID file and potentially modifies its default configuration. Notably, the custom `index.html` file doesn't appear in the diff because I modified it in the original container before committing, and the diff shows only changes made after the container started from the committed image. + +#### Reflection: +Docker commit offers the advantage of quickly creating an image from a running container, which is useful for debugging, testing, or capturing a one-off state without writing a Dockerfile. However, it has significant disadvantages: it creates a "black box" image where the build process isn't documented, makes it difficult to recreate the image consistently, and typically results in larger image sizes since it includes all temporary files and history. Dockerfile approaches provide reproducibility, clear documentation of each step, smaller images through layer caching, and easier version control integration. The main disadvantage is the initial learning curve and the need to rebuild the image when making changes. For production environments, Dockerfiles are strongly preferred, while docker commit remains useful for quick experiments and emergency debugging of running containers. + +## Task 3: Container Networking & Service Discovery +#### Output of ping command: +``` +arinapetuhova@MacBook-Air-Arina ~ % 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=0.157 ms +64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.234 ms +64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.249 ms + +--- container2 ping statistics --- +3 packets transmitted, 3 packets received, 0% packet loss +round-trip min/avg/max = 0.157/0.213/0.249 ms +``` + +#### Network inspection output: +``` +arinapetuhova@MacBook-Air-Arina ~ % docker network inspect lab_network +[ + { + "Name": "lab_network", + "Id": "87a819d2ac78421d45f162c264fa9008db45e731b9ceca6b0dee88853bff1adc", + "Created": "2026-03-11T13:30:56.8214693Z", + "Scope": "local", + "Driver": "bridge", + "EnableIPv4": true, + "EnableIPv6": false, + "IPAM": { + "Driver": "default", + "Options": {}, + "Config": [ + { + "Subnet": "172.18.0.0/16", + "Gateway": "172.18.0.1" + } + ] + }, + "Internal": false, + "Attachable": false, + "Ingress": false, + "ConfigFrom": { + "Network": "" + }, + "ConfigOnly": false, + "Containers": { + "66c785c8a4da27d3f0368bb6c508ee2e42e9334a2429ebbd2d7e626c66b8a8c7": { + "Name": "container2", + "EndpointID": "fd389e0f26450a6094577809036f8d85d41b147aad60f89c1c1550ecf739ca67", + "MacAddress": "ea:fd:1a:0d:53:a3", + "IPv4Address": "172.18.0.3/16", + "IPv6Address": "" + }, + "eb89be9745dcf0331851f43e8c1546cb6853dd4ab1d42e59774fa10fefde83f4": { + "Name": "container1", + "EndpointID": "e63cc851ae31a1d972cd16d6ce1407232fd6dc0fcf6a5f1e88538c1afe896d9c", + "MacAddress": "da:9e:28:3e:38:1b", + "IPv4Address": "172.18.0.2/16", + "IPv6Address": "" + } + }, + "Options": {}, + "Labels": {} + } +] +``` + +#### DNS resolution output: +``` +arinapetuhova@MacBook-Air-Arina ~ % docker exec container1 nslookup container2 +Server: 127.0.0.11 +Address: 127.0.0.11:53 + +Non-authoritative answer: + +Non-authoritative answer: +Name: container2 +Address: 172.18.0.3 +``` + +#### Analysis: +Docker's internal DNS server (running at `127.0.0.11` inside containers) automatically resolves container names to IP addresses on user-defined networks. As shown in the `nslookup` output, when container1 queries "container2", the DNS server returns the IP address 172.18.0.3, exactly matching the IPv4 address shown in the network inspection. This allows containers to communicate using friendly names rather than hard-to-remember IP addresses. The DNS resolution works because Docker maintains a real-time mapping of container names to their assigned IP addresses on each user-defined network, and automatically injects this DNS configuration into containers, as evidenced by the successful ping using the name "container2" rather than its IP address. + +#### Comparison: +User-defined bridge networks provide the following advantages over the default bridge network: + + - Containers on a user-defined network can find each other by name automatically (like "container2"). On the default bridge, containers must use IP addresses to communicate, unless you use the old --link flag; + - A user-defined network creates a private space where only containers you specifically add can talk to each other. On the default bridge, every container on your system can potentially connect unless you manually prevent it. + - You can connect or disconnect containers from a user-defined network anytime without restarting them. Containers can also join multiple networks at once, allowing more flexible setups; + - You can choose your own IP address range for the network, giving you more control over how IP addresses are assigned to containers. + +## Task 4: Data Persistence with Volumes +#### Custom HTML content used (`index.html`): +``` +

Persistent Data

+``` + +#### Output of curl showing content persists after container recreation: +``` +arinapetuhova@MacBook-Air-Arina ~ % docker stop web && docker rm web +web +web +arinapetuhova@MacBook-Air-Arina ~ % docker run -d -p 80:80 -v app_data:/usr/share/nginx/html --name web_new nginx +8b3234e768ffd76ddb49b173f48c76f3a984cdcbc089ca716949eea69906397f +arinapetuhova@MacBook-Air-Arina ~ % curl http://localhost +

Persistent Data

+``` + +#### Volume inspection output: +``` +arinapetuhova@MacBook-Air-Arina ~ % docker volume inspect app_data +[ + { + "CreatedAt": "2026-03-11T13:43:42Z", + "Driver": "local", + "Labels": null, + "Mountpoint": "/var/lib/docker/volumes/app_data/_data", + "Name": "app_data", + "Options": null, + "Scope": "local" + } +] +``` + +#### Analysis: +Data persistence is important because containers are temporary - they can be stopped, removed, or recreated at any time, and without persistence, all data inside them disappears forever. As shown above, even after completely removing the original container (`web`) and starting a new one (`web_new`), the custom HTML content remained accessible because it was stored in a volume. This matters for real applications where you can't afford to lose databases, user uploads, or configuration files every time you update or restart a container. + +#### Comparison: +Container storage is temporary and dies with the container (it's the default but unsuitable for important data). Volumes are managed by Docker (stored in `/var/lib/docker/volumes/`) and outlive containers, making them perfect for databases and application data that must survive container recreations. Bind mounts map any folder from your host computer into the container, ideal for development because you can edit files on your host and see changes immediately inside the container. Use volumes for production data you want Docker to manage, bind mounts for development and live code updates, and container storage only for temporary files that don't need to survive. \ No newline at end of file diff --git a/labs/submission7.md b/labs/submission7.md new file mode 100644 index 000000000..990bddb69 --- /dev/null +++ b/labs/submission7.md @@ -0,0 +1,164 @@ +# Lab 7 Submission +## Task 1: Git State Reconciliation +#### Initial desired-state.txt and current-state.txt contents: +``` +arinapetuhova@MacBook-Air-Arina ~ % echo "version: 1.0" > desired-state.txt +echo "app: myapp" >> desired-state.txt +echo "replicas: 3" >> desired-state.txt +arinapetuhova@MacBook-Air-Arina ~ % cp desired-state.txt current-state.txt +arinapetuhova@MacBook-Air-Arina ~ % echo "version: 2.0" > current-state.txt +arinapetuhova@MacBook-Air-Arina ~ % echo "app: myapp" >> current-state.txt +arinapetuhova@MacBook-Air-Arina ~ % echo "replicas: 5" >> current-state.txt +``` + +#### Output of drift detection and reconciliation: +``` +arinapetuhova@MacBook-Air-Arina ~ % ./reconcile.sh +суббота, 14 марта 2026 г. 13:33:01 (MSK) - ⚠️ DRIFT DETECTED! +Reconciling current state with desired state... +суббота, 14 марта 2026 г. 13:33:01 (MSK) - ✅ Reconciliation complete +``` + +#### Output showing synchronized state after reconciliation: +``` +arinapetuhova@MacBook-Air-Arina ~ % diff desired-state.txt current-state.txt +arinapetuhova@MacBook-Air-Arina ~ % cat current-state.txt +version: 1.0 +app: myapp +replicas: 3 +``` + +#### Output from continuous reconciliation loop detecting auto-healing: +``` +arinapetuhova@MacBook-Air-Arina ~ % watch -n 5 ./reconcile.sh + + + + 8:35 ⚠️ DRIFT DETECTED! +Reconciling current state with desired state... +суббота, 14 марта 2026 г. 13:38:35 (MSK) - ✅ Reconciliation complete + +arinapetuhova@MacBook-Air-Arina ~ % watch -n 5 ./reconcile.sh + + + + 8:45 ✅ States synchronized +``` + +#### Analysis: +The GitOps reconciliation loop works by continuously comparing the desired state (in Git/desired-state.txt) with the actual current state (in the cluster/current-state.txt). As shown in the output, when I manually changed current-state.txt to have version 2.0 and replicas 5, the reconcile.sh script immediately detected this drift at 13:33:01 and automatically copied the desired state back to current state. This prevents configuration drift by constantly enforcing that the actual system always matches the declared configuration in Git, automatically fixing any manual changes or unexpected modifications within seconds. + +#### Reflection: +Declarative configuration is better for production because you simply describe what you want (like "replicas: 3") instead of typing specific commands to make changes. As shown in the output, when I used imperative commands to manually change the state to version 2.0 and replicas 5, the declarative approach automatically detected this and reverted it back to the correct version 1.0 with replicas 3. This makes production systems more reliable, self-healing, and easier to manage because you never have to remember what commands were run - you just look at the declarative config files to know exactly what your system should look like. + +## Task 2: GitOps Health Monitoring +#### Contents of healthcheck.sh script: +``` +#!/bin/bash +# healthcheck.sh - Monitor GitOps sync health + +DESIRED_MD5=$(md5 -q desired-state.txt) +CURRENT_MD5=$(md5 -q current-state.txt) + +if [ "$DESIRED_MD5" != "$CURRENT_MD5" ]; then + echo "$(date) - ❌ CRITICAL: State mismatch detected!" | tee -a health.log + echo " Desired MD5: $DESIRED_MD5" | tee -a health.log + echo " Current MD5: $CURRENT_MD5" | tee -a health.log +else + echo "$(date) - ✅ OK: States synchronized" | tee -a health.log +fi +``` + +#### Output showing "OK" status when states match: +``` +arinapetuhova@MacBook-Air-Arina ~ % ./healthcheck.sh +cat health.log +суббота, 14 марта 2026 г. 13:48:43 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:48:43 (MSK) - ✅ OK: States synchronized +``` + +#### Output showing "CRITICAL" status when drift is detected: +``` +arinapetuhova@MacBook-Air-Arina ~ % echo "unapproved-change: true" >> current-state.txt +arinapetuhova@MacBook-Air-Arina ~ % ./healthcheck.sh +cat health.log +суббота, 14 марта 2026 г. 13:48:55 (MSK) - ❌ CRITICAL: State mismatch detected! + Desired MD5: a15a1a4f965ecd8f9e23a33a6b543155 + Current MD5: 48168ff3ab5ffc0214e81c7e2ee356f5 +суббота, 14 марта 2026 г. 13:48:43 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:48:55 (MSK) - ❌ CRITICAL: State mismatch detected! + Desired MD5: a15a1a4f965ecd8f9e23a33a6b543155 + Current MD5: 48168ff3ab5ffc0214e81c7e2ee356f5 +``` + +#### Complete health.log file showing multiple checks: +``` +arinapetuhova@MacBook-Air-Arina ~ % cat health.log +суббота, 14 марта 2026 г. 13:48:43 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:48:55 (MSK) - ❌ CRITICAL: State mismatch detected! + Desired MD5: a15a1a4f965ecd8f9e23a33a6b543155 + Current MD5: 48168ff3ab5ffc0214e81c7e2ee356f5 +суббота, 14 марта 2026 г. 13:49:04 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:02 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:05 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:08 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:12 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:15 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:18 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:21 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:24 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:27 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:30 (MSK) - ✅ OK: States synchronized +``` + +#### Output from monitor.sh showing continuous monitoring: +``` +arinapetuhova@MacBook-Air-Arina ~ % ./monitor.sh +Starting GitOps monitoring... + +--- Check #1 --- +суббота, 14 марта 2026 г. 13:50:02 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:02 (MSK) - ✅ States synchronized + +--- Check #2 --- +суббота, 14 марта 2026 г. 13:50:05 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:05 (MSK) - ✅ States synchronized + +--- Check #3 --- +суббота, 14 марта 2026 г. 13:50:08 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:09 (MSK) - ✅ States synchronized + +--- Check #4 --- +суббота, 14 марта 2026 г. 13:50:12 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:12 (MSK) - ✅ States synchronized + +--- Check #5 --- +суббота, 14 марта 2026 г. 13:50:15 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:15 (MSK) - ✅ States synchronized + +--- Check #6 --- +суббота, 14 марта 2026 г. 13:50:18 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:18 (MSK) - ✅ States synchronized + +--- Check #7 --- +суббота, 14 марта 2026 г. 13:50:21 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:21 (MSK) - ✅ States synchronized + +--- Check #8 --- +суббота, 14 марта 2026 г. 13:50:24 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:24 (MSK) - ✅ States synchronized + +--- Check #9 --- +суббота, 14 марта 2026 г. 13:50:27 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:27 (MSK) - ✅ States synchronized + +--- Check #10 --- +суббота, 14 марта 2026 г. 13:50:30 (MSK) - ✅ OK: States synchronized +суббота, 14 марта 2026 г. 13:50:30 (MSK) - ✅ States synchronized +``` + +#### Analysis: +Checksums like MD5 act like a digital fingerprint for files. When you run the `md5` command on `desired-state.txt` and `current-state.txt,` it creates unique hash values based on the exact content inside each file. If someone adds, removes, or changes even one character in a file, the MD5 hash completely changes. In my output, when I added "unapproved-change: true" to `current-state.txt`, its MD5 hash changed from `a15a1a4f...` to `48168ff3...`, which immediately told the healthcheck script that something was wrong without having to compare the actual text line by line. + +#### Comparison: +This is exactly how ArgoCD and other GitOps tools monitor sync status in production. In my output, `healthcheck.sh` comparing MD5 hashes is like ArgoCD comparing what's in Git (`desired-state.txt`) against what's running in Kubernetes (`current-state.txt`). When my script showed "❌ CRITICAL: State mismatch detected!", that's the same as ArgoCD showing "Out of Sync" status. And when it later showed "✅ OK: States synchronized", that's ArgoCD's "Synced" status. The `health.log` file acts like ArgoCD's history of sync status changes over time. \ No newline at end of file diff --git a/labs/submission8.md b/labs/submission8.md new file mode 100644 index 000000000..02ac52d4a --- /dev/null +++ b/labs/submission8.md @@ -0,0 +1,179 @@ +# Lab 8 Submission +## Task 1: Key Metrics for SRE and System Analysis +#### Top 3 most consuming applications for CPU (with screenshot output): +1. **spice-vdagent (PID 2876) - 101.3% CPU:** VM integration agent for UTM. Handles clipboard sharing, mouse integration, display optimization + +2. **unattended-upgrade (PID 3864) - 31.3% CPU:** System automatic update process. Currently installing/checking for updates. + +3. **unattended-upgrade (PID 15641) - 12.7% CPU:** Secondary unattended-upgrade process. Multiple processes handling different update tasks + +![CPU based](screenshots/cpu_based.png) + +#### Top 3 most consuming applications for memory (with screenshot output): +1. **gnome-shell (PID 2741, 2756, 2757, etc.) - 10.2% Memory (each):** The multiple entries with identical 10.2% memory usage are threads of the same gnome-shell process. This is the desktop environment/GUI. + +2. **unattended-upgrade (PID 3864, 3911) - 6.0% Memory:** Main system update process. This memory is used to load package information, maintain the package database in memory, and process update metadata during installation. + +3. **unattended-upgrade (PID 15641) - 3.9% Memory:** Secondary unattended-upgrade process (child/spawned process). Handles specific update subtasks while sharing some memory with the parent. + +![Memory based](screenshots/mem_based.png) + +#### Top 3 most consuming applications for I/O usage (with screenshot output): +According to the screenshot, there were no applications that used I/O at that moment. It is related to the fact that the system was in an idle state with minimal disk reads/writes. + +![I/O based](screenshots/io_based.png) + +#### Top 3 largest files in the /var directory: +**Disk Usage:** +``` +arina_os@arinaos:~$ df -h +du -h /var | sort -rh | head -n 10 +Filesystem Size Used Avail Use% Mounted on +tmpfs 391M 1.9M 389M 1% /run +efivarfs 256K 28K 229K 11% /sys/firmware/efi/efivars +/dev/mapper/ubuntu--vg-ubuntu--lv 30G 16G 14G 54% / +tmpfs 2.0G 0 2.0G 0% /dev/shm +tmpfs 5.0M 8.0K 5.0M 1% /run/lock +/dev/vda2 2.0G 301M 1.5G 17% /boot +/dev/vda1 1.1G 6.4M 1.1G 1% /boot/efi +tmpfs 391M 124K 391M 1% /run/user/1000 +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-systemd-timedated.service-74QJ1H': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-fwupd.service-b5b30H': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-systemd-logind.service-lTrpfj': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-polkit.service-BUAjK2': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-ModemManager.service-lljQyn': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-systemd-oomd.service-Wa6GdZ': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-spice-vdagentd.service-RKW5iw': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-switcheroo-control.service-GvvDxm': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-systemd-timesyncd.service-VmrsCU': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-power-profiles-daemon.service-k7RLRE': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-upower.service-WE2VSP': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-systemd-resolved.service-eQ6WP7': Permission denied +du: cannot read directory '/var/tmp/systemd-private-6e9bf392836c4dc383e3648ba1e4cd56-colord.service-cKUrqG': Permission denied +du: cannot read directory '/var/lib/bluetooth': Permission denied +du: cannot read directory '/var/lib/gdm3': Permission denied +du: cannot read directory '/var/lib/saned': Permission denied +du: cannot read directory '/var/lib/private': Permission denied +du: cannot read directory '/var/lib/openvpn/chroot': Permission denied +du: cannot read directory '/var/lib/colord/.cache': Permission denied +du: cannot read directory '/var/lib/AccountsService/users': Permission denied +du: cannot read directory '/var/lib/fprint': Permission denied +du: cannot read directory '/var/lib/polkit-1': Permission denied +du: cannot read directory '/var/lib/gnome-remote-desktop': Permission denied +du: cannot read directory '/var/lib/NetworkManager': Permission denied +du: cannot read directory '/var/lib/update-notifier/package-data-downloads/partial': Permission denied +du: cannot read directory '/var/lib/snapd/cookie': Permission denied +du: cannot read directory '/var/lib/snapd/void': Permission denied +du: cannot read directory '/var/lib/snapd/cache': Permission denied +du: cannot read directory '/var/lib/apt/lists/partial': Permission denied +du: cannot read directory '/var/lib/fwupd/gnupg': Permission denied +du: cannot read directory '/var/lib/ubuntu-advantage/apt-esm/var/lib/apt/lists/partial': Permission denied +du: cannot read directory '/var/lib/ubuntu-advantage/apt-esm/var/cache/apt/archives/partial': Permission denied +du: cannot read directory '/var/lib/sss/db': Permission denied +du: cannot read directory '/var/lib/sss/pipes/private': Permission denied +du: cannot read directory '/var/lib/sss/deskprofile': Permission denied +du: cannot read directory '/var/lib/sss/keytabs': Permission denied +du: cannot read directory '/var/lib/sss/secrets': Permission denied +du: cannot read directory '/var/lib/udisks2': Permission denied +du: cannot read directory '/var/spool/cups': Permission denied +du: cannot read directory '/var/spool/cron/crontabs': Permission denied +du: cannot read directory '/var/spool/rsyslog': Permission denied +du: cannot read directory '/var/log/gdm3': Permission denied +du: cannot read directory '/var/log/private': Permission denied +du: cannot read directory '/var/log/speech-dispatcher': Permission denied +du: cannot read directory '/var/log/sssd': Permission denied +du: cannot read directory '/var/cache/cups': Permission denied +du: cannot read directory '/var/cache/private': Permission denied +du: cannot read directory '/var/cache/pollinate': Permission denied +du: cannot read directory '/var/cache/ldconfig': Permission denied +du: cannot read directory '/var/cache/apparmor/baad73a1.0': Permission denied +du: cannot read directory '/var/cache/apt/archives/partial': Permission denied +3.6G /var +2.1G /var/lib +1.7G /var/lib/snapd/snaps +1.7G /var/lib/snapd +1.3G /var/cache/apt +1.3G /var/cache +1.2G /var/cache/apt/archives +296M /var/log +292M /var/log/journal/d9d987f1ef9342639b1d58d683bcc891 +292M /var/log/journal +``` + +**Largest Files:** +``` +arina_os@arinaos:~$ sudo find /var -type f -exec du -h {} + | sort -rh | head -n 3 +[sudo] password for arina_os: +515M /var/cache/apt/archives/linux-firmware_20240318.git3b128b60-0ubuntu2.21_arm64.deb +484M /var/lib/snapd/snaps/gnome-42-2204_178.snap +248M /var/lib/snapd/cache/8afe31cd36ba23ac9938cbe26ba2d35b020e04d5b29232ffc92f2c655ee37acf3fd47aeb2d59af488c823500aedf6da1 +arina_os@arinaos:~$ +``` + +#### Analysis: +The automatic update process `unattended-upgrade` is using the most CPU and memory. Together, its two processes are taking up 44% of the CPU and about 10% of memory. The `GNOME desktop` is using a steady 10% of memory through its many threads. The `spice-vdagent` (which helps to run Linux VM on Mac) is using over 100% CPU, which means it's using more than one full CPU core, which seems really high. When it comes to disk space, the biggest files are all system packages and applications, with a Linux firmware file taking up 515MB and Snap packages filling up space in `/var/lib/snapd`. + +#### Reflection: +To optimize resource usage, I would first look into why `spice-vdagent` is using so much CPU and maybe turn off some features that I don't need. I would also schedule system updates to run at night when I'm not using the computer, so they don't slow things down during the day. To free up disk space, I would run `sudo apt clean` to delete the 1.2GB of old package files sitting in the cache. I would also set up automatic log cleanup so logs in `/var/log` don't keep growing forever, and put a size limit on Snap package cache so it doesn't fill up with big files I don't need. + +## Task 2: Practical Website Monitoring Setup +#### Website URL to monitor: +[RussianFood](https://www.russianfood.com) + +#### Screenshots of browser check configuration: +**Configuration code:** +``` +const { test, expect } = require('@playwright/test'); + +test('Russian Food Website Check', async ({ page }) => { + // Go to the website + await page.goto('https://www.russianfood.com'); + + // Log success + console.log('✅ Page loaded successfully'); + + // Get page title + const title = await page.title(); + console.log(`Page title: ${title}`); + + // Take a screenshot + await page.screenshot({ path: 'homepage.png' }); + + // Check if page has content + const bodyText = await page.textContent('body'); + + // Look for Russian text + const hasRussianText = bodyText.includes('рецепты') || + bodyText.includes('Рецепты') || + bodyText.includes('кулинар'); + + // Assert that the page contains Russian text + expect(hasRussianText).toBeTruthy(); + + console.log('✅ All checks passed'); +}); +``` + +![Browser configuration](screenshots/brows_conf1.png) +![Browser configuration](screenshots/brows_conf2.png) + +#### Screenshots of successful check results: +**API Check:** +![API Check](screenshots/api_check.png) + +**Browser Check:** +![Browser Check](screenshots/brows_check_out1.png) +![Browser Check](screenshots/brows_check_out2.png) +![Browser Check](screenshots/brows_check_out3.png) + +**Dashboard:** +![Dashboard](screenshots/dashboard.png) + +#### Screenshots of alert settings: +![Alert settings](screenshots/alerts.png) + +#### Analysis: +I chose this browser check to verify that the website actually loads and displays content in Russian since it's a Russian recipe site. The test checks for common Russian words to confirm that the page content is loading correctly, not just returning a blank page or error message. I set the check to take a screenshot for visual verification and included a simple pass/fail assertion - if the Russian text isn't found, the test fails and triggers an alert. This approach ensures the site is not just "up" but actually usable for its target audience. + +#### Reflection: +This monitoring setup helps maintain reliability by automatically catching content-related issues that basic uptime monitoring would miss. For example, if the site's database fails and pages load without recipe text, or if the site gets hacked and content is replaced, this check would immediately fail and make alert. The screenshot provides visual proof of what the page looked like when the check ran, which helps with debugging. Since this runs automatically every few minutes, there's no need to manually visit the site to know it's working correctly - all will be sent in alert notifications. \ No newline at end of file diff --git a/labs/submission9.md b/labs/submission9.md new file mode 100644 index 000000000..8047bab97 --- /dev/null +++ b/labs/submission9.md @@ -0,0 +1,74 @@ +# Lab 9 Submission +## Task 1: Web Application Scanning with OWASP ZAP +#### Number of Medium risk vulnerabilities found: +1. Content Security Policy (CSP) Header Not Set +2. Cross-Domain Misconfiguration + +#### Description of the 2 most interesting vulnerabilities: +1. Content Security Policy (CSP) Header Not Set (Medium) +This vulnerability means the web application does not have a Content Security Policy header configured. CSP is a critical security layer that helps prevent Cross-Site Scripting (XSS) and data injection attacks by telling the browser which sources of content are trusted to load on the page. Without it, the application is more vulnerable to malicious script injection, where attackers could potentially steal user data or deface the website. + +2. Cross-Domain Misconfiguration (Medium) +The scan found that the server has an overly permissive CORS (Cross-Origin Resource Sharing) policy with `Access-Control-Allow-Origin: *` configured. This means any website can make requests to this application and read the responses. While this is less risky for unauthenticated APIs, it could allow attackers to bypass IP whitelisting or access sensitive data that should be restricted to specific domains only. + +#### Security headers status (which are present/missing and why they matter): +**Missing Headers:** +- **Content-Security-Policy:** This header prevents XSS attacks by controlling which resources can load +- **Cross-Origin-Embedder-Policy** This prevents documents from loading cross-origin resources without permission +- **Cross-Origin-Opener-Policy** This isolates browsing contexts to prevent data leaks + +**Present but Problematic Headers:** +- **Access-Control-Allow-Origin:** Present but set to * (wildcard). This is too permissive and allows any domain to access resources +- **Feature-Policy:** Present but deprecated. Should be replaced with Permissions-Policy header + +**Why matters:** +These headers are essential for modern web security. CSP prevents malicious script execution, CORS controls cross-domain access, and COOP/COEP provide isolation against side-channel attacks. Missing them leaves the application vulnerable to common attacks like XSS, data theft, and cross-origin exploits. + +#### Screenshot of ZAP HTML report overview: +![ZAP HTML](screenshots/zap1.png) +![ZAP HTML](screenshots/zap2.png) +![ZAP HTML](screenshots/zap3.png) + +#### Analysis: +Based on the scan and general security trends, the most common vulnerabilities in web applications are: +1. **Security Misconfigurations:** Like missing CSP headers and permissive CORS policies, these are extremely common because they require manual configuration and are easy to overlook during development. +2. **Information Disclosure:** Timestamp disclosures and cacheable content (both found in the scan) are frequent issues where applications accidentally leak system information or sensitive data through headers or responses. +3. **Outdated or Deprecated Features:** Using deprecated headers like`Feature-Policy` instead of `Permissions-Policy` shows how applications often lag behind evolving security standards. +4. **Client-Side Vulnerabilities:** Dangerous JS functions (like `bypassSecurityTrustHtml`) found in this scan represent common risks where developers bypass security mechanisms for convenience. + +## Task 2: Container Vulnerability Scanning with Trivy +#### Total count of CRITICAL and HIGH vulnerabilities: +**CRITICAL:** 9 vulnerabilities + +**HIGH:** 44 vulnerabilities + + +#### List of 2 vulnerable packages with their CVE IDs: +1. **crypto-js (package.json) - CVE-2023-46233 (CRITICAL)** + +- Vulnerability: PBKDF2 is 1,000 times weaker than specified in 1993 and 1.3 million times weaker than current standards +- Installed version: 3.3.0 +- Fixed version: 4.2.0 + +2. **jsonwebtoken (package.json) - CVE-2015-9235 (CRITICAL)** + +- Vulnerability: Verification step can be bypassed with an altered token +- Installed version: 0.1.0 and 0.4.0 +- Fixed version: 4.2.2 + +#### Most common vulnerability type found: +The most common vulnerability type found is **Denial of Service (DoS) and Path Traversal issues**, particularly in packages like `multer`, `tar`, and `minimatch`. These vulnerabilities allow attackers to crash the application, overwrite files, or access sensitive data through maliciously crafted requests or archive files. + +#### Screenshot of Trivy terminal output showing critical findings: +![ZAP HTML](screenshots/trivy1.png) +![ZAP HTML](screenshots/trivy2.png) +![ZAP HTML](screenshots/trivy3.png) +![ZAP HTML](screenshots/trivy4.png) +![ZAP HTML](screenshots/trivy5.png) +![ZAP HTML](screenshots/trivy6.png) + +#### Analysis: +Container image scanning is important because it finds security problems in your application before they go live. This scan found 53 critical and high vulnerabilities, including issues that could let attackers bypass login systems or crash the application. If these problems make it to production, hackers could steal data or take down your website. Scanning catches these issues early when they're easy and cheap to fix, rather than after deployment when they could cause real damage to your users and business. + +#### Reflection: +I would add Trivy scanning at two key points in the pipeline. First, on every pull request, I'd run a scan and fail the build if critical vulnerabilities are found, this prevents bad code from ever being merged. Second, right after building the container image, I'd scan it again and block it from being pushed to the registry if it has high-risk issues. This creates a security gate that automatically stops vulnerable images from reaching production, without needing manual checks. The whole process runs automatically every time code changes, keeping security simple and consistent. \ No newline at end of file diff --git a/test.txt b/test.txt new file mode 100644 index 000000000..2eec599a1 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +Test content