<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://syarif.kosasih.my.id</link><generator>RSS for Node</generator><lastBuildDate>Tue, 15 Sep 2026 06:20:24 GMT</lastBuildDate><atom:link href="https://syarif.kosasih.my.id/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[connect Amavis to an external ClamAV daemon using TCP]]></title><description><![CDATA[To connect Amavis to an external ClamAV daemon using TCP, update your Amavis configuration (typically in /etc/amavis/conf.d/50-user or /etc/amavisd/amavisd.conf).
1. Update @av_scanners Configuration
]]></description><link>https://syarif.kosasih.my.id/connect-amavis-to-an-external-clamav-daemon-using-tcp</link><guid isPermaLink="true">https://syarif.kosasih.my.id/connect-amavis-to-an-external-clamav-daemon-using-tcp</guid><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Sun, 30 Aug 2026 19:33:13 GMT</pubDate><content:encoded><![CDATA[<p>To connect Amavis to an external ClamAV daemon using TCP, update your Amavis configuration (typically in <code>/etc/amavis/conf.d/50-user</code> or <code>/etc/amavisd/amavisd.conf</code>).</p>
<h3>1. Update <code>@av_scanners</code> Configuration</h3>
<p>Replace or update your <code>@av_scanners</code> array with the following syntax:<br />@av_scanners = ( ['ClamAV-clamd', &amp;ask_daemon, ["{}/<em>", "clamd:CLAMAV_HOST:3310"], qr/\bOK\(/m, qr/\bFOUND\)/m, qr/^.</em>?: (?!Infected Archive)(.*) FOUND$/m ], );</p>
<p>Replace CLAMAV_HOST with your ClamAV container/server hostname or IP address.</p>
<ol>
<li>Crucial Syntax Rules clamd: scheme prefix: Required so ask_daemon matches the protocol to clamav_clamd_internal. Using tcp: or clamav: will cause Unsupported AV protocol name errors.</li>
</ol>
<p>"{}/*" placeholder: Passes individual extracted MIME files. Using "{}" passes the directory path, causing Is a directory errors during TCP streaming (zINSTREAM).</p>
<p>Single string endpoint: Formatted as "clamd:HOST:PORT". Passing an array reference like ["HOST", 3310] causes Amavis to misinterpret the host as a local UNIX socket.</p>
<ol>
<li>Restart and Test Restart the Amavis service or container to reload the configuration:</li>
</ol>
<p>Bash systemctl restart amavis Inject the EICAR test string to verify the scan:</p>
<p>Bash printf "X5O!P%%@AP[4\PZX54(P^)7CC)7}\(EICAR-STANDARD-ANTIVIRUS-TEST-FILE!\)H+H*" | sendmail <a href="mailto:postmaster@yourdomain.com">postmaster@yourdomain.com</a> Check your mail log for a successful block:</p>
<p>Plaintext amavis[...]: (...) Blocked INFECTED (Eicar-Signature) ...</p>
]]></content:encoded></item><item><title><![CDATA[Running the Traefik 3 Hardened Image (nonroot) on Podman: 3 Problems and Their Fixes]]></title><description><![CDATA[Docker Hardened Images (DHI) give you production-ready images with a small attack surface: no shell, no package manager, and — this is the part that confuses people the most — they run as a nonroot us]]></description><link>https://syarif.kosasih.my.id/running-the-traefik-3-hardened-image-nonroot-on-podman-3-problems-and-their-fixes</link><guid isPermaLink="true">https://syarif.kosasih.my.id/running-the-traefik-3-hardened-image-nonroot-on-podman-3-problems-and-their-fixes</guid><category><![CDATA[Docker]]></category><category><![CDATA[podman]]></category><category><![CDATA[Traefik]]></category><category><![CDATA[Security]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Thu, 06 Aug 2026 03:01:01 GMT</pubDate><content:encoded><![CDATA[<p>Docker Hardened Images (DHI) give you production-ready images with a small attack surface: no shell, no package manager, and — this is the part that confuses people the most — <strong>they run as a nonroot user (UID 65532) by default</strong>. This is great for security. But if you switch your old image to <code>dhi.io/traefik:3-alpine</code> without any changes, you will almost certainly hit a few errors.</p>
<p>This article covers three problems I found while moving a Traefik reverse proxy to DHI on top of Podman (rootful), along with the root cause and the fix for each one.</p>
<h2>The starting setup</h2>
<p>A simple stack: Traefik as a reverse proxy plus a Cloudflare Tunnel, running on Podman with the socket mounted in place of the Docker socket:</p>
<pre><code class="language-plaintext">services:
  traefik:
    image: dhi.io/traefik:3-alpine
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.http.address=:8080"
      - "--entrypoints.https.address=:8443"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http"
      - "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:8080"
      - "443:8443"
    volumes:
      - traefik_letsencrypt:/letsencrypt
      - "/run/podman/podman.sock:/var/run/docker.sock:ro,z"

  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}

volumes:
  traefik_letsencrypt:
</code></pre>
<p>This looks normal. But once you run <code>docker compose up</code>, three problems appear one after another.</p>
<h2>Problem 1: <code>listen tcp :8080: bind: address already in use</code></h2>
<p>The first instinct is usually: "a nonroot user can't bind to a privileged port." But look closely at the error message — it says <code>address already in use</code>, not <code>permission denied</code>. These are two different errors with two different causes.</p>
<p><strong>Root cause:</strong> <code>--api.insecure=true</code> without an explicit entrypoint makes Traefik automatically create an internal entrypoint called <code>traefik</code> for the dashboard. This entrypoint <strong>also defaults to</strong> <code>:8080</code>. If your config already sets another entrypoint to <code>:8080</code> too, both listeners try to bind the same port inside the same process.</p>
<p><strong>Fix:</strong> give the dashboard its own port, separate from the web entrypoint:</p>
<pre><code class="language-plaintext">command:
  - "--api.dashboard=true"
  - "--api.insecure=true"
  - "--entrypoints.http.address=:8080"
  - "--entrypoints.https.address=:8443"
  - "--entrypoints.traefik.address=:8081"   # dashboard, its own port
</code></pre>
<p>A quick note on privileged ports: on Docker Engine 20.10 and later, a nonroot user can actually still bind to ports below 1024. But on Kubernetes or older engines, you still need to use ports above 1024 inside the container (as shown above), then map them to 80/443 with <code>ports:</code>.</p>
<h2>Problem 2: <code>permission denied</code> when connecting to the Podman socket</h2>
<p>Once the port issue is fixed, the next error shows up:</p>
<pre><code class="language-plaintext">Failed to retrieve information of the docker client and server host
error="permission denied while trying to connect to the docker API
at unix:///var/run/docker.sock" providerName=docker
</code></pre>
<p><strong>Root cause:</strong> UID 65532 (nonroot) doesn't match the owner or group of <code>podman.sock</code> on the host, which is usually:</p>
<pre><code class="language-plaintext">root root 660
</code></pre>
<p>Since the DHI image has no shell, you can't run <code>chmod</code> or <code>chown</code> from inside the container. A few quick fixes exist — using an ACL, or changing the socket's group to GID 65532 — but they both have two downsides:</p>
<ol>
<li><p>Host permissions can reset every time the socket service restarts (you'd need a systemd override to make it permanent).</p>
</li>
<li><p>More importantly: giving direct socket access means giving Traefik <strong>full root-level access</strong> to the entire container engine on the host. If Traefik (which faces the public internet) gets compromised, the attacker gets full control over every container.</p>
</li>
</ol>
<h2>Problem 3: The real fix — a Docker/Podman Socket Proxy</h2>
<p>The correct solution for this combination — nonroot, hardened image, and a publicly-facing reverse proxy — is to <strong>not give Traefik socket access at all</strong>. Instead, put a dedicated proxy between Traefik and the socket, one that only allows the read-only endpoints actually needed for service discovery.</p>
<pre><code class="language-yaml">services:
  socket-proxy:
    image: lscr.io/linuxserver/socket-proxy:latest
    restart: unless-stopped
    environment:
      - CONTAINERS=1   # list containers (required for discovery)
      - NETWORKS=1     # resolve container networks (required for routing)
      - EVENTS=1       # live updates when containers start/stop
      # everything else stays at the default 0 (deny)
    volumes:
      - "/run/podman/podman.sock:/var/run/docker.sock:ro,z"
    networks:
      - socket-proxy-net

  traefik:
    image: dhi.io/traefik:3-alpine
    command:
      - "--api.dashboard=true"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.endpoint=tcp://socket-proxy:2375"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.http.address=:8080"
      - "--entrypoints.https.address=:8443"
      - "--entrypoints.traefik.address=:8081"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http"
      - "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:8080"
      - "443:8443"
    volumes:
      - traefik_letsencrypt:/letsencrypt
    networks:
      - socket-proxy-net
      - default
    depends_on:
      - socket-proxy

  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: unless-stopped
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
    networks:
      - default

networks:
  socket-proxy-net:
    internal: true
  default:

volumes:
  traefik_letsencrypt:
</code></pre>
<p>The <code>socket-proxy-net</code> network is marked <code>internal: true</code> so it stays fully isolated. Nothing outside this network can reach it, even if the socket-proxy port is accidentally exposed somewhere else.</p>
<h2>Why this approach is better</h2>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>Direct socket mount</th>
<th>Socket proxy</th>
</tr>
</thead>
<tbody><tr>
<td>Requires host permission changes</td>
<td>Yes (chmod/setfacl, breaks on restart)</td>
<td>No</td>
</tr>
<tr>
<td>Works with a nonroot image that has no shell</td>
<td>Needs a workaround</td>
<td>Works natively, no issues</td>
</tr>
<tr>
<td>API access if the container is compromised</td>
<td>Full read-write access to the whole engine</td>
<td>Read-only, limited to containers/networks/events</td>
</tr>
<tr>
<td>Label-based autodiscovery</td>
<td>Works</td>
<td>Still works, no changes needed</td>
</tr>
</tbody></table>
<p>That last point matters most: <strong>Traefik's label-based autodiscovery (</strong><code>traefik.enable=true</code><strong>, and so on) doesn't change at all.</strong> Traefik still uses the same <code>providers.docker</code> setup — only the endpoint now points to the proxy instead of the raw socket.</p>
<h2>Summary</h2>
<p>If you're moving Traefik to a hardened or nonroot image (or any production image that runs as nonroot) on top of Docker or Podman:</p>
<ol>
<li><p><strong>Don't assume a port error is always about privileges.</strong> Check the error message closely — <code>already in use</code> is not the same as <code>permission denied</code>, and each one has a different cause and a different fix.</p>
</li>
<li><p><strong>Give the dashboard/API its own entrypoint, separate from the web entrypoint</strong>, when using <code>api.insecure=true</code>. This avoids implicit port conflicts.</p>
</li>
<li><p><strong>Never mount the container engine socket directly into a publicly-facing reverse proxy.</strong> Use a socket proxy with the narrowest read-only permissions possible. This isn't just a workaround for the nonroot permission issue — it's good security practice regardless of which user your container runs as.</p>
</li>
</ol>
<blockquote>
<p>Note: the examples above use rootful Podman with the socket at <code>/run/podman/podman.sock</code>. If you're using regular Docker, change the socket path to <code>/var/run/docker.sock</code>.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Why I Didn’t Trust Bitcoin at First — Until I Found a Way to Solve Its Biggest Problem]]></title><description><![CDATA[Like many others, I wasn’t exactly against Bitcoin — but I had serious concerns. It wasn’t price volatility or market speculation that made me hesitant. My main worry was: what if I lose access to my wallet?
The Fear of Permanent Loss
Imagine this:

...]]></description><link>https://syarif.kosasih.my.id/why-i-didnt-trust-bitcoin-at-first-until-i-found-a-way-to-solve-its-biggest-problem</link><guid isPermaLink="true">https://syarif.kosasih.my.id/why-i-didnt-trust-bitcoin-at-first-until-i-found-a-way-to-solve-its-biggest-problem</guid><category><![CDATA[Bitcoin]]></category><category><![CDATA[Cryptocurrency]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[decentralization]]></category><category><![CDATA[crypto adoption]]></category><category><![CDATA[Digital currency]]></category><category><![CDATA[finance]]></category><category><![CDATA[multisig crypto wallet]]></category><category><![CDATA[shamir secret sharing]]></category><category><![CDATA[inheritance]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Thu, 19 Jun 2025 08:25:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750319701926/25b4753b-2edb-4b72-961f-2d33ab7a47da.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Like many others, I wasn’t exactly against Bitcoin — but I had serious concerns. It wasn’t price volatility or market speculation that made me hesitant. My main worry was: <em>what if I lose access to my wallet?</em></p>
<h2 id="heading-the-fear-of-permanent-loss">The Fear of Permanent Loss</h2>
<p>Imagine this:</p>
<ul>
<li><p>I forget my password</p>
</li>
<li><p>I misplace my recovery phrase</p>
</li>
<li><p>Someone steals it</p>
</li>
<li><p>I suffer from memory loss</p>
</li>
<li><p>Or worse — I pass away</p>
</li>
</ul>
<p>In any of these cases, my Bitcoin could be <em>gone forever</em>.</p>
<p>Years ago, when Bitcoin was still new, I couldn’t find a reliable way to deal with this. I remember reading about a man digging through a landfill for years, trying to recover a hard drive with lost Bitcoin worth millions. That could be anyone.</p>
<p>Then there’s the question of <strong>exchanges</strong>. Buying Bitcoin through an exchange might feel convenient, but what if the exchange goes bankrupt? Unlike traditional banks — which at least offer some legal means of recovery — there’s no such fallback with most crypto exchanges. If they disappear, so might your assets.</p>
<p>Unfortunately, many people I asked back then simply said, <em>"just accept the risk."</em><br />That wasn’t good enough for me.</p>
<h2 id="heading-how-i-found-a-better-way">How I Found a Better Way</h2>
<p>Fast forward to today — the world has changed, and so has crypto. But surprisingly, many people still don’t know how to prepare for worst-case scenarios like death or memory loss. That’s why I want to share the system I use today, which could also help othe<strong>rs.</strong></p>
<ul>
<li><p><strong>Everyday Usage: Multi-Signature Wallet</strong></p>
<p>  In a typical family structure — husband, wife, and two children — I use a <strong>2-of-3 multisig wallet</strong>. This means that any transaction must be approved by at least two people. This prevents a single point of failure and helps protect against misuse or accidents.</p>
</li>
<li><p><strong>Long-Term Inheritance: Shamir Backup</strong></p>
<p>  For legacy and inheritance, I use a <strong>Shamir Secret Sharing</strong> method with a <strong>6-of-9 setup</strong>. The wallet’s seed phrase is divided into 9 pieces. Any 6 of them can be combined to recover the wallet. The distribution looks like this:</p>
<ul>
<li><p><strong>Husband</strong>: 2 shares (kept in a bank safe deposit box)</p>
</li>
<li><p><strong>Wife</strong>: 2 shares (also in a separate safe deposit box)</p>
</li>
<li><p><strong>Child 1</strong>: 1 share</p>
</li>
<li><p><strong>Child 2</strong>: 1 share</p>
</li>
<li><p><strong>Husband Trusted Person</strong>: 1 share</p>
</li>
<li><p><strong>Wife trusted person</strong>: 1 share</p>
</li>
<li><p><strong>netral person / Lawyer</strong>: 1 share</p>
</li>
</ul>
</li>
</ul>
<p>This creates a balance of security, trust, and accessibility — even in the event of my death. With joining six share, my family can still recover the funds responsibly.</p>
<h2 id="heading-not-your-keys-not-your-coins">"Not Your Keys, Not Your Coins"</h2>
<p>I still don’t fully trust exchanges.<br />Crypto's golden rule remains:</p>
<blockquote>
<p>If you don’t own the keys, you don’t own the assets.</p>
</blockquote>
<p>Most exchanges keep your funds in wallets they control. Several years ago, an incident involving <strong>Indodax</strong>, one of Indonesia’s popular exchanges, reaffirmed my stance — exchanges are not safe places to store crypto long-term.</p>
<p>Sure, exchanges are necessary for buying and selling. But for <strong>storage</strong>, I <strong>always withdraw to my personal wallet</strong>.</p>
<h2 id="heading-choosing-an-exchange-wisely">Choosing an Exchange Wisely</h2>
<p>Exchanges differ wildly in fees — transaction fees, withdrawal fees, and even taxation policies. Some are rigid, some are fair. After trying several platforms, I found the most competitive (at least as of writing this article) to be:<br /><a target="_blank" href="https://reku.page.link/kw2XyGjGRD1B7YSu6">https://reku.id/</a></p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Owning Bitcoin is about freedom, but with freedom comes responsibility. It’s not just about investment or speculation — it’s about <strong>building a system that protects your assets</strong>, even when you’re no longer here.</p>
<p>I hope my approach can inspire others to take ownership of their crypto <strong>securely, responsibly, and wisely</strong>.</p>
<blockquote>
<p>In this article, I discuss my initial concerns about the security and accessibility of Bitcoin and how my approach has evolved over time. To mitigate risks like loss of access or inheritance issues, I use a 2-of-3 multi-signature wallet for everyday transactions and Shamir Secret Sharing for long-term inheritance planning. I emphasize the importance of owning your private keys to ensure control over your assets and recommend cautious use of exchanges for storage. The article aims to offer a practical framework for managing Bitcoin securely and responsibly.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[How to Create a Free Email Account with a Custom Domain Name in Zoho.com]]></title><description><![CDATA[Introduction: Having a professional email address that matches your domain name adds credibility and authenticity to your online presence. Zoho.com offers a free plan that allows you to create email accounts with your custom domain name. In this arti...]]></description><link>https://syarif.kosasih.my.id/how-to-create-a-free-email-account-with-a-custom-domain-name-in-zohocom</link><guid isPermaLink="true">https://syarif.kosasih.my.id/how-to-create-a-free-email-account-with-a-custom-domain-name-in-zohocom</guid><category><![CDATA[free]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Homelab]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:37:33 GMT</pubDate><content:encoded><![CDATA[<p>Introduction: Having a professional email address that matches your domain name adds credibility and authenticity to your online presence. <a target="_blank" href="http://Zoho.com">Zoho.com</a> offers a free plan that allows you to create email accounts with your custom domain name. In this article, we will guide you through the process of setting up a free email account using <a target="_blank" href="http://Zoho.com">Zoho.com</a>, enabling you to communicate professionally and effectively with your custom domain.</p>
<p>Step 1: Sign up for a <a target="_blank" href="http://Zoho.com">Zoho.com</a> Account Visit the <a target="_blank" href="http://Zoho.com">Zoho.com</a> website at <a target="_blank" href="https://www.zoho.com"><strong>https://www.zoho.com</strong></a> and sign up for a free account. Provide the required information, including your name, email address, and a secure password. Once registered, log in to your <a target="_blank" href="http://Zoho.com">Zoho.com</a> account.</p>
<p>Step 2: Verify Your Domain After logging in, <a target="_blank" href="http://Zoho.com">Zoho.com</a> will guide you through the process of verifying your domain ownership. Choose the "Verify Domain" option and follow the instructions provided. This typically involves adding a DNS TXT record or creating a CNAME record with your domain registrar.</p>
<p>Step 3: Add Email Accounts Once your domain is verified, you can add email accounts with your custom domain. In the <a target="_blank" href="http://Zoho.com">Zoho.com</a> dashboard, navigate to the "Mail" section and select "User Details." Click the "+ New User" button and enter the required details, such as the username and password for your email account.</p>
<p>Step 4: Configure Email Delivery To receive emails in your <a target="_blank" href="http://Zoho.com">Zoho.com</a> email account, you need to configure the email delivery settings. In the <a target="_blank" href="http://Zoho.com">Zoho.com</a> dashboard, go to the "Mail" section and select "Email Delivery" or "Control Panel." Follow the provided instructions to set up the necessary MX records with your domain registrar.</p>
<p>Step 5: Access Your Email Account Once the MX records are set up and propagated, you can access your email account using your custom domain. Visit the <a target="_blank" href="http://Zoho.com">Zoho.com</a> website, log in to your account, and navigate to the "Mail" section. Here, you can access your inbox, compose and send emails, set up email signatures, and manage other email-related settings.</p>
<p>Step 6: Configure Email Clients and Devices To access your <a target="_blank" href="http://Zoho.com">Zoho.com</a> email account through email clients or mobile devices, you need to configure the appropriate settings. <a target="_blank" href="http://Zoho.com">Zoho.com</a> provides detailed instructions for popular email clients like Outlook, Thunderbird, and mobile devices like Android and iOS. Follow the step-by-step instructions provided by <a target="_blank" href="http://Zoho.com">Zoho.com</a> to set up your email account on your preferred client or device.</p>
<p>Step 7: Customize Email Settings <a target="_blank" href="http://Zoho.com">Zoho.com</a> offers various customization options to tailor your email experience. Explore the settings in your <a target="_blank" href="http://Zoho.com">Zoho.com</a> account to personalize your email account's appearance, email filters, autoresponders, and other preferences.</p>
<p>Step 8: Manage Additional Features (Optional) <a target="_blank" href="http://Zoho.com">Zoho.com</a> offers additional features and services, such as calendar integration, document collaboration, and task management. Explore the <a target="_blank" href="http://Zoho.com">Zoho.com</a> dashboard to discover and utilize these features to enhance your productivity and communication.</p>
<p>Step 9: Maintain Security and Backups To ensure the security of your email account and data, enable two-factor authentication (2FA) in your <a target="_blank" href="http://Zoho.com">Zoho.com</a> account settings. Additionally, consider regularly backing up your emails to prevent any accidental data loss.</p>
<p>Step 10: Regularly Manage and Monitor Regularly manage your email account settings, check your inbox, and monitor any security notifications or updates from <a target="_blank" href="http://Zoho.com">Zoho.com</a>. Staying vigilant and proactive will help you maintain a secure and efficient email communication system.</p>
<p>Conclusion: With <a target="_blank" href="http://Zoho.com">Zoho.com</a>, you can create a free email account with a custom domain name, enabling you to communicate professionally and effectively. By following the steps outlined in this article, you can set up your email account, configure email delivery, access your inbox, and customize settings according to your preferences. Take advantage of <a target="_blank" href="http://Zoho.com">Zoho.com</a>'s features and services to streamline your email communication and enhance your online presence.</p>
]]></content:encoded></item><item><title><![CDATA[How to Manage Your Domain for Free Using Cloudflare]]></title><description><![CDATA[Introduction: Cloudflare is a powerful platform that offers various services to enhance your website's performance, security, and reliability. In addition to these features, Cloudflare also provides a free plan that allows you to manage your domain e...]]></description><link>https://syarif.kosasih.my.id/how-to-manage-your-domain-for-free-using-cloudflare</link><guid isPermaLink="true">https://syarif.kosasih.my.id/how-to-manage-your-domain-for-free-using-cloudflare</guid><category><![CDATA[free]]></category><category><![CDATA[opensource]]></category><category><![CDATA[Homelab]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:35:54 GMT</pubDate><content:encoded><![CDATA[<p>Introduction: Cloudflare is a powerful platform that offers various services to enhance your website's performance, security, and reliability. In addition to these features, Cloudflare also provides a free plan that allows you to manage your domain effectively. This article will guide you through the process of managing your domain using Cloudflare's free plan. By following these steps, you can take advantage of Cloudflare's robust management tools without any cost.</p>
<p>Step 1: Sign up for a Cloudflare Account Visit the Cloudflare website at <a target="_blank" href="https://www.cloudflare.com"><strong>https://www.cloudflare.com</strong></a> and sign up for a free account. Provide the required information, including your email address and a secure password. Once registered, log in to your Cloudflare account.</p>
<p>Step 2: Add Your Domain to Cloudflare After logging in, you will be prompted to add your domain to Cloudflare. Enter your domain name in the provided field and click the "Add Site" button. Cloudflare will scan your domain's DNS records to identify the existing settings.</p>
<p>Step 3: Verify DNS Records Cloudflare will display a list of DNS records it discovered for your domain. Ensure that all necessary records are listed correctly. Review the records related to your website's main domain (e.g., A, CNAME) and any subdomains you want to manage.</p>
<p>Step 4: Update Name Servers To activate Cloudflare's management for your domain, you need to update your domain's name servers. Cloudflare will provide you with two nameserver addresses. Take note of these addresses and proceed to update the nameservers with your domain registrar.</p>
<p>Step 5: Confirm DNS Propagation After updating the nameservers, it may take some time for the changes to propagate across the internet. You can use online tools like "DNS Propagation Checker" to verify if the nameserver update is complete. Once the propagation is confirmed, Cloudflare will begin managing your domain.</p>
<p>Step 6: Configure DNS Settings Once your domain is active on Cloudflare, you can access various DNS management settings. Navigate to the "DNS" section in your Cloudflare account. Here, you can add, modify, or delete DNS records for your domain and subdomains. Make any necessary changes to align with your website's requirements.</p>
<p>Step 7: Enable SSL/TLS Encryption Cloudflare provides free SSL/TLS certificates for your domain, ensuring secure communication between your website and visitors. In the "SSL/TLS" section of your Cloudflare account, enable the "Flexible," "Full," or "Full (Strict)" SSL mode, depending on your website configuration. This step helps secure your domain with HTTPS.</p>
<p>Step 8: Utilize Cloudflare Features Cloudflare offers various features to enhance your website's performance, security, and caching. Explore the "Speed," "Caching," "Firewall," and other sections in your Cloudflare account to take advantage of these capabilities. Enable or customize features based on your website's specific needs.</p>
<p>Step 9: Monitor and Analyze Cloudflare provides comprehensive analytics and insights about your website's performance, visitors, and threats. Explore the "Analytics" section to gain valuable information and make data-driven decisions to optimize your website's performance and security.</p>
<p>Step 10: Periodically Review and Update Regularly review and update your Cloudflare settings as your website evolves. Ensure that DNS records, security configurations, and performance optimizations remain up to date. Cloudflare's user-friendly interface makes it easy to manage your domain effectively.</p>
<p>Conclusion: By utilizing Cloudflare's free plan, you can effectively manage your domain without any additional cost. From DNS management to SSL/TLS encryption and advanced features, Cloudflare offers a comprehensive suite of tools to enhance your website's performance and security. Follow the steps outlined in this article to set up and manage your domain using Cloudflare, and enjoy the benefits of this powerful platform without breaking your budget.</p>
]]></content:encoded></item><item><title><![CDATA[How to Buy a Domain Name from IDCloudHost.com]]></title><description><![CDATA[Introduction: Choosing the right domain name is a crucial step when establishing your online presence. IDCloudHost.com is a reputable domain registrar that offers a wide range of domain name options. In this article, we will guide you through the pro...]]></description><link>https://syarif.kosasih.my.id/how-to-buy-a-domain-name-from-idcloudhostcom</link><guid isPermaLink="true">https://syarif.kosasih.my.id/how-to-buy-a-domain-name-from-idcloudhostcom</guid><category><![CDATA[free]]></category><category><![CDATA[opensource]]></category><category><![CDATA[Homelab]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:34:13 GMT</pubDate><content:encoded><![CDATA[<p>Introduction: Choosing the right domain name is a crucial step when establishing your online presence. <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> is a reputable domain registrar that offers a wide range of domain name options. In this article, we will guide you through the process of buying a domain name from <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a>. Whether you're a business owner, blogger, or individual looking to create a website, this step-by-step tutorial will help you navigate the domain purchase process.</p>
<p>Step 1: Visit <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> Open your preferred web browser and go to the official website of <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> at <a target="_blank" href="https://www.idcloudhost.com"><strong>https://www.idcloudhost.com</strong></a>.</p>
<p>Step 2: Search for Your Desired Domain Name On the <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> homepage, you will find a domain search box. Enter the domain name you want to purchase and click the "Search" button. <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> will display the availability and pricing of the domain name you entered.</p>
<p>Step 3: Choose Your Domain Extension <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> offers a variety of domain extensions, such as .com, .net, .org, and many more. Select the extension that best suits your website's purpose and audience. Consider factors like branding, target market, and industry relevance when making your choice.</p>
<p>Step 4: Add the Domain to Your Cart Once you've decided on the domain name and extension, click the "Add to Cart" or "Buy Now" button to add it to your shopping cart.</p>
<p>Step 5: Review Your Cart After adding the domain to your cart, you will be redirected to a page where you can review your order details. Ensure that the domain name, extension, and pricing are correct before proceeding.</p>
<p>Step 6: Choose Additional Services (Optional) <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> offers various additional services, such as WHOIS privacy protection, SSL certificates, and website hosting. You can select any desired add-ons during the checkout process. Consider your specific needs and budget when deciding on these services.</p>
<p>Step 7: Proceed to Checkout Click the "Checkout" or "Proceed to Checkout" button to proceed with your domain purchase. You may need to create an account if you don't already have one. Fill in the required information, including your name, email address, billing address, and payment details.</p>
<p>Step 8: Complete the Payment Choose your preferred payment method and provide the necessary information to complete the transaction securely. <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> accepts various payment options, including credit/debit cards, bank transfers, and e-wallets.</p>
<p>Step 9: Verify and Confirm Your Purchase Carefully review your order summary, including the domain name, pricing, and additional services. Once you are satisfied, click the "Confirm Purchase" or "Place Order" button to finalize your domain name purchase.</p>
<p>Step 10: Manage Your Domain After completing your purchase, <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> will provide you with instructions on managing your domain. You can configure DNS settings, set up email accounts, and link the domain to your website hosting.</p>
<p>Conclusion: Buying a domain name from <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> is a straightforward process. By following the steps outlined in this article, you can successfully register a domain name that aligns with your online goals. Remember to choose a domain name that reflects your brand, is memorable, and resonates with your target audience. Establishing a strong online presence starts with securing the right domain name, and <a target="_blank" href="http://IDCloudHost.com">IDCloudHost.com</a> offers a convenient platform to make that happen.</p>
]]></content:encoded></item><item><title><![CDATA[Lab: Troubleshoot and Scale Applications]]></title><description><![CDATA[Navigate the OpenShift web console to identify CPU-consuming workloads.
Troubleshoot and fix a failed MySQL pod.
Manually scale an application.
Configure health probes.
Outcomes
You should be able to troubleshoot malfunctioning workloads, configure d...]]></description><link>https://syarif.kosasih.my.id/lab-troubleshoot-and-scale-applications</link><guid isPermaLink="true">https://syarif.kosasih.my.id/lab-troubleshoot-and-scale-applications</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:26:42 GMT</pubDate><content:encoded><![CDATA[<p>Navigate the OpenShift web console to identify CPU-consuming workloads.</p>
<p>Troubleshoot and fix a failed MySQL pod.</p>
<p>Manually scale an application.</p>
<p>Configure health probes.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to troubleshoot malfunctioning workloads, configure deployments, and scale applications.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. The command also creates the <code>compreview-scale</code> project and deploys some applications in that project.</p>
<p>The command creates the <code>/home/student/DO180/labs/compreview-scale/resources.txt</code> file. The <code>resources.txt</code> file contains the URLs of your OpenShift cluster and the name of the images that you use during the exercise. You can use the file to copy and paste these URLs and image names.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start compreview-scale
</code></pre>
<p><strong>Specifications</strong></p>
<p>The API URL of your OpenShift cluster is <a target="_blank" href="https://api.ocp4.example.com:6443">https://api.ocp4.example.com:6443</a>, and the <code>oc</code> command is already installed on your <code>workstation</code> machine.</p>
<p>The URL of the OpenShift web console is <a target="_blank" href="https://console-openshift-console.apps.ocp4.example.com">https://console-openshift-console.apps.ocp4.example.com</a>. When you access the web console, select <strong>Red Hat Identity Management</strong> as the authentication mechanism.</p>
<p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. The password for the <code>admin</code> user is <code>redhatocp</code>.</p>
<p>Perform the following tasks to complete the comprehensive review:</p>
<ul>
<li><p>A pod in the cluster is consuming excessive CPU and is interfering with other tasks. Identify the pod and remove its workload.</p>
</li>
<li><p>The <code>compreview-scale</code> project already includes a web application at <a target="_blank" href="http://frontend-compreview-scale.apps.ocp4.example.com">http://frontend-compreview-scale.apps.ocp4.example.com</a>. When you access this URL, the application returns a list of quotations from famous authors. The application is broken for now, and is missing some configuration to be ready for production.</p>
<p>  The application uses two Kubernetes <code>Deployment</code> objects. The <code>frontend</code> deployment provides the application web pages, and relies on the <code>quotesdb</code> deployment that runs a MySQL database. The <code>lab</code> command already created the services and routes that connect the application components and that make the application available from outside the cluster.</p>
<p>  Fix the application and make it ready for production:</p>
<ul>
<li><p>The <code>quotesdb</code> deployment in the <code>compreview-scale</code> project starts a MySQL server, but the database is failing. Review the logs of the pod to identify and then fix the issue.</p>
<p>  Use the following parameters for the database:</p>
<p>  | Name | Value |
  | --- | --- |
  | Username | <code>operator1</code> |
  | Password | <code>redhat123</code> |
  | Database name | <code>quotes</code> |</p>
</li>
<li><p>You security team validated a new version of the MySQL container image that fixes a security issue. The new container image is <a target="_blank" href="http://registry.ocp4.example.com:8443/rhel9/mysql-80:1-237"><code>registry.ocp4.example.com:8443/rhel9/mysql-80:1-237</code></a>.</p>
<p>  Update the <code>quotesdb</code> deployment to use this image. Ensure that the database redeploys.</p>
<p>  The classroom setup copied the image from the Red Hat Ecosystem Catalog. The original image is <a target="_blank" href="http://registry.redhat.io/rhel9/mysql-80:1-237"><code>registry.redhat.io/rhel9/mysql-80:1-237</code></a>.</p>
</li>
<li><p>Add a probe to the <code>quotesdb</code> deployment so that OpenShift can detect when the database is ready to accept requests. Use the <code>mysqladmin ping</code> command for the probe.</p>
</li>
<li><p>Add a second probe that regularly verifies the status of the database. Use the <code>mysqladmin ping</code> command as well.</p>
</li>
<li><p>Configure CPU and memory usage for the <code>quotesdb</code> deployment. The deployment needs 200 millicores of CPU and 256 MiB of memory to run, and you must restrict its CPU usage to 500 millicores and its memory usage to 1 GiB.</p>
</li>
<li><p>Add a probe to the <code>frontend</code> deployment so that OpenShift can detect when the web application is ready to accept requests. The application is ready when an HTTP request on port 8000 to the <code>/status</code> path is successful.</p>
</li>
<li><p>Add a second probe that regularly verifies the status of the web front end. The front end works as expected when an HTTP request on port 8000 to the <code>/env</code> path is successful.</p>
</li>
<li><p>Configure CPU and memory usage for the <code>frontend</code> deployment. The deployment needs 200 millicores of CPU and 256 MiB of memory to run, and you must restrict its CPU usage to 500 millicores and its memory usage to 512 MiB.</p>
</li>
<li><p>Scale the <code>frontend</code> application to three pods to accommodate for the estimated production load.</p>
</li>
<li><p>To verify your work, access the <a target="_blank" href="http://frontend-compreview-scale.apps.ocp4.example.com">http://frontend-compreview-scale.apps.ocp4.example.com</a> URL. The application returns a list of quotations from famous authors.</p>
</li>
</ul>
</li>
</ul>
<ol>
<li><p>Use the OpenShift web console to identify and then delete the pod that consumes excessive CPU.</p>
<ol>
<li><p>Use a web browser to access the <a target="_blank" href="https://console-openshift-console.apps.ocp4.example.com">https://console-openshift-console.apps.ocp4.example.com</a> URL.</p>
</li>
<li><p>Select <strong>Red Hat Identity Management</strong>, and then log in as the <code>admin</code> user with the <code>redhatocp</code> password. Click <strong>Skip tour</strong> if the <strong>Welcome to the Developer Perspective</strong> message is displayed.</p>
</li>
<li><p>Switch to the <strong>Administrator</strong> perspective and then navigate to <strong>Observe</strong> → <strong>Dashboards</strong>.</p>
<p> <img src="https://rol.redhat.com/rol/static/static_file_cache/do180-4.12/compreview/scale/assets/dashboards.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select the <strong>Kubernetes / Compute Resources / Cluster</strong> dashboard, and then click <strong>Inspect</strong> in the <strong>CPU Usage</strong> graph.</p>
<p> <img src="https://rol.redhat.com/rol/static/static_file_cache/do180-4.12/compreview/scale/assets/cpu.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Set the zoom to five minutes and then hover over the graph. Notice that the interface lists the <code>compreview-scale-load</code> namespace in the first position, which indicated that this namespace is the first CPU consumer.</p>
<p> <img src="https://rol.redhat.com/rol/static/static_file_cache/do180-4.12/compreview/scale/assets/consumer.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Navigate to <strong>Observe</strong> → <strong>Dashboards</strong> and then select the <strong>Kubernetes / Compute Resources / Namespace (Workloads)</strong> dashboard. Select the <code>compreview-scale-load</code> namespace and then set the time range to the last five minutes. The <code>computeprime</code> deployment is the workload that consumes excessive CPU.</p>
<p> <img src="https://rol.redhat.com/rol/static/static_file_cache/do180-4.12/compreview/scale/assets/workload.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Navigate to <strong>Workloads</strong> → <strong>Deployments</strong> and then select the <code>compreview-scale-load</code> project. Select the menu for the <code>computeprime</code> deployment and then click <strong>Delete Deployment</strong>. Click <strong>Delete</strong> to confirm the operation.</p>
<p> <img src="https://rol.redhat.com/rol/static/static_file_cache/do180-4.12/compreview/scale/assets/delete.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
</li>
<li><p>Review the logs of the pod that is failing for the <code>quotesdb</code> deployment. Set the missing environment variables in the <code>quotesdb</code> deployment.</p>
<ol>
<li><p>Log in to the OpenShift cluster from the command line.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>compreview-scale</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project compreview-scale
 ...output omitted...
</code></pre>
</li>
<li><p>List the pods to identify the failing pod from the <code>quotesdb</code> deployment. The names of the pods on your system probably differ.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS             RESTARTS         AGE
 frontend-5fb85b4c75-5s7xr   0/1     CrashLoopBackOff   14 (2m52s ago)   50m
 quotesdb-9b9776479-4z4g9    0/1     CrashLoopBackOff   14 (3m4s ago)    50m
</code></pre>
</li>
<li><p>Retrieve the logs for the failing pod. Some environment variables are missing.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc logs quotesdb-9b9776479-4z4g9
 =&gt; sourcing 20-validate-variables.sh ...
 You must either specify the following environment variables:
   MYSQL_USER (regex: '^[a-zA-Z0-9_]+$')
   MYSQL_PASSWORD (regex: '[a-zA-Z0-9_~!@#$%&amp;*()-=&lt;&gt;,.?;:|]+$')
   MYSQL_DATABASE (regex: '^[a-zA-Z0-9_]+$')
 ...output omitted...
</code></pre>
</li>
<li><p>Add the missing environment variables to the <code>quotesdb</code> deployment. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set env deployment/quotesdb \
   MYSQL_USER=operator1  MYSQL_PASSWORD=redhat123 MYSQL_DATABASE=quotes
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb updated
</code></pre>
</li>
</ol>
</li>
<li><p>Update the MySQL container image for the <code>quotesdb</code> deployment.</p>
<ol>
<li><p>Retrieve the name of the container that is running inside the pod. You need the container name to update its image.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment/quotesdb -o wide
 NAME       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS ...
 quotesdb   1/1     1            1           59m   mysql-80   ...
</code></pre>
</li>
<li><p>Set the image to <a target="_blank" href="http://registry.ocp4.example.com:8443/rhel9/mysql-80:1-237"><code>registry.ocp4.example.com:8443/rhel9/mysql-80:1-237</code></a>. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image deployment/quotesdb \
   mysql-80=registry.ocp4.example.com:8443/rhel9/mysql-80:1-237
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb image updated
</code></pre>
</li>
<li><p>Verify your work.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment/quotesdb -o wide
 NAME      ... CONTAINERS   IMAGES
 quotesdb  ... mysql-80     registry.ocp4.example.com:8443/rhel9/mysql-80:1-237
</code></pre>
</li>
<li><p>Wait for the deployment to roll out. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS             RESTARTS         AGE
 frontend-5fb85b4c75-5s7xr   0/1     CrashLoopBackOff   15 (3m39s ago)   56m
 quotesdb-54d64749c4-chhq6   1/1     Running            0                106s
</code></pre>
</li>
</ol>
</li>
<li><p>Add a readiness and a liveness probe to the <code>quotesdb</code> deployment that runs the <code>mysqladmin ping</code> command.</p>
<ol>
<li><p>Use the <code>oc set probe</code> command with the <code>--readiness</code> option to add the readiness probe. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set probe deployment/quotesdb \
   --readiness -- mysqladmin ping
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb probes updated
</code></pre>
</li>
<li><p>Use the <code>oc set probe</code> command with the <code>--liveness</code> option to add the liveness probe. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set probe deployment/quotesdb \
   --liveness -- mysqladmin ping
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb probes updated
</code></pre>
</li>
</ol>
</li>
<li><p>Define resource limits for the <code>quotesdb</code> deployment. Set the CPU request to 200 millicores and the memory request to 256 MiB. Set the CPU limit to 500 millicores and the memory limit to 1 GiB. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set resources deployment/quotesdb \
   --requests cpu=200m,memory=256Mi --limits cpu=500m,memory=1Gi
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb resource requirements updated
</code></pre>
</li>
<li><p>Add a readiness and a liveness probe to the <code>frontend</code> deployment.</p>
<ol>
<li><p>Use the <code>oc set probe</code> command with the <code>--readiness</code> option to add the readiness probe that tests the <code>/status</code> path on HTTP port 8000. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set probe deployment/frontend --readiness \
   --get-url http://:8000/status
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/frontend probes updated
</code></pre>
</li>
<li><p>Use the <code>oc set probe</code> command with the <code>--liveness</code> option to add the liveness probe that tests the <code>/env</code> path on HTTP port 8000. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set probe deployment/frontend --liveness \
   --get-url http://:8000/env
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/frontend probes updated
</code></pre>
</li>
</ol>
</li>
<li><p>Define resource limits for the <code>frontend</code> deployment. Set the CPU request to 200 millicores and the memory request to 256 MiB. Set the CPU limit to 500 millicores and the memory limit to 512 MiB. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set resources deployment/frontend \
   --requests cpu=200m,memory=256Mi --limits cpu=500m,memory=512Mi
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/frontend resource requirements updated
</code></pre>
</li>
<li><p>Scale the <code>frontend</code> deployment to three pods.</p>
<ol>
<li><p>Scale the deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/frontend --replicas 3
 deployment.apps/frontend scaled
</code></pre>
</li>
<li><p>Wait for the deployment to scale up. You might have to rerun the command several times for the pods to report a <code>Running</code> status. The names of the pods on your system probably differ.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 frontend-86cdd7c7bf-8vrrs   1/1     Running   0          3m10s
 frontend-86cdd7c7bf-ds79w   1/1     Running   0          44s
 frontend-86cdd7c7bf-hpnwz   1/1     Running   0          44s
 quotesdb-66ff98b88c-fhwhs   1/1     Running   0          12m
</code></pre>
</li>
</ol>
</li>
<li><p>Verify that the application responds to web requests.</p>
<ol>
<li><p>Retrieve the URL of the application.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get route
 NAME       HOST/PORT                                         PATH   SERVICES ...
 frontend   frontend-compreview-scale.apps.ocp4.example.com          frontend ...
</code></pre>
</li>
<li><p>Use the <code>curl</code> command to test the application.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ curl \
   http://frontend-compreview-scale.apps.ocp4.example.com
 &lt;html&gt;
     &lt;head&gt;
         &lt;title&gt;Quotes&lt;/title&gt;
     &lt;/head&gt;
     &lt;body&gt;

         &lt;h1&gt;Quote List&lt;/h1&gt;

             &lt;ul&gt;

                     &lt;li&gt;1: When words fail, music speaks.
 - William Shakespeare
 &lt;/li&gt;
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
</ol>
<p><a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<p><strong>Evaluation</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to grade your work. Correct any reported failures and rerun the command until successful.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab grade compreview-scale
</code></pre>
<p><strong>Finish</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish compreview-scale
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Lab: Deploy Web Applications]]></title><description><![CDATA[Use image streams with Kubernetes workload resources to ensure reproducibility of application deployments.
Configure applications by using Kubernetes secrets to initialize environment variables.
Provide applications with persistent storage volumes.
E...]]></description><link>https://syarif.kosasih.my.id/lab-deploy-web-applications</link><guid isPermaLink="true">https://syarif.kosasih.my.id/lab-deploy-web-applications</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:25:20 GMT</pubDate><content:encoded><![CDATA[<p>Use image streams with Kubernetes workload resources to ensure reproducibility of application deployments.</p>
<p>Configure applications by using Kubernetes secrets to initialize environment variables.</p>
<p>Provide applications with persistent storage volumes.</p>
<p>Expose applications to clients outside the cluster.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to create and configure OpenShift and Kubernetes resources, such as projects, secrets, deployments, persistent volumes, services, and routes.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. The command also creates the <code>/home/student/DO180/labs/compreview-deploy/resources.txt</code> file. The <code>resources.txt</code> file contains the URLs of your OpenShift cluster and the image names that you use in the exercise. You can use the file to copy and paste these URLs and image names.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start compreview-deploy
</code></pre>
<p><strong>Specifications</strong></p>
<p>The API URL of your OpenShift cluster is <a target="_blank" href="https://api.ocp4.example.com:6443">https://api.ocp4.example.com:6443</a>, and the <code>oc</code> command is already installed on your <code>workstation</code> machine.</p>
<p>The URL of the OpenShift web console is <a target="_blank" href="https://console-openshift-console.apps.ocp4.example.com">https://console-openshift-console.apps.ocp4.example.com</a>. When you access the web console, select <strong>Red Hat Identity Management</strong> as the authentication mechanism.</p>
<p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. The password for the <code>admin</code> user is <code>redhatocp</code>, although you do not need administrator privileges to complete the exercise.</p>
<p>In this exercise, you deploy a web application and its database for testing purposes. The resulting configuration is not ready for production, because you do not configure probes and resource limits, which are required for production. Another comprehensive review exercise covers these subjects.</p>
<p>Perform the following tasks to complete the exercise:</p>
<ul>
<li><p>Create a project named <code>review</code> to store all of your work.</p>
</li>
<li><p>Configure your project so that its workloads refer to the database image by the <code>mysql8:1</code> short name.</p>
<ul>
<li><p>The short name must point to the <a target="_blank" href="http://registry.ocp4.example.com:8443/rhel9/mysql-80:1-228"><code>registry.ocp4.example.com:8443/rhel9/mysql-80:1-228</code></a> container image. The database image name and its source registry are expected to change in the near future, and you want to isolate your workloads from that change.</p>
<p>  The classroom setup copied the image from the Red Hat Ecosystem Catalog. The original image is <a target="_blank" href="http://registry.redhat.io/rhel9/mysql-80:1-228"><code>registry.redhat.io/rhel9/mysql-80:1-228</code></a>.</p>
</li>
<li><p>Ensure that the workload resources in the <code>review</code> project can use the <code>mysql8:1</code> resource. You create these workload resources in a later step.</p>
</li>
</ul>
</li>
<li><p>Create the <code>dbparams</code> secret to store the MySQL database parameters. Both the database and the front-end deployment need these parameters. The <code>dbparams</code> secret must include the following variables:</p>
<p>  | Name | Value |
  | --- | --- |
  | <code>user</code> | <code>operator1</code> |
  | <code>password</code> | <code>redhat123</code> |
  | <code>database</code> | <code>quotesdb</code> |</p>
</li>
<li><p>Create the <code>quotesdb</code> deployment and configure it as follows:</p>
<ul>
<li><p>Use the <code>mysql8:1</code> image for the deployment.</p>
</li>
<li><p>The database must automatically roll out whenever the source container in the <code>mysql8:1</code> resource changes.</p>
<p>  To test your configuration, you can change the <code>mysql8:1</code> image to point to the <a target="_blank" href="http://registry.ocp4.example.com:8443/rhel9/mysql-80:1-237"><code>registry.ocp4.example.com:8443/rhel9/mysql-80:1-237</code></a> container image that the classroom provides, and then verify that the <code>quotesdb</code> deployment rolls out. Remember to reset the <code>mysql8:1</code> image to the <a target="_blank" href="http://registry.ocp4.example.com:8443/rhel9/mysql-80:1-228"><code>registry.ocp4.example.com:8443/rhel9/mysql-80:1-228</code></a> container image before grading your work.</p>
</li>
<li><p>Define the following environment variables in the deployment from the keys in the <code>dbparams</code> secret:</p>
<p>  | Environment variable | <code>dbparams</code> secret key |
  | --- | --- |
  | <code>MYSQL_USER</code> | <code>user</code> |
  | <code>MYSQL_PASSWORD</code> | <code>password</code> |
  | <code>MYSQL_DATABASE</code> | <code>database</code> |</p>
</li>
<li><p>Ensure that OpenShift preserves the database data between pod restarts. This data does not consume more than 2 GiB of disk space. The MySQL database stores its data under the <code>/﻿var/lib/mysql</code> directory. Use the <code>lvms-vg1</code> storage class for the volume.</p>
</li>
</ul>
</li>
<li><p>Create a <code>quotesdb</code> service to make the database available to the front-end web application. The database service is listening on port 3306.</p>
</li>
<li><p>Create the <code>frontend</code> deployment and configure it as follows:</p>
<ul>
<li><p>Use the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/famous-quotes:2-42"><code>registry.ocp4.example.com:8443/redhattraining/famous-quotes:2-42</code></a> image. For this deployment, you refer to the image by its full name, because your organization develops the image and controls its release process.</p>
</li>
<li><p>Define the following environment variables in the deployment:</p>
<p>  | Environment variable name | Value |
  | --- | --- |
  | <code>QUOTES_USER</code> | The <code>user</code> key from the <code>dbparams</code> secret |
  | <code>QUOTES_PASSWORD</code> | The <code>password</code> key from the <code>dbparams</code> secret |
  | <code>QUOTES_DATABASE</code> | The <code>database</code> key from the <code>dbparams</code> secret |
  | <code>QUOTES_HOSTNAME</code> | <code>quotesdb</code> |</p>
</li>
</ul>
</li>
<li><p>You cannot yet test the application from outside the cluster. Expose the <code>frontend</code> deployment so that the application can be reached at <a target="_blank" href="http://frontend-review.apps.ocp4.example.com">http://frontend-review.apps.ocp4.example.com</a>.</p>
<p>  The <code>frontend</code> deployment is listening to port 8000.</p>
<p>  When you access the <a target="_blank" href="http://frontend-review.apps.ocp4.example.com">http://frontend-review.apps.ocp4.example.com</a> URL, the application returns a list of quotations from famous authors.</p>
</li>
</ul>
<ol>
<li><p>Log in to the OpenShift cluster from the command line, and then create the <code>review</code> project.</p>
<ol>
<li><p>Log in as the <code>developer</code> user.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Create the <code>review</code> project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc new-project review
 Now using project "review" on server "https://api.ocp4.example.com:6443".
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>mysql8:1</code> image stream tag from the <a target="_blank" href="http://registry.ocp4.example.com:8443/rhel9/mysql-80:1-228"><code>registry.ocp4.example.com:8443/rhel9/mysql-80:1-228</code></a> image. Enable image stream resolution for the <code>mysql8</code> image stream so that Kubernetes resources in the current project can use it.</p>
<ol>
<li><p>Use the <code>oc create istag</code> command to create the image stream and the image stream tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create istag mysql8:1 \
   --from-image registry.ocp4.example.com:8443/rhel9/mysql-80:1-228
 imagestreamtag.image.openshift.io/mysql8:1 created
</code></pre>
</li>
<li><p>Use the <code>oc set image-lookup</code> command to enable image lookup resolution.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image-lookup mysql8
 imagestream.image.openshift.io/mysql8 image lookup updated
</code></pre>
</li>
<li><p>Run the <code>oc set image-lookup</code> command without any arguments to verify your work.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image-lookup
 NAME    LOCAL
 mysql8  true
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>dbparams</code> secret.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create secret generic dbparams \
   --from-literal user=operator1 --from-literal password=redhat123 \
   --from-literal database=quotesdb
 secret/dbparams created
</code></pre>
</li>
<li><p>Create the <code>quotesdb</code> deployment from the <code>mysql8:1</code> image stream tag. Set the number of replicas to zero, to prevent OpenShift from deploying the database before you finish its configuration. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create deployment quotesdb --image mysql8:1 \
   --replicas 0
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb created
</code></pre>
</li>
<li><p>Add an image trigger to the <code>quotesdb</code> deployment.</p>
<ol>
<li><p>Retrieve the name of the container from the <code>quotesdb</code> deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment quotesdb -o wide
 NAME       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS ...
 quotesdb   0/0     0            0           11s   mysql8     ...
</code></pre>
</li>
<li><p>Use the <code>oc set triggers</code> command to add the trigger for the <code>mysql8:1</code> image stream tag to the <code>mysql8</code> container. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set triggers deployment/quotesdb \
   --from-image mysql8:1 --containers mysql8
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb triggers updated
</code></pre>
</li>
</ol>
</li>
<li><p>Add environment variables to the <code>quotesdb</code> deployment from the <code>dbparams</code> secret. Add the <code>MYSQL_</code> prefix to each variable name. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set env deployment/quotesdb \
   --from secret/dbparams --prefix MYSQL_
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb updated
</code></pre>
</li>
<li><p>Add a 2 GiB persistent volume to the <code>quotesdb</code> deployment. Use the <code>lvms-vg1</code> storage class. Inside the pods, mount the volume under the <code>/var/lib/mysql</code> directory. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set volumes deployment/quotesdb --add \
   --claim-class lvms-vg1 --claim-size 2Gi --mount-path /var/lib/mysql
 info: Generated volume name: volume-n7xpd
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/quotesdb volume updated
</code></pre>
</li>
<li><p>Start the database by scaling up the <code>quotesdb</code> deployment to one replica.</p>
<ol>
<li><p>Scale up the deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/quotesdb --replicas 1
 deployment.apps/quotesdb scaled
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                       READY   STATUS    RESTARTS   AGE
 quotesdb-99f9b4ff8-ggs7z   1/1     Running   0          4s
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>quotesdb</code> service for the <code>quotesdb</code> deployment. The database server is listening on port 3306.</p>
<ol>
<li><p>Use the <code>oc expose deployment</code> command to create the service.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc expose deployment quotesdb --port 3306
 service/quotesdb exposed
</code></pre>
</li>
<li><p>Verify that OpenShift associates the IP address of the MySQL server with the endpoint. The endpoint IP address on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe service quotesdb
 Name:              quotesdb
 Namespace:         review
 ...output omitted...
 TargetPort:        3306/TCP
 Endpoints:         10.8.0.123:3306
 Session Affinity:  None
 Events:            &lt;none&gt;
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>frontend</code> deployment from the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/famous-quotes:2-42"><code>registry.ocp4.example.com:8443/redhattraining/famous-quotes:2-42</code></a> image. Set the number of replicas to zero, to prevent OpenShift from deploying the application before you finish its configuration. Ignore the warning message.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ oc create deployment frontend \
  --image registry.ocp4.example.com:8443/redhattraining/famous-quotes:2-42 \
  --replicas 0
Warning: would violate PodSecurity "restricted:v1.24":
...output omitted...
deployment.apps/frontend created
</code></pre>
</li>
<li><p>Add environment variables to the <code>frontend</code> deployment from the <code>dbparams</code> secret, and add the <code>QUOTES_HOSTNAME</code> variable with the <code>quotesdb</code> value.</p>
<ol>
<li><p>Add the variables from the <code>dbparams</code> secret. Add the <code>QUOTES_</code> prefix to each variable name. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set env deployment/frontend \
   --from secret/dbparams --prefix QUOTES_
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/frontend updated
</code></pre>
</li>
<li><p>Declare the <code>QUOTES_HOSTNAME</code> variable. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set env deployment/frontend QUOTES_HOSTNAME=quotesdb
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/frontend updated
</code></pre>
</li>
</ol>
</li>
<li><p>Start the application by scaling up the <code>frontend</code> deployment to one replica.</p>
<ol>
<li><p>Scale up the deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/frontend --replicas 1
 deployment.apps/frontend scaled
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                       READY   STATUS    RESTARTS   AGE
 frontend-86cdd7c7bf-hpnwz  1/1     Running   0          44s
 quotesdb-99f9b4ff8-ggs7z   1/1     Running   0          2m11s
</code></pre>
</li>
</ol>
</li>
<li><p>Expose the <code>frontend</code> deployment so that the application is accessible from outside the cluster. The web application is listening on port 8000.</p>
<ol>
<li><p>Create the <code>frontend</code> service for the <code>frontend</code> deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc expose deployment frontend --port 8000
 service/frontend exposed
</code></pre>
</li>
<li><p>Create the route.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc expose service frontend
 route.route.openshift.io/frontend exposed
</code></pre>
</li>
<li><p>Retrieve the application URL from the route.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get route
 NAME       HOST/PORT                               PATH   SERVICES ...
 frontend   frontend-review.apps.ocp4.example.com          frontend ...
</code></pre>
</li>
<li><p>Use the <code>curl</code> command to test the application.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ curl http://frontend-review.apps.ocp4.example.com
 &lt;html&gt;
     &lt;head&gt;
         &lt;title&gt;Quotes&lt;/title&gt;
     &lt;/head&gt;
     &lt;body&gt;

         &lt;h1&gt;Quote List&lt;/h1&gt;

             &lt;ul&gt;

                     &lt;li&gt;1: When words fail, music speaks.
 - William Shakespeare
 &lt;/li&gt;
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
</ol>
<p><a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<p><strong>Evaluation</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to grade your work. Correct any reported failures and rerun the command until successful.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab grade compreview-deploy
</code></pre>
<p><strong>Finish</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish compreview-deploy
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Lab: Manage Application Updates]]></title><description><![CDATA[Update two live applications to their latest releases as identified by non-floating tags.
Outcomes
You should be able to configure Deployment objects with images and triggers, and configure image stream tags and aliases.
As the student user on the wo...]]></description><link>https://syarif.kosasih.my.id/lab-manage-application-updates</link><guid isPermaLink="true">https://syarif.kosasih.my.id/lab-manage-application-updates</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:23:44 GMT</pubDate><content:encoded><![CDATA[<p>Update two live applications to their latest releases as identified by non-floating tags.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to configure <code>Deployment</code> objects with images and triggers, and configure image stream tags and aliases.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>updates-review</code> project and deploys two applications, <code>app1</code> and <code>app2</code>, in that project.</p>
<p>The command creates the <code>/home/student/DO180/labs/updates-review/resources.txt</code> file. The <code>resources.txt</code> file contains the name of the images that you use during the exercise. You can use the file to copy and paste these image names.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start updates-review
</code></pre>
<p><strong>Procedure 7.5. Instructions</strong></p>
<p>The API URL of your OpenShift cluster is <a target="_blank" href="https://api.ocp4.example.com:6443">https://api.ocp4.example.com:6443</a>, and the <code>oc</code> command is already installed on your <code>workstation</code> machine.</p>
<p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>updates-review</code> project for your work.</p>
<ol>
<li><p>Your team created the <code>app1</code> deployment in the <code>updates-review</code> project from the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/php-ssl:latest"><code>registry.ocp4.example.com:8443/redhattraining/php-ssl:latest</code></a> container image. Recently, a developer in your organization pushed a new version of the image and then reassigned the <code>latest</code> tag to that version.</p>
<p> Reconfigure the <code>app1</code> deployment to use the <code>1-222</code> static tag instead of the <code>latest</code> floating tag, to prevent accidental redeployment of your application with untested image versions that your developers can publish at any time.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>updates-review</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project updates-review
 ...output omitted...
</code></pre>
</li>
<li><p>Verify that the <code>app1</code> deployment uses the <code>latest</code> tag. Retrieve the container name.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment/app1 -o wide
 NAME  READY ...  CONTAINERS  IMAGES ...
 app1  1/1   ...  php-ssl     registry...:8443/redhattraining/php-ssl:latest ...
</code></pre>
</li>
<li><p>In the <code>Deployment</code> object, change the image to <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/php-ssl:1-222"><code>registry.ocp4.example.com:8443/redhattraining/php-ssl:1-222</code></a>. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image deployment/app1 \
   php-ssl=registry.ocp4.example.com:8443/redhattraining/php-ssl:1-222
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/app1 image updated
</code></pre>
</li>
<li><p>Verify your work.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment/app1 -o wide
 NAME   READY ... CONTAINERS  IMAGES ...
 app1   1/1   ... php-ssl     registry...:8443/redhattraining/php-ssl:1-222 ...
</code></pre>
</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<ol>
<li><p>The <code>app2</code> deployment is using the <code>php-ssl:1</code> image stream tag, which is an alias for the <code>php-ssl:1-222</code> image stream tag.</p>
<p> Enable image triggering for the <code>app2</code> deployment, so that whenever the <code>php-ssl:1</code> image stream tag changes, OpenShift rolls out the application. You test your configuration in a later step, when you reassign the <code>php-ssl:1</code> alias to a new image stream tag.</p>
<ol>
<li><p>Retrieve the container name from the <code>Deployment</code> object.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment/app2 -o wide
 NAME   READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS  ...
 app2   1/1     1            1           21m   php-ssl     ...
</code></pre>
</li>
<li><p>Add the image trigger to the <code>Deployment</code> object. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set triggers deployment/app2 \
   --from-image php-ssl:1 --containers php-ssl
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/app2 triggers updated
</code></pre>
</li>
<li><p>Verify your work.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set triggers deployment/app2
 NAME              TYPE    VALUE                AUTO
 deployments/app2  config                       true
 deployments/app2  image   php-ssl:1 (php-ssl)  true
</code></pre>
</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<ol>
<li><p>A new image version, <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/php-ssl:1-234"><code>registry.ocp4.example.com:8443/redhattraining/php-ssl:1-234</code></a>, is available in the container registry. Your QA team tested and approved that version. It is ready for production.</p>
<p> Create the <code>php-ssl:1-234</code> image stream tag that points to the new image. Move the <code>php-ssl:1</code> image stream tag alias to the new <code>php-ssl:1-234</code> image stream tag. Verify that the <code>app2</code> application redeploys.</p>
<ol>
<li><p>Create the <code>php-ssl:1-234</code> image stream tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create istag php-ssl:1-234 \
   --from-image registry.ocp4.example.com:8443/redhattraining/php-ssl:1-234
 imagestreamtag.image.openshift.io/php-ssl:1-234 created
</code></pre>
</li>
<li><p>Move the <code>php-ssl:1</code> alias to the new <code>php-ssl:1-234</code> image stream tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc tag --alias php-ssl:1-234 php-ssl:1
 Tag php-ssl:1 set up to track php-ssl:1-234.
</code></pre>
</li>
<li><p>Verify that the <code>app2</code> application rolls out. The names of the replica sets on your system probably differ.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe deployment/app2
 Name:                   app2
 Namespace:              updates-review
 ...output omitted...
 Events:
   Type    ...  Age         Message
   ----         ----        -------
   Normal  ...  33m    ...  Scaled up replica set app2-7dd589f6d5 to 1
   Normal  ...  3m30s  ...  Scaled up replica set app2-7bf5b7787 to 1
   Normal  ...  3m28s  ...  Scaled down replica set app2-7dd589f6d5 to 0 from 1
</code></pre>
</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<p><strong>Evaluation</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to grade your work. Correct any reported failures and rerun the command until successful.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab grade updates-review
</code></pre>
<p><strong>Finish</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish updates-review
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Automatic Image Updates with OpenShift Image Change Triggers]]></title><description><![CDATA[Update an application that references container images indirectly though image streams.
Outcomes

Add an image trigger to a deployment.

Modify an image stream tag to point to a new image.

Watch the rollout of the application.

Roll back a deploymen...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-automatic-image-updates-with-openshift-image-change-triggers</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-automatic-image-updates-with-openshift-image-change-triggers</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:22:39 GMT</pubDate><content:encoded><![CDATA[<p>Update an application that references container images indirectly though image streams.</p>
<p><strong>Outcomes</strong></p>
<ul>
<li><p>Add an image trigger to a deployment.</p>
</li>
<li><p>Modify an image stream tag to point to a new image.</p>
</li>
<li><p>Watch the rollout of the application.</p>
</li>
<li><p>Roll back a deployment to the previous image.</p>
</li>
</ul>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>updates-triggers</code> project and deploys a web application with 10 replicas.</p>
<p>The command creates the <code>/home/student/DO180/labs/updates-triggers/resources.txt</code> file. The <code>resources.txt</code> file contains the name of the images and some commands that you use during the exercise. You can use the file to copy and paste these image names and commands.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start updates-triggers
</code></pre>
<p><strong>Procedure 7.4. Instructions</strong></p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>updates-triggers</code> project.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>updates-triggers</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project updates-triggers
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Inspect the <code>versioned-hello</code> image stream that the <code>lab</code> command created.</p>
<ol>
<li><p>Verify that the <code>lab</code> command enabled the local lookup policy for the <code>versioned-hello</code> image stream.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image-lookup
 NAME             LOCAL
 versioned-hello  true
</code></pre>
</li>
<li><p>Verify that the <code>lab</code> command created the <code>versioned-hello:1</code> image stream tag. The image stream tag refers to the image in the classroom registry by its SHA ID.</p>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> To improve readability, the instructions truncate the SHA-256 strings.</p>
<p> On your system, the commands return the full SHA-256 strings. Also, you must type the full SHA-256 string, to provide such a parameter to a command.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get istag
 NAME               IMAGE REFERENCE ...
 versioned-hello:1  ...:8443/redhattraining/versioned-hello@sha256:66e0...105e ...
</code></pre>
</li>
<li><p>Verify that the <code>lab</code> command created the <code>versioned-hello:1</code> image stream tag from the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/versioned-hello:1-123"><code>registry.ocp4.example.com:8443/redhattraining/versioned-hello:1-123</code></a> image.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get istag versioned-hello:1 \
   -o jsonpath='{.tag.from.name}{"\n"}'
 registry.ocp4.example.com:8443/redhattraining/versioned-hello:1-123
</code></pre>
</li>
</ol>
</li>
<li><p>Inspect the <code>Deployment</code> object that the <code>lab</code> command created. Verify that the application is available from outside the cluster.</p>
<ol>
<li><p>List the <code>Deployment</code> objects. The <code>version</code> deployment retrieved the SHA image ID from the <code>versioned-hello:1</code> image stream tag. The <code>Deployment</code> object includes a container named <code>versioned-hello</code>. You use that information in a later step, when you configure the trigger.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment -o wide
 NAME     READY ... CONTAINERS        IMAGES ...
 version  10/10 ... versioned-hello   .../versioned-hello@sha256:66e0...105e ...
</code></pre>
</li>
<li><p>Open a new terminal.</p>
</li>
<li><p>Run the <code>/home/student/DO180/labs/updates-triggers/curl_loop.sh</code> script that the <code>lab</code> command prepared. The script sends web requests to the application in a loop. Leave the script running and do not interrupt it.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ /home/student/DO180/labs/updates-triggers/curl_loop.sh
 Hi!
 Hi!
 Hi!
 Hi!
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Add an image trigger to the <code>Deployment</code> object.</p>
<ol>
<li><p>Switch back to the first terminal window, and then use the <code>oc set triggers</code> command to add the trigger for the <code>versioned-hello:1</code> image stream tag to the <code>versioned-hello</code> container. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set triggers deployment/version \
   --from-image versioned-hello:1 --containers versioned-hello
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/version triggers updated
</code></pre>
</li>
<li><p>Review the definition of the trigger from the <a target="_blank" href="http://image.openshift.io/triggers"><code>image.openshift.io/triggers</code></a> annotation.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment version \
   -o jsonpath='{.metadata.annotations.image\.openshift\.io/triggers}' | jq .
 [
   {
     "from": {
       "kind": "ImageStreamTag",
       "name": "versioned-hello:1"
     },
     "fieldPath": "spec.template.spec.containers[?(@.name==\"versioned-hello\")].image"
   }
 ]
</code></pre>
</li>
</ol>
</li>
<li><p>Update the <code>versioned-hello:1</code> image stream tag to point to the <code>1-125</code> tag of the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/versioned-hello"><code>registry.ocp4.example.com:8443/redhattraining/versioned-hello</code></a> image. Watch the output of the <code>curl_loop.sh</code> script to verify that the <code>Deployment</code> object automatically rolls out.</p>
<ol>
<li><p>Use the <code>oc tag</code> command to update the <code>versioned-hello:1</code> tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc tag \
   registry.ocp4.example.com:8443/redhattraining/versioned-hello:1-125 \
   versioned-hello:1
 Tag versioned-hello:1 set to registry.ocp4.example.com:8443/redhattraining/versioned-hello:1-125.
</code></pre>
</li>
<li><p>Changing the image stream tag triggered a rolling update. Watch the output of the <code>curl_loop.sh</code> script in the second terminal.</p>
<p> Before the update, only pods that use the earlier version of the image reply. During the rolling updates, both old and new pods respond. After the update, only pods that run the latest version of the image reply. The following output probably differs on your system.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 Hi!
 Hi!
 Hi!
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 ...output omitted...
</code></pre>
<p> Do not stop the script.</p>
</li>
</ol>
</li>
<li><p>Inspect the <code>Deployment</code> object and the image stream.</p>
<ol>
<li><p>List the <code>version</code> deployment and notice that the image changed.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment version -o wide
 NAME     READY ... CONTAINERS        IMAGES ...
 version  10/10 ... versioned-hello   .../versioned-hello@sha256:834d...fcb4 ...
</code></pre>
</li>
<li><p>Display the details of the <code>versioned-hello</code> image stream. The <code>versioned-hello:1</code> image stream tag points to the image with the same SHA ID as in the <code>Deployment</code> object.</p>
<p> Notice that the preceding image is still available. In the following step, you roll back to that image by specifying its SHA ID.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe is versioned-hello
 Name:           versioned-hello
 Namespace:      updates-triggers
 ...output omitted...

 1
   tagged from registry.ocp4.example.com:8443/redhattraining/versioned-hello:1-125

   * registry.ocp4.example.com:8443/.../versioned-hello@sha256:834d...fcb4
       6 minutes ago
     registry.ocp4.example.com:8443/.../versioned-hello@sha256:66e0...105e
       37 minutes ago
</code></pre>
</li>
</ol>
</li>
<li><p>Roll back the <code>Deployment</code> object by reverting the <code>versioned-hello:1</code> image stream tag.</p>
<ol>
<li><p>Use the <code>oc tag</code> command. For the source image, copy and paste the old image name and the SHA ID from the output of the preceding command.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc tag \
 registry.ocp4.example.com:8443/redhattraining/versioned-hello@sha256:66e0...105e \
 versioned-hello:1
 Tag versioned-hello:1 set to registry.ocp4.example.com:8443/redhattraining/versioned-hello@sha256:66e0...105e.
</code></pre>
</li>
<li><p>Watch the output of the <code>curl_loop.sh</code> script in the second terminal. The pods that run the <code>v1.0</code> version of the application are responding again. The following output probably differs on your system.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi!
 Hi!
 ...output omitted...
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the script. Close that second terminal when done.</p>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish updates-triggers
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Reproducible Deployments with OpenShift Image Streams]]></title><description><![CDATA[Deploy an application that references container images indirectly by using image streams.
Outcomes
You should be able to create image streams and image stream tags, and deploy applications that use image stream tags.
As the student user on the workst...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-reproducible-deployments-with-openshift-image-streams</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-reproducible-deployments-with-openshift-image-streams</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:21:03 GMT</pubDate><content:encoded><![CDATA[<p>Deploy an application that references container images indirectly by using image streams.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to create image streams and image stream tags, and deploy applications that use image stream tags.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>updates-imagestreams</code> project and the <code>/home/student/DO180/labs/updates-imagestreams/resources.txt</code> file. The <code>resources.txt</code> file contains the name of the images and some commands that you use during the exercise. You can use the file to copy and paste these image names and commands.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start updates-imagestreams
</code></pre>
<p><strong>Procedure 7.3. Instructions</strong></p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>updates-imagestreams</code> project.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>updates-imagestreams</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project updates-imagestreams
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>versioned-hello</code> image stream and the <code>v1.0</code> image stream tag from the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0"><code>registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0</code></a> image.</p>
<ol>
<li><p>Use the <code>oc create is</code> command to create the image stream.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create is versioned-hello
 imagestream.image.openshift.io/versioned-hello created
</code></pre>
</li>
<li><p>Use the <code>oc create istag</code> command to create the image stream tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create istag versioned-hello:v1.0 \
   --from-image registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0
 imagestreamtag.image.openshift.io/versioned-hello:v1.0 created
</code></pre>
</li>
</ol>
</li>
<li><p>Enable image stream resolution for the <code>versioned-hello</code> image stream so that Kubernetes resources in the current project can use it.</p>
<ol>
<li><p>Use the <code>oc set image-lookup</code> command to enable image lookup resolution.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image-lookup versioned-hello
 imagestream.image.openshift.io/versioned-hello image lookup updated
</code></pre>
</li>
<li><p>Run the <code>oc set image-lookup</code> command without any arguments to verify your work.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image-lookup
 NAME             LOCAL
 versioned-hello  true
</code></pre>
</li>
</ol>
</li>
<li><p>Review the image stream and confirm that the image stream tag refers to the source image by its SHA ID. Verify that the source image in the <a target="_blank" href="http://registry.ocp4.example.com:8443"><code>registry.ocp4.example.com:8443</code></a> registry has the same SHA ID.</p>
<ol>
<li><p>Retrieve the details of the <code>versioned-hello</code> image stream.</p>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> To improve readability, the instructions truncate the SHA-256 strings.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe is versioned-hello
 Name:           versioned-hello
 Namespace:      updates-imagestreams
 Created:        7 minutes ago
 ...output omitted...

 v1.0
   tagged from registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0

   * registry.ocp4.example.com:8443/.../versioned-hello@sha256:66e0...105e
       7 minutes ago
</code></pre>
</li>
<li><p>Use the <code>oc image info</code> command to query the image from the classroom container registry. The SHA image ID is the same as the one from the image stream tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc image info \
   registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0
 Name:          registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0
 Digest:        sha256:66e0...105e
 Media Type:    application/vnd.docker.distribution.manifest.v2+json
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Create a deployment named <code>version</code> that uses the <code>versioned-hello:v1.0</code> image stream tag.</p>
<ol>
<li><p>Use the <code>oc create deployment</code> command to create the object. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create deployment version --image versioned-hello:v1.0
 Warning: would violate PodSecurity "restricted:v1.24":
  ...output omitted...
 deployment.apps/version created
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                       READY   STATUS    RESTARTS   AGE
 version-744bf7694b-bzhd2   1/1     Running   0          2m11s
</code></pre>
</li>
</ol>
</li>
<li><p>Confirm that both the deployment and the pod refer to the image by its SHA ID.</p>
<ol>
<li><p>Retrieve the image that the deployment uses. The deployment refers to the image from the source registry by its SHA ID. The <code>v1.0</code> image stream tag also points to that SHA image ID.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment -o wide
 ... IMAGES ...
 ... registry.ocp4.example.com:8443/.../versioned-hello@sha256:66e0...105e ...
</code></pre>
</li>
<li><p>Retrieve the image that the pod is using. The pod is also referring to the image by its SHA ID.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pod version-744bf7694b-bzhd2 \
   -o jsonpath='{.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/redhattraining/versioned-hello@sha256:66e0...105e
</code></pre>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish updates-imagestreams
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Update Application Image and Settings]]></title><description><![CDATA[Update the manifests of a database and a web application while minimizing interruption of service to their users.
Outcomes
You should be able to pause, update, and resume a deployment, and roll back a failing application.
As the student user on the w...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-update-application-image-and-settings</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-update-application-image-and-settings</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:19:21 GMT</pubDate><content:encoded><![CDATA[<p>Update the manifests of a database and a web application while minimizing interruption of service to their users.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to pause, update, and resume a deployment, and roll back a failing application.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>updates-rollout-db</code> project and deploys a MySQL database in that project. It creates the <code>updates-rollout-web</code> project and then deploys a web application with 10 replicas.</p>
<p>The command creates the <code>/home/student/DO180/labs/updates-rollout/resources.txt</code> file. The <code>resources.txt</code> file contains the name of the images and some commands that you use during the exercise. You can use the file to copy and paste these image names and commands.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start updates-rollout
</code></pre>
<p><strong>Procedure 7.2. Instructions</strong></p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>updates-rollout-db</code> project.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>updates-rollout-db</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project updates-rollout-db
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Review the resources that the <code>lab</code> command created. Confirm that you can connect to the database. The MySQL database uses ephemeral storage.</p>
<ol>
<li><p>List the <code>Deployment</code> object and confirm that the pod is available. Retrieve the name of the container. You use that information when you update the container image in another step.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment -o wide
 NAME   READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS ...
 mydb   1/1     0            1           17m   mysql-80   ...
</code></pre>
</li>
<li><p>List the pods and confirm that the pod is running. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pod
 NAME                    READY   STATUS    RESTARTS   AGE
 mydb-5c79866d48-5xzkk   1/1     Running   0          18m
</code></pre>
</li>
<li><p>Retrieve the name of the image that the pod is using. The pod is using the <code>rhel9/mysql-80</code> image version <code>1-224</code>. Replace the pod name with your own from the previous step.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pod mydb-5c79866d48-5xzkk \
   -o jsonpath='{.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/rhel9/mysql-80:1-224
</code></pre>
<p> The classroom setup copied that image from the Red Hat Ecosystem Catalog. The original image is <a target="_blank" href="http://registry.redhat.io/rhel9/mysql-80"><code>registry.redhat.io/rhel9/mysql-80</code></a>.</p>
</li>
<li><p>Confirm that you can connect to the database system by listing the available databases. Run the <code>mysql</code> command from inside the pod and connect as the <code>operator1</code> user by using <code>test</code> as the password.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rsh mydb-5c79866d48-5xzkk \
   mysql --user=operator1 --password=test -e "SHOW DATABASES"
 mysql: [Warning] Using a password on the command line interface can be insecure.
 +--------------------+
 | Database           |
 +--------------------+
 | information_schema |
 | performance_schema |
 | quotes             |
 +--------------------+
</code></pre>
</li>
</ol>
</li>
<li><p>You must implement several updates to the <code>Deployment</code> object. Pause the deployment to prevent OpenShift from rolling out the application for each modification that you make. After you pause the deployment, change the password for the <code>operator1</code> database user, update the container image, and then resume the deployment.</p>
<ol>
<li><p>Pause the <code>mydb</code> deployment. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rollout pause deployment/mydb
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/mydb paused
</code></pre>
</li>
<li><p>Change the password of the <code>operator1</code> database user to <code>redhat123</code>. To change the password, update the <code>MYSQL_PASSWORD</code> environment variable in the pod template of the <code>Deployment</code> object. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set env deployment/mydb MYSQL_PASSWORD=redhat123
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/mydb updated
</code></pre>
</li>
<li><p>Because the <code>Deployment</code> object is paused, confirm that the new password is not yet active. To do so, rerun the <code>mysql</code> command by using the current password. The database connection succeeds.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rsh mydb-5c79866d48-5xzkk \
   mysql --user=operator1 --password=test -e "SHOW DATABASES"
 mysql: [Warning] Using a password on the command line interface can be insecure.
 +--------------------+
 | Database           |
 +--------------------+
 | information_schema |
 | performance_schema |
 | quotes             |
 +--------------------+
</code></pre>
</li>
<li><p>Update the MySQL container image to the <code>1-228</code> version. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image deployment/mydb \
   mysql-80=registry.ocp4.example.com:8443/rhel9/mysql-80:1-228
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/mydb image updated
</code></pre>
</li>
<li><p>Because the <code>Deployment</code> object is paused, confirm that the pod still uses the <code>1-224</code> image version.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pod mydb-5c79866d48-5xzkk \
   -o jsonpath='{.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/rhel9/mysql-80:1-224
</code></pre>
</li>
<li><p>Resume the <code>mydb</code> deployment. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rollout resume deployment/mydb
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/mydb resumed
</code></pre>
</li>
<li><p>Confirm that the new rollout completes by waiting for the new pod to be running. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                   READY   STATUS    RESTARTS   AGE
 mydb-dd5dcbddb-rmf85   1/1     Running   0          2m2s
</code></pre>
</li>
</ol>
</li>
<li><p>Verify that OpenShift applied all your modifications to the <code>Deployment</code> object.</p>
<ol>
<li><p>Retrieve the name of the image that the new pod is using. In the following command, use the name of the new pod as a parameter to the <code>oc get pod</code> command. The pod is now using the <code>1-228</code> image version.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pod mydb-dd5dcbddb-rmf85 \
   -o jsonpath='{.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/rhel9/mysql-80:1-228
</code></pre>
</li>
<li><p>Confirm that you can connect to the database system by using the new password, <code>redhat123</code>, for the <code>operator1</code> database user.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rsh mydb-dd5dcbddb-rmf85 \
   mysql --user=operator1 --password=redhat123 -e "SHOW DATABASES"
 mysql: [Warning] Using a password on the command line interface can be insecure.
 +--------------------+
 | Database           |
 +--------------------+
 | information_schema |
 | performance_schema |
 | quotes             |
 +--------------------+
</code></pre>
</li>
</ol>
</li>
<li><p>In the second part of the exercise, you perform a rolling update of a replicated web application. Use the <code>updates-rollout-web</code> project and review the resources that the <code>lab</code> command created.</p>
<ol>
<li><p>Set the <code>updates-rollout-web</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project updates-rollout-web
 ...output omitted...
</code></pre>
</li>
<li><p>List the <code>Deployment</code> object and confirm that the pods are available. Retrieve the name of the containers. You use that information when you update the container image in another step.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment -o wide
 NAME      READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS      ...
 version   10/10   10           10          32m   versioned-hello ...
</code></pre>
</li>
<li><p>List the <code>ReplicaSet</code> objects. Because OpenShift did not yet perform rolling updates, only one <code>ReplicaSet</code> object exists. The name of the <code>ReplicaSet</code> object on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get replicaset
 NAME                 DESIRED   CURRENT   READY   AGE
 version-7bfff6b5b4   10        10        10      11m
</code></pre>
</li>
<li><p>Retrieve the name and version of the image that the <code>ReplicaSet</code> object uses to deploy the pods. The pods are using the <code>redhattraining/versioned-hello</code> image version <code>v1.0</code>.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get replicaset version-7bfff6b5b4 \
   -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.0
</code></pre>
</li>
<li><p>Confirm that the <code>version</code> deployment includes a readiness probe. The probe performs an HTTP GET request on port 8080.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment version \
   -o jsonpath='{.spec.template.spec.containers[0].readinessProbe}' | jq .
 {
   "failureThreshold": 3,
   "httpGet": {
     "path": "/",
     "port": 8080,
     "scheme": "HTTP"
   },
   "initialDelaySeconds": 3,
   "periodSeconds": 10,
   "successThreshold": 1,
   "timeoutSeconds": 1
 }
</code></pre>
</li>
</ol>
</li>
<li><p>To watch the rolling update that you cause in a following step, open a new terminal window and then run the <code>~/DO180/labs/updates-rollout/curl_loop.sh</code> script that the <code>lab</code> command prepared. The script sends web requests to the application in a loop.</p>
<ol>
<li><p>Open a new terminal.</p>
</li>
<li><p>Run the <code>/home/student/DO180/labs/updates-rollout/curl_loop.sh</code> script. Leave the script running and do not interrupt it.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ /home/student/DO180/labs/updates-rollout/curl_loop.sh
 Hi!
 Hi!
 Hi!
 Hi!
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Change the container image of the <code>version</code> deployment. The new application version creates a web page with a different message.</p>
<ol>
<li><p>Switch back to the first terminal window, and then use the <code>oc set image</code> command to update the deployment. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image deployment/version \
 versioned-hello=registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.1
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/version image updated
</code></pre>
</li>
<li><p>Changing the image caused a rolling update. Watch the output of the <code>curl_loop.sh</code> script in the second terminal.</p>
<p> Before the update, only pods that run the <code>v1.0</code> version of the application reply. During the rolling updates, both old and new pods are responding. After the update, only pods that run the <code>v1.1</code> version of the application reply. The following output probably differs on your system.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 Hi!
 Hi!
 Hi!
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 ...output omitted...
</code></pre>
<p> Do not stop the script.</p>
</li>
</ol>
</li>
<li><p>Confirm that the rollout process is successful. List the <code>ReplicaSet</code> objects and verify that the new object uses the new image version.</p>
<ol>
<li><p>Use the <code>oc rollout status</code> command to confirm that the rollout process is successful.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rollout status deployment/version
 deployment "version" successfully rolled out
</code></pre>
</li>
<li><p>List the <code>ReplicaSet</code> objects. The initial object scaled down to zero pods. The new <code>ReplicaSet</code> object scaled up to 10 pods. The names of the <code>ReplicaSet</code> objects on your system probably differ.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get replicaset
 NAME                 DESIRED   CURRENT   READY   AGE
 version-7bfff6b5b4   0         0         0       28m
 version-b7fddfc8c    10        10        10      3m40s
</code></pre>
</li>
<li><p>Retrieve the name and version of the image that the new <code>ReplicaSet</code> object uses. This image provides the new version of the application.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get replicaset version-b7fddfc8c \
   -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/redhattraining/versioned-hello:v1.1
</code></pre>
</li>
</ol>
</li>
<li><p>Roll back the <code>version</code> deployment.</p>
<ol>
<li><p>Use the <code>oc rollout undo</code> command to roll back to the initial application version. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc rollout undo deployment/version
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/version rolled back
</code></pre>
</li>
<li><p>Watch the output of the <code>curl_loop.sh</code> script in the second terminal. The pods that run the <code>v1.0</code> version of the application are responding again. The following output probably differs on your system.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi!
 Hi! v1.1
 Hi! v1.1
 Hi!
 Hi!
 Hi!
 ...output omitted...
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the script. Close that second terminal when done.</p>
</li>
<li><p>List the <code>ReplicaSet</code> objects. The initial object scaled up to 10 pods. The object for the new application version scaled down to zero pods.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get replicaset
 NAME                 DESIRED   CURRENT   READY   AGE
 version-7bfff6b5b4   10        10        10      52m
 version-b7fddfc8c    0         0         0       27m
</code></pre>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish updates-rollout
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Container Image Identity and Tags]]></title><description><![CDATA[Update an application by changing its deployment to reference a newer image tag, and find the hashes of the old and new application images.
Outcomes
You should be able to inspect container images, list images of containers that run on compute nodes, ...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-container-image-identity-and-tags</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-container-image-identity-and-tags</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:18:32 GMT</pubDate><content:encoded><![CDATA[<p>Update an application by changing its deployment to reference a newer image tag, and find the hashes of the old and new application images.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to inspect container images, list images of containers that run on compute nodes, and deploy applications by using image tags or SHA IDs.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>updates-ids</code> project and the <code>/home/student/DO180/labs/updates-ids/resources.txt</code> file. The <code>resources.txt</code> file contains the name of the images and some commands that you use during the exercise. You can use the file to copy and paste these image names and commands.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start updates-ids
</code></pre>
<p><strong>Procedure 7.1. Instructions</strong></p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>updates-ids</code> project.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>updates-ids</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project updates-ids
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Inspect the two versions of the <a target="_blank" href="http://registry.ocp4.example.com:8443/ubi8/httpd-24"><code>registry.ocp4.example.com:8443/ubi8/httpd-24</code></a> image from the classroom container registry. The classroom setup copied that image from the Red Hat Ecosystem Catalog. The original image is <a target="_blank" href="http://registry.access.redhat.com/ubi8/httpd-24"><code>registry.access.redhat.com/ubi8/httpd-24</code></a>.</p>
<ol>
<li><p>Use the <code>oc image info</code> command to inspect the image version that the <code>1-209</code> tag references. Notice the unique SHA ID that identifies the image version.</p>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> To improve readability, the instructions truncate the SHA-256 strings.</p>
<p> On your system, the commands return the full SHA-256 strings. Also, you must type the full SHA-256 string, to provide such a parameter to a command.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc image info \
   registry.ocp4.example.com:8443/ubi8/httpd-24:1-209
 Name:          registry.ocp4.example.com:8443/ubi8/httpd-24:1-209
 Digest:        sha256:b1e3...f876
 ...output omitted...
</code></pre>
</li>
<li><p>Inspect the image version that the <code>1-215</code> tag references. Notice that the SHA ID, or digest, differs from the preceding image version.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc image info \
   registry.ocp4.example.com:8443/ubi8/httpd-24:1-215
 Name:          registry.ocp4.example.com:8443/ubi8/httpd-24:1-215
 Digest:        sha256:91ad...fd83
 ...output omitted...
</code></pre>
</li>
<li><p>For inspecting images, you can also use the <code>skopeo inspect</code> command. The output format differs from the <code>oc image info</code> command, although both commands report similar data.</p>
<p> Log in to the registry as the <code>developer</code> user with the <code>developer</code> password by using the <code>skopeo login</code> command. Then, use the <code>skopeo inspect</code> command to inspect the <code>1-215</code> image tag.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ skopeo login registry.ocp4.example.com:8443 -u developer
 Password:
 Login Succeeded!
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation ~]$ skopeo inspect \
   docker://registry.ocp4.example.com:8443/ubi8/httpd-24:1-215
 {
     "Name": "registry.ocp4.example.com:8443/ubi8/httpd-24",
     "Digest": "sha256:91ad...fd83",
     "RepoTags": [
         "1-209",
         "1-215"
     ],
 ...output omitted...
 }
</code></pre>
<p> The <code>skopeo inspect</code> command also shows other existing image tags.</p>
</li>
</ol>
</li>
<li><p>Deploy an application from the image version that the <code>1-209</code> tag references.</p>
<ol>
<li><p>Use the <code>oc create deployment</code> command to deploy the application. Set the name of the deployment to <code>httpd1</code>. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create deployment httpd1 \
   --image registry.ocp4.example.com:8443/ubi8/httpd-24:1-209
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/httpd1 created
</code></pre>
</li>
<li><p>Wait for the pod to start, and then retrieve the name of the cluster node that runs it. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods -o wide
 NAME                     READY  STATUS   RESTARTS  AGE  IP          NODE     ...
 httpd1-6dff796d99-pm2x6  1/1    Running  0         19s  10.8.0.104  master01 ...
</code></pre>
</li>
<li><p>Retrieve the name of the container that is running inside the pod. The <code>crictl ps</code> command that you run in a following step takes the container name as an argument.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment httpd1 -o wide
 NAME     READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS  ...
 httpd1   1/1     1            1           1m10s   httpd-24    ...
</code></pre>
</li>
</ol>
</li>
<li><p>Access the cluster node and then retrieve the image that the container is using.</p>
<ol>
<li><p>You must log in as the <code>admin</code> user to access the cluster node. Use the <code>redhatocp</code> password.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u admin -p redhatocp
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Use the <code>oc debug node</code> command to access the cluster node.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc debug node/master01
 Temporary namespace openshift-debug-flz4d is created for debugging node...
 Starting pod/master01-debug ...
 To use host binaries, run `chroot /host`
 Pod IP: 192.168.50.10
 If you don't see a command prompt, try pressing enter.
</code></pre>
</li>
<li><p>In the remote shell, run the <code>chroot /﻿host</code> command.</p>
<pre><code class="lang-plaintext"> sh-4.4# chroot /host
 sh-4.4#
</code></pre>
</li>
<li><p>Use the <code>crictl ps</code> command to confirm that the <code>httpd-24</code> container is running. Add the <code>-o yaml</code> option to display the container details in YAML format.</p>
<pre><code class="lang-plaintext"> sh-4.4# crictl ps --name httpd-24 -o yaml
 containers:
 - annotations:
 ...output omitted...
   image:
     annotations: {}
     image: registry.ocp4.example.com:8443/ubi8/httpd-24@sha256:b1e3...f876
   imageRef: registry.ocp4.example.com:8443/ubi8/httpd-24@sha256:b1e3...f876
   labels:
 ...output omitted...
   state: CONTAINER_RUNNING
</code></pre>
<p> Notice that the command refers to the image by its SHA ID, and not by the tag that you specified when you created the deployment resource.</p>
</li>
<li><p>Use the <code>crictl images</code> command to list the locally available images on the node. The <a target="_blank" href="http://registry.ocp4.example.com:8443/ubi8/httpd-24:1-209"><code>registry.ocp4.example.com:8443/ubi8/httpd-24:1-209</code></a> is in that list, because the local container engine pulled it when you deployed the <code>httpd1</code> application.</p>
<h3 id="heading-note-1"><strong>NOTE</strong></h3>
<p> The <code>IMAGE ID</code> column displays the local image identifier that the container engine assigns to the image. This identifier is not related to the SHA image ID that the container registry assigned to the image.</p>
<p> Most <code>crictl</code> commands, such as <code>crictl images</code> or <code>crictl rmi</code>, accept a local image identifier instead of the full image name. For example, you can run the <code>crictl images 8ee59251acc93</code> command as a short version of the <code>crictl images</code> <a target="_blank" href="http://registry.ocp4.example.com:8443/ubi8/httpd-24:1-209"><code>registry.ocp4.example.com:8443/ubi8/httpd-24:1-209</code></a> command.</p>
<pre><code class="lang-plaintext"> sh-4.4# crictl images
 IMAGE                                           TAG     IMAGE ID           SIZE
 quay.io/openshift-release-dev/ocp-release       &lt;none&gt;  d52324cb88017      444MB
 quay.io/openshift-release-dev/ocp-v4.0-art-dev  &lt;none&gt;  22e6e45df32af      468MB
 quay.io/openshift-release-dev/ocp-v4.0-art-dev  &lt;none&gt;  e798432938c49      503MB
 quay.io/openshift-release-dev/ocp-v4.0-art-dev  &lt;none&gt;  3ca084e53b321      873MB
 ...output omitted...
 registry.ocp4.example.com:8443/ubi8/httpd-24    1-209   8ee59251acc93      461MB
 ...output omitted...
</code></pre>
</li>
<li><p>The preceding <code>crictl images</code> command does not display the SHA image IDs by default. Rerun the command and add the <code>--digests</code> option to display the SHA IDs. Also add the local image ID to the command to limit the output to the <a target="_blank" href="http://registry.ocp4.example.com:8443/ubi8/httpd-24:1-209"><code>registry.ocp4.example.com:8443/ubi8/httpd-24:1-209</code></a> image.</p>
<p> The command reports only the first characters of the SHA image ID. These characters match the SHA ID of the image that the <code>httpd-24</code> container is using. Therefore, the <code>httpd-24</code> container is using the expected image.</p>
<pre><code class="lang-plaintext"> sh-4.4# crictl images --digests 8ee59251acc93
 IMAGE                                        TAG   DIGEST        IMAGE ID      ...
 registry.ocp4.example.com:8443/ubi8/httpd-24 1-209 b1e3c572516d1 8ee59251acc93 ...
</code></pre>
</li>
<li><p>Disconnect from the cluster node.</p>
<pre><code class="lang-plaintext"> sh-4.4# exit
 exit
 sh-4.4# exit
 exit

 Removing debug pod ...
 Temporary namespace openshift-debug-flz4d was removed.
 [student@workstation ~]$
</code></pre>
</li>
</ol>
</li>
<li><p>Log in as the <code>developer</code> user and then deploy another application by using the SHA ID of the image as the digest.</p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Rerun the <code>oc image info</code> command to retrieve the SHA ID of the image version that the <code>1-209</code> tag references. Specify the JSON format for the command output. Parse the JSON output with the <code>jq -r</code> command to retrieve the value of the <code>.digest</code> object. Export the SHA ID as the <code>$IMAGE</code> environment variable.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc image info \
   registry.ocp4.example.com:8443/ubi8/httpd-24:1-209 -o json | \
   jq -r .digest
 sha256:b1e3...f876
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation ~]$ IMAGE=sha256:b1e3...f876
</code></pre>
</li>
<li><p>Use the <code>oc create deployment</code> command to deploy the application. Set the name of the deployment to <code>httpd2</code>. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create deployment httpd2 \
   --image registry.ocp4.example.com:8443/ubi8/httpd-24@$IMAGE
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/httpd2 created
</code></pre>
</li>
<li><p>Confirm that the new deployment refers to the image version by its SHA ID.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment httpd2 -o wide
 NAME     READY  ...  CONTAINERS   IMAGES ...
 httpd2   1/1    ...  httpd-24     registry.../ubi8/httpd-24@sha256:b1e3...f876 ...
</code></pre>
</li>
</ol>
</li>
<li><p>Update the <code>httpd2</code> application by using a more recent image version.</p>
<ol>
<li><p>In the <code>httpd2</code> deployment, update the <code>httpd-24</code> container to use the image version that the <code>1-215</code> tag references. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set image deployment/httpd2 \
   httpd-24=registry.ocp4.example.com:8443/ubi8/httpd-24:1-215
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/httpd2 image updated
</code></pre>
</li>
<li><p>Confirm that the deployment refers to the new image version.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment httpd2 -o wide
 NAME     READY   ...    IMAGES ...
 httpd2   1/1     ...    registry.ocp4.example.com:8443/ubi8/httpd-24:1-215 ...
</code></pre>
</li>
<li><p>Confirm that the deployment finished redeploying the pod. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The pod names probably differ on your system.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                      READY   STATUS    RESTARTS   AGE
 httpd1-6dff796d99-pm2x6   1/1     Running   0          118m
 httpd2-998d9b9b9-5859j    1/1     Running   0          21s
</code></pre>
</li>
<li><p>Inspect the pod to confirm that the container is using the new image. Replace the pod name with your own from the previous step.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pod httpd2-998d9b9b9-5859j \
   -o jsonpath='{.spec.containers[0].image}{"\n"}'
 registry.ocp4.example.com:8443/ubi8/httpd-24:1-215
</code></pre>
</li>
</ol>
</li>
<li><p>Add the <code>latest</code> tag to the image version that the <code>1-209</code> tag already references. Deploy an application from the image with the <code>latest</code> tag.</p>
<ol>
<li><p>Use the <code>skopeo login</code> command to log in to the classroom container registry as the <code>developer</code> user. Use <code>developer</code> for the password.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ skopeo login -u developer -p developer \
   registry.ocp4.example.com:8443
 Login Succeeded!
</code></pre>
</li>
<li><p>Use the <code>skopeo copy</code> command to add the <code>latest</code> tag to the image.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ skopeo copy \
   docker://registry.ocp4.example.com:8443/ubi8/httpd-24:1-209 \
   docker://registry.ocp4.example.com:8443/ubi8/httpd-24:latest
 Getting image source signatures
 ...output omitted...
 Writing manifest to image destination
 Storing signatures
</code></pre>
</li>
<li><p>Use the <code>oc image info</code> command to confirm that both tags refer to the same image. The two commands report the same SHA image ID, which indicates that the tags point to the same image version.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc image info \
   registry.ocp4.example.com:8443/ubi8/httpd-24:1-209
 Name:          registry.ocp4.example.com:8443/ubi8/httpd-24:1-209
 Digest:        sha256:b1e3...f876
 ...output omitted...
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc image info \
   registry.ocp4.example.com:8443/ubi8/httpd-24:latest
 Name:          registry.ocp4.example.com:8443/ubi8/httpd-24:latest
 Digest:        sha256:b1e3...f876
 ...output omitted...
</code></pre>
</li>
<li><p>Use the <code>oc create deployment</code> command to deploy another application. Set the name of the deployment to <code>httpd3</code>. To confirm that by default the command selects the <code>latest</code> tag, do not provide the tag part in the image name. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc create deployment httpd3 \
   --image registry.ocp4.example.com:8443/ubi8/httpd-24
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/httpd3 created
</code></pre>
</li>
<li><p>Confirm that the pod is running. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The pod names probably differ on your system.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                      READY   STATUS    RESTARTS   AGE
 httpd1-6dff796d99-pm2x6   1/1     Running   0          150m
 httpd2-998d9b9b9-5859j    1/1     Running   0          32m
 httpd3-85b978d758-fvqdr   1/1     Running   0          42s
</code></pre>
</li>
<li><p>Confirm that the pod is using the expected image. Notice that the SHA image ID corresponds to the image that the <code>1-209</code> tag references. You retrieved that SHA image ID in a preceding step when you ran the <code>oc image info</code> command.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe pod httpd3-85b978d758-fvqdr
 ...output omitted...
 Containers:
   httpd-24:
     Container ID: cri-o://2cee...3a68
     Image:        registry.ocp4.example.com:8443/ubi8/httpd-24
     Image ID:     registry.ocp4.example.com:8443/ubi8/httpd-24@sha256:b1e3...f876
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Assign the <code>latest</code> tag to a different image version. This operation simulates a developer who pushes a new version of an image and assigns the <code>latest</code> tag to that new image version.</p>
<ol>
<li><p>Use the <code>skopeo copy</code> command to add the <code>latest</code> tag to the image version that the <code>1-215</code> tag already references. The command automatically removes the <code>latest</code> tag from the earlier image.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ skopeo copy \
   docker://registry.ocp4.example.com:8443/ubi8/httpd-24:1-215 \
   docker://registry.ocp4.example.com:8443/ubi8/httpd-24:latest
 Getting image source signatures
 ...output omitted...
 Writing manifest to image destination
 Storing signatures
</code></pre>
</li>
<li><p>Log out from the classroom container registry.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ skopeo logout registry.ocp4.example.com:8443
 Removed login credentials for registry.ocp4.example.com:8443
</code></pre>
</li>
<li><p>Even though the <code>latest</code> tag is now referencing a different image version, OpenShift does not redeploy the pods that are running with the previous image version.</p>
<p> Rerun the <code>oc describe pod</code> command to confirm that the pod still uses the preceding image.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe pod httpd3-85b978d758-fvqdr
 ...output omitted...
 Containers:
   httpd-24:
     Container ID: cri-o://2cee...3a68
     Image:        registry.ocp4.example.com:8443/ubi8/httpd-24
     Image ID:     registry.ocp4.example.com:8443/ubi8/httpd-24@sha256:b1e3...f876
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Scale the <code>httpd3</code> deployment to two pods.</p>
<ol>
<li><p>Use the <code>oc scale</code> command to add a new pod to the deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/httpd3 --replicas 2
 deployment.apps/httpd3 scaled
</code></pre>
</li>
<li><p>List the pods to confirm that two pods are running for the <code>httpd3</code> deployment. The pod names probably differ on your system.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 httpd1-6dff796d99-pm2x6   1/1     Running   0          75m
 httpd2-998d9b9b9-5859j    1/1     Running   0          30m
 httpd3-85b978d758-f98jh   1/1     Running   0          54s
 httpd3-85b978d758-fvqdr   1/1     Running   0          11m
</code></pre>
</li>
<li><p>Retrieve the SHA image ID for the pod that the deployment initially created. The ID did not change. The container is still using the original image version.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe pod httpd3-85b978d758-fvqdr
 ...output omitted...
 Containers:
   httpd-24:
     Container ID: cri-o://2cee...3a68
     Image:        registry.ocp4.example.com:8443/ubi8/httpd-24
     Image ID:     registry.ocp4.example.com:8443/ubi8/httpd-24@sha256:b1e3...f876
 ...output omitted...
</code></pre>
</li>
<li><p>Retrieve the SHA image ID for the additional pod. Notice that the ID is different. The additional pod is using the image that the <code>latest</code> tag is currently referencing.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe pod httpd3-85b978d758-f98jh
 ...output omitted...
 Containers:
   httpd-24:
     Container ID: cri-o://d254...c893
     Image:        registry.ocp4.example.com:8443/ubi8/httpd-24
     Image ID:     registry.ocp4.example.com:8443/ubi8/httpd-24@sha256:91ad...fd83
 ...output omitted...
</code></pre>
<p> The state of the deployment is inconsistent. The two replicated pods use a different image version. Consequently, the scaled application might not behave correctly. Red Hat recommends that you use a less volatile tag than <code>latest</code> in production environments, or that you tightly control the tag assignments in your container registry.</p>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish updates-ids
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Lab: Configure Applications for Reliability]]></title><description><![CDATA[Deploy and troubleshoot a reliable application that defines health probes, compute resource requests, and compute resource limits so it can run N instances per node; and configure a horizontal pod autoscaler that will scale to a maximum of N instance...]]></description><link>https://syarif.kosasih.my.id/lab-configure-applications-for-reliability</link><guid isPermaLink="true">https://syarif.kosasih.my.id/lab-configure-applications-for-reliability</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:17:07 GMT</pubDate><content:encoded><![CDATA[<p>Deploy and troubleshoot a reliable application that defines health probes, compute resource requests, and compute resource limits so it can run N instances per node; and configure a horizontal pod autoscaler that will scale to a maximum of N instances.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to add resource requests to a <code>Deployment</code> object, configure probes, and create a horizontal pod autoscaler resource.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>reliability-review</code> project and deploys the <code>longload</code> application in that project.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start reliability-review
</code></pre>
<p><strong>Procedure 6.6. Instructions</strong></p>
<p>The API URL of your OpenShift cluster is <a target="_blank" href="https://api.ocp4.example.com:6443">https://api.ocp4.example.com:6443</a>, and the <code>oc</code> command is already installed on your <code>workstation</code> machine.</p>
<p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password.</p>
<p>Use the <code>reliability-review</code> project for your work.</p>
<ol>
<li><p>The <code>longload</code> application in the <code>reliability-review</code> project fails to start. Diagnose and then fix the issue. The application needs 512 MiB of memory to work.</p>
<p> After you fix the issue, you can confirm that the application works by running the <code>~/DO180/labs/reliability-review/curl_loop.sh</code> script that the <code>lab</code> command prepared. The script sends requests to the application in a loop. For each request, the script displays the pod name and the application status. Press <strong>Ctrl</strong>+<strong>C</strong> to quit the script.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>reliability-review</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project reliability-review
 ...output omitted...
</code></pre>
</li>
<li><p>List the pods in the project. The pod is in the <code>Pending</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 longload-64bf8dd776-b6rkz   0/1     Pending   0          8m1s
</code></pre>
</li>
<li><p>Retrieve the events for the pod. No compute node has enough memory to accommodate the pod.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe pod longload-64bf8dd776-b6rkz
 Name:             longload-64bf8dd776-b6rkz
 Namespace:        reliability-review
 ...output omitted...
 Events:
   Type     Reason            Age   From               Message
   ----     ------            ----  ----               -------
   Warning  FailedScheduling  8m    default-scheduler  0/1 nodes are available: 1 Insufficient memory. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.
</code></pre>
</li>
<li><p>Review the resource requests for memory. The <code>longload</code> deployment requests 8 GiB of memory.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get deployment longload -o \
   jsonpath='{.spec.template.spec.containers[0].resources.requests.memory}{"\n"}'
 8Gi
</code></pre>
</li>
<li><p>Set the memory requests to 512 MiB. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set resources deployment/longload \
   --requests memory=512Mi
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/longload resource requirements updated
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 longload-5897c9558f-cx4gt   1/1     Running   0          86s
</code></pre>
</li>
<li><p>Run the <code>~/DO180/labs/reliability-review/curl_loop.sh</code> script to confirm that the application works.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ ~/DO180/labs/reliability-review/curl_loop.sh
 1 curl: (7) Failed to connect to master01.ocp4.example.com port 30372: Connection refused
 2 longload-5897c9558f-cx4gt: app is still starting
 3 longload-5897c9558f-cx4gt: app is still starting
 4 longload-5897c9558f-cx4gt: app is still starting
 5 longload-5897c9558f-cx4gt: Ok
 6 longload-5897c9558f-cx4gt: Ok
 7 longload-5897c9558f-cx4gt: Ok
 8 longload-5897c9558f-cx4gt: Ok
 ...output omitted...
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the script.</p>
</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<ol>
<li><p>When the application scales up, your customers complain that some requests fail. To replicate the issue, manually scale up the <code>longload</code> application to three replicas, and run the <code>~/DO180/labs/reliability-review/curl_loop.sh</code> script at the same time.</p>
<p> The application takes seven seconds to initialize. The application exposes the <code>/health</code> API endpoint on HTTP port 3000. Configure the <code>longload</code> deployment to use this endpoint, to ensure that the application is ready before serving client requests.</p>
<ol>
<li><p>Open a new terminal window and run the <code>~/DO180/labs/reliability-review/curl_loop.sh</code> script.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ ~/DO180/labs/reliability-review/curl_loop.sh
 1 longload-5897c9558f-cx4gt: Ok
 2 longload-5897c9558f-cx4gt: Ok
 3 longload-5897c9558f-cx4gt: Ok
 4 longload-5897c9558f-cx4gt: Ok
 ...output omitted...
</code></pre>
<p> Leave the script running and do not interrupt it.</p>
</li>
<li><p>Scale up the application to three replicas.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/longload --replicas 3
 deployment.apps/longload scaled
</code></pre>
</li>
<li><p>Watch the output of the <code>curl_loop.sh</code> script in the second terminal. Some requests fail because OpenShift sends requests to the new pods before the application is ready.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 22 longload-5897c9558f-cx4gt: Ok
 23 longload-5897c9558f-cx4gt: Ok
 24 longload-5897c9558f-cx4gt: Ok
 25 curl: (7) Failed to connect to master01.ocp4.example.com port 30372: Connection refused
 26 curl: (7) Failed to connect to master01.ocp4.example.com port 30372: Connection refused
 27 longload-5897c9558f-cx4gt: Ok
 28 curl: (7) Failed to connect to master01.ocp4.example.com port 30372: Connection refused
 29 longload-5897c9558f-cx4gt: Ok
 30 curl: (7) Failed to connect to master01.ocp4.example.com port 30372: Connection refused
 31 longload-5897c9558f-tpssf: app is still starting
 32 longload-5897c9558f-kkvm5: app is still starting
 33 longload-5897c9558f-cx4gt: Ok
 34 longload-5897c9558f-tpssf: app is still starting
 35 longload-5897c9558f-tpssf: app is still starting
 36 longload-5897c9558f-tpssf: app is still starting
 37 longload-5897c9558f-cx4gt: Ok
 38 longload-5897c9558f-tpssf: app is still starting
 39 longload-5897c9558f-cx4gt: Ok
 40 longload-5897c9558f-cx4gt: Ok
 ...output omitted...
</code></pre>
<p> Leave the script running and do not interrupt it.</p>
</li>
<li><p>Add a readiness probe to the <code>longload</code> deployment. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set probe deployment/longload --readiness \
   --initial-delay-seconds 7 \
   --get-url http://:3000/health
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/longload probes updated
</code></pre>
</li>
<li><p>Scale down the application back to one pod.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/longload --replicas 1
 deployment.apps/longload scaled
</code></pre>
</li>
<li><p>To test your work, scale up the application to three replicas again.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/longload --replicas 3
 deployment.apps/longload scaled
</code></pre>
</li>
<li><p>Watch the output of the <code>curl_loop.sh</code> script in the second terminal. No request fails.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 92 longload-7ddcc9b7fd-72dtm: Ok
 93 longload-7ddcc9b7fd-72dtm: Ok
 94 longload-7ddcc9b7fd-72dtm: Ok
 95 longload-7ddcc9b7fd-qln95: Ok
 96 longload-7ddcc9b7fd-wrxrb: Ok
 97 longload-7ddcc9b7fd-qln95: Ok
 98 longload-7ddcc9b7fd-wrxrb: Ok
 99 longload-7ddcc9b7fd-72dtm: Ok
 ...output omitted...
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the script.</p>
</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<ol>
<li><p>Configure the application so that it automatically scales up when the average memory usage is above 60% of the memory requests value, and scales down when the usage is below this percentage. The minimum number of replicas must be one, and the maximum must be three. The resource that you create for scaling the application must be named <code>longload</code>.</p>
<p> The <code>lab</code> command provides the <code>~/DO180/labs/reliability-review/hpa.yml</code> resource file as an example. Use the <code>oc explain</code> command to learn the valid parameters for the <a target="_blank" href="http://hpa.spec.metrics.resource.target"><code>hpa.spec.metrics.resource.target</code></a> attribute. Because the file is incomplete, you must update it first if you choose to use it.</p>
<p> To test your work, use the <code>~/DO180/labs/reliability-review/allocate.sh</code> script that the <code>lab</code> command prepared. This script sends an HTTP request to the application <code>/﻿leak</code> API endpoint. Each request consumes an additional 480 MiB of memory. To free this memory, you can use the <code>~/DO180/labs/reliability-review/free.sh</code> script.</p>
<ol>
<li><p>Before you create the horizontal pod autoscaler resource, scale down the application to one pod.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/longload --replicas 1
 deployment.apps/longload scaled
</code></pre>
</li>
<li><p>Edit the <code>~/DO180/labs/reliability-review/hpa.yml</code> resource file. You can retrieve the parameters for the <code>resource</code> attribute by using the <code>oc explain hpa.spec.metrics.resource</code> and <code>oc explain</code> <a target="_blank" href="http://hpa.spec.metrics.resource.target"><code>hpa.spec.metrics.resource.target</code></a> commands.</p>
<pre><code class="lang-plaintext"> apiVersion: autoscaling/v2
 kind: HorizontalPodAutoscaler
 metadata:
   name: longload
   labels:
     app: longload
 spec:
   maxReplicas: 3
   minReplicas: 1
   scaleTargetRef:
     apiVersion: apps/v1
     kind: Deployment
     name: longload
   metrics:
   - type: Resource
     resource:
       name: memory
       target:
         type: Utilization
         averageUtilization: 60
</code></pre>
</li>
<li><p>Use the <code>oc apply</code> command to deploy the horizontal pod autoscaler.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc apply -f ~/DO180/labs/reliability-review/hpa.yml
 horizontalpodautoscaler.autoscaling/longload created
</code></pre>
</li>
<li><p>In the second terminal, run the <code>watch</code> command to monitor the <code>oc get hpa longload</code> command. Wait for the <code>longload</code> horizontal pod autoscaler to report usage in the <code>TARGETS</code> column. The percentage on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc get hpa longload
 Every 2.0s: oc get hpa longload            workstation: Fri Mar 10 05:15:34 2023

 NAME       REFERENCE             TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
 longload   Deployment/longload   13%/60%   1         3         1          75s
</code></pre>
<p> Leave the command running and do not interrupt it.</p>
</li>
<li><p>To test your work, run the <code>~/DO180/labs/reliability-review/allocate.sh</code> script in the first terminal for the application to allocate 480 MiB of memory.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ ~/DO180/labs/reliability-review/allocate.sh
 longload-7ddcc9b7fd-72dtm: consuming memory!
</code></pre>
</li>
<li><p>In the second terminal, after two minutes, the <code>oc get hpa longload</code> command shows the memory increase. The horizontal pod autoscaler scales up the application to more than one replica. The percentage on your system probably differs.</p>
<pre><code class="lang-plaintext"> Every 2.0s: oc get hpa longload            workstation: Fri Mar 10 05:19:44 2023

 NAME       REFERENCE             TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
 longload   Deployment/longload   145%/60%   1         3         2          5m18s
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command. Close that second terminal when done.</p>
</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Hide Solution</a></p>
<p><strong>Evaluation</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to grade your work. Correct any reported failures and rerun the command until successful.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab grade reliability-review
</code></pre>
<p><strong>Finish</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish reliability-review
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Application Autoscaling]]></title><description><![CDATA[Configure an autoscaler for an application and then load test that application to observe scaling up.
Outcomes
You should be able to manually scale up a deployment, configure a horizontal pod autoscaler resource, and monitor the autoscaler.
As the st...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-application-autoscaling</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-application-autoscaling</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:14:47 GMT</pubDate><content:encoded><![CDATA[<p>Configure an autoscaler for an application and then load test that application to observe scaling up.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to manually scale up a deployment, configure a horizontal pod autoscaler resource, and monitor the autoscaler.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>reliability-autoscaling</code> project.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start reliability-autoscaling
</code></pre>
<p><strong>Procedure 6.5. Instructions</strong></p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>reliability-autoscaling</code> project.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>reliability-autoscaling</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project reliability-autoscaling
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>loadtest</code> deployment, service, and route. The deployment uses the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/loadtest:v1.0"><code>registry.ocp4.example.com:8443/redhattraining/loadtest:v1.0</code></a> container image that provides a web application. The web application exposes an API endpoint that creates a CPU-intensive task when queried.</p>
<ol>
<li><p>Review the <code>~/DO180/labs/reliability-autoscaling/loadtest.yml</code> resource file that the <code>lab</code> command prepared. The container specification does not include the <code>resources</code> section that you use to specify CPU requests and limits. You configure that section in another step. Do not change the file for now.</p>
<pre><code class="lang-plaintext"> apiVersion: v1
 kind: List
 metadata: {}
 items:
   - apiVersion: apps/v1
     kind: Deployment
 ...output omitted...
         spec:
           containers:
           - image: registry.ocp4.example.com:8443/redhattraining/loadtest:v1.0
             name: loadtest
             readinessProbe:
               failureThreshold: 3
               httpGet:
                 path: /api/loadtest/v1/healthz
                 port: 8080
                 scheme: HTTP
               periodSeconds: 10
               successThreshold: 1
               timeoutSeconds: 1

   - apiVersion: v1
     kind: Service
 ...output omitted...

   - apiVersion: route.openshift.io/v1
     kind: Route
 ...output omitted...
</code></pre>
</li>
<li><p>Use the <code>oc apply</code> command to create the application. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc apply -f \
 ~/DO180/labs/reliability-autoscaling/loadtest.yml
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/loadtest created
 service/loadtest created
 route.route.openshift.io/loadtest created
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                       READY   STATUS    RESTARTS   AGE
 loadtest-65c55b7dc-r4s4s   1/1     Running   0          49s
</code></pre>
</li>
</ol>
</li>
<li><p>Configure a horizontal pod autoscaler resource for the <code>loadtest</code> deployment. Set the minimum number of replicas to 2 and the maximum to 20. Set the average CPU usage to 50% of the CPU requests attribute.</p>
<p> The horizontal pod autoscaler does not work, because the <code>loadtest</code> deployment does not specify requests for CPU usage.</p>
<ol>
<li><p>Use the <code>oc autoscale</code> command to create the horizontal pod autoscaler resource.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc autoscale deployment/loadtest --min 2 --max 20 \
 --cpu-percent 50
 horizontalpodautoscaler.autoscaling/loadtest autoscaled
</code></pre>
</li>
<li><p>Retrieve the status of the <code>loadtest</code> horizontal pod autoscaler resource. The <code>unknown</code> value in the <code>TARGETS</code> column indicates that OpenShift cannot compute the current CPU usage of the <code>loadtest</code> deployment. The deployment must include the CPU requests attribute for OpenShift to be able to compute the CPU usage.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get hpa loadtest
 NAME      REFERENCE            TARGETS         MINPODS  MAXPODS   REPLICAS   AGE
 loadtest  Deployment/loadtest  &lt;unknown&gt;/50%   2        20        2          74s
</code></pre>
</li>
<li><p>Get more details about the resource status. You might have to rerun the command several times. Wait three minutes for the command to report the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc describe hpa loadtest
 Warning: autoscaling/v2beta2 HorizontalPodAutoscaler is deprecated in v1.23+, unavailable in v1.26+; use autoscaling/v2 HorizontalPodAutoscaler
 Name:                                                  loadtest
 Namespace:                                             reliability-autoscaling
 ...output omitted...
 Conditions:
   Type           Status  Reason                   Message
   ----           ------  ------                   -------
   AbleToScale    True    SucceededGetScale        the HPA controller was able to get the target's current scale
   ScalingActive  False   FailedGetResourceMetric  the HPA was unable to compute the replica count: failed to get cpu utilization: missing request for cpu
 Events:
   Type     ... Message
   ----     ... -------
 ...output omitted...
   Warning  ... failed to get cpu utilization: missing request for cpu
 ...output omitted...
</code></pre>
</li>
<li><p>Delete the horizontal pod autoscaler resource. You re-create the resource in another step, after you fix the <code>loadtest</code> deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc delete hpa loadtest
 horizontalpodautoscaler.autoscaling "loadtest" deleted
</code></pre>
</li>
<li><p>Delete the <code>loadtest</code> application.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc delete all -l app=loadtest
 pod "loadtest-65c55b7dc-r4s4s" deleted
 pod "loadtest-65c55b7dc-mgqr6" deleted
 service "loadtest" deleted
 deployment.apps "loadtest" deleted
 replicaset.apps "loadtest-65c55b7dc" deleted
 route.route.openshift.io "loadtest" deleted
</code></pre>
</li>
</ol>
</li>
<li><p>Add a CPU resource section to the <code>~/DO180/labs/reliability-autoscaling/loadtest.yml</code> file. Redeploy the application from the file.</p>
<ol>
<li><p>Edit the <code>~/DO180/labs/reliability-autoscaling/loadtest.yml</code> file, and configure the CPU limits and requests for the <code>loadtest</code> deployment. The pods need 25 millicores to operate, and must not consume more that 100 millicores.</p>
<p> You can compare your work with the completed <code>~/DO180/solutions/reliability-autoscaling/loadtest.yml</code> file that the <code>lab</code> command prepared.</p>
<pre><code class="lang-plaintext"> ...output omitted...
         spec:
           containers:
           - image: registry.ocp4.example.com:8443/redhattraining/loadtest:v1.0
             name: loadtest
             readinessProbe:
               failureThreshold: 3
               httpGet:
                 path: /api/loadtest/v1/healthz
                 port: 8080
                 scheme: HTTP
               periodSeconds: 10
               successThreshold: 1
               timeoutSeconds: 1
             resources:
               requests:
                 cpu: 25m
               limits:
                 cpu: 100m
 ...output omitted...
</code></pre>
</li>
<li><p>Use the <code>oc apply</code> command to deploy the application from the file. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc apply -f \
 ~/DO180/labs/reliability-autoscaling/loadtest.yml
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/loadtest created
 service/loadtest created
 route.route.openshift.io/loadtest created
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 loadtest-667bdcdc99-vhc9x   1/1     Running   0          36s
</code></pre>
</li>
</ol>
</li>
<li><p>Manually scale the <code>loadtest</code> deployment by first increasing and then decreasing the number of running pods.</p>
<ol>
<li><p>Scale up the <code>loadtest</code> deployment to five pods.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/loadtest --replicas 5
 deployment.apps/loadtest scaled
</code></pre>
</li>
<li><p>Confirm that all five application pods are running. You might have to rerun the command several times for all the pods to report a <code>Running</code> status. The name of the pods on your system probably differ.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 loadtest-667bdcdc99-5fcvh   1/1     Running   0          43s
 loadtest-667bdcdc99-dpspr   1/1     Running   0          42s
 loadtest-667bdcdc99-hkssk   1/1     Running   0          43s
 loadtest-667bdcdc99-vhc9x   1/1     Running   0          8m11s
 loadtest-667bdcdc99-z5n9q   1/1     Running   0          43s
</code></pre>
</li>
<li><p>Scale down the <code>loadtest</code> deployment back to one pod.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc scale deployment/loadtest --replicas 1
 deployment.apps/loadtest scaled
</code></pre>
</li>
<li><p>Confirm that only one application pod is running. You might have to rerun the command several times for the pods to terminate.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 loadtest-667bdcdc99-vhc9x   1/1     Running   0          11m
</code></pre>
</li>
</ol>
</li>
<li><p>Configure a horizontal pod autoscaler resource for the <code>loadtest</code> deployment. Set the minimum number of replicas to 2 and the maximum to 20. Set the average CPU usage to 50% of the CPU request attribute.</p>
<ol>
<li><p>Use the <code>oc autoscale</code> command to create the horizontal pod autoscaler resource.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc autoscale deployment/loadtest --min 2 --max 20 \
 --cpu-percent 50
 horizontalpodautoscaler.autoscaling/loadtest autoscaled
</code></pre>
</li>
<li><p>Open a new terminal window and run the <code>watch</code> command to monitor the <code>oc get hpa loadtest</code> command. Wait five minutes for the <code>loadtest</code> horizontal pod autoscaler to report usage in the <code>TARGETS</code> column.</p>
<p> Notice that the horizontal pod autoscaler scales up the deployment to two replicas, to conform with the minimum number of pods that you configured.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc get hpa loadtest
 Every 2.0s: oc get hpa loadtest            workstation: Fri Mar  3 06:26:24 2023

 NAME       REFERENCE             TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
 loadtest   Deployment/loadtest   0%/50%    2         20        2          52s
</code></pre>
<p> Leave the command running, and do not interrupt it.</p>
</li>
</ol>
</li>
<li><p>Increase the CPU usage by sending requests to the <code>loadtest</code> application API.</p>
<ol>
<li><p>Use the <code>oc get route</code> command to retrieve the URL of the application.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get route loadtest
 NAME       HOST/PORT                                                ...
 loadtest   loadtest-reliability-autoscaling.apps.ocp4.example.com   ...
</code></pre>
</li>
<li><p>Send a request to the application API to simulate additional CPU pressure on the container. Do not wait for the <code>curl</code> command to complete, and continue with the exercise. After a minute, the command reports a timeout error that you can ignore.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ curl \
 loadtest-reliability-autoscaling.apps.ocp4.example.com/api/loadtest/v1/cpu/1
 &lt;html&gt;&lt;body&gt;&lt;h1&gt;504 Gateway Time-out&lt;/h1&gt;
 The server didn't respond in time.
 &lt;/body&gt;&lt;/html&gt;
</code></pre>
</li>
<li><p>Watch the output of the <code>oc get hpa loadtest</code> command in the second terminal. After a minute, the horizontal pod autoscaler detects an increase in the CPU usage and deploys additional pods.</p>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> The increased activity of the application does not immediately trigger the autoscaler. Wait a few moments if you do not see any changes to the number of replicas.</p>
<p> You might need to run the <code>curl</code> command multiple times before the application uses enough CPU to trigger the autoscaler.</p>
<p> The CPU usage and the number of replicas on your system probably differ.</p>
<pre><code class="lang-plaintext"> Every 2.0s: oc get hpa loadtest            workstation: Fri Mar  3 07:20:19 2023

 NAME      REFERENCE             TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
 loadtest  Deployment/loadtest   220%/50%   2         20        9          16m
</code></pre>
</li>
<li><p>Wait five minutes after the <code>curl</code> command completes. The <code>oc get hpa loadtest</code> command shows that the CPU load decreases.</p>
<h3 id="heading-note-1"><strong>NOTE</strong></h3>
<p> Although the horizontal pod autoscaler resource can be quick to scale up, it is slower to scale down.</p>
<pre><code class="lang-plaintext"> Every 2.0s: oc get hpa loadtest            workstation: Fri Mar  3 07:23:11 2023

 NAME      REFERENCE             TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
 loadtest  Deployment/loadtest   0%/50%    2         20        9          18m
</code></pre>
</li>
<li><p><strong>Optional</strong>: Wait for the <code>loadtest</code> application to scale down. It takes five additional minutes for the horizontal pod autoscaler to scale down to two replicas.</p>
<pre><code class="lang-plaintext"> Every 2.0s: oc get hpa loadtest            workstation: Fri Mar  3 07:29:12 2023

 NAME      REFERENCE             TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
 loadtest  Deployment/loadtest   0%/50%    2         20        2          24m
</code></pre>
</li>
<li><p>Press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command. Close that second terminal when done.</p>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish reliability-autoscaling
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Limit Compute Capacity for Applications]]></title><description><![CDATA[Configure an application with compute resource limits that allow and prevent successful execution of its pods.
Outcomes
You should be able to monitor the memory usage of an application, and set a memory limit for a pod.
As the student user on the wor...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-limit-compute-capacity-for-applications</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-limit-compute-capacity-for-applications</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:10:59 GMT</pubDate><content:encoded><![CDATA[<p>Configure an application with compute resource limits that allow and prevent successful execution of its pods.</p>
<p><strong>Outcomes</strong></p>
<p>You should be able to monitor the memory usage of an application, and set a memory limit for a pod.</p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that all resources are available for this exercise. It also creates the <code>reliability-limits</code> project and the <code>/home/student/DO180/labs/reliability-limits/resources.txt</code> file. The <code>resources.txt</code> file contains some commands that you use during the exercise. You can use the file to copy and paste these commands.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start reliability-limits
</code></pre>
<p><strong>Procedure 6.4. Instructions</strong></p>
<ol>
<li><p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password. Use the <code>reliability-limits</code> project.</p>
<ol>
<li><p>Log in to the OpenShift cluster.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
   https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Set the <code>reliability-limits</code> project as the active project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project reliability-limits
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Create the <code>leakapp</code> deployment from the <code>~/DO180/labs/reliability-limits/leakapp.yml</code> file that the <code>lab</code> command prepared. The application has a bug, and leaks 1 MiB of memory every second.</p>
<ol>
<li><p>Review the <code>~/DO180/labs/reliability-limits/leakapp.yml</code> resource file. The memory limit is set to 35 MiB. Do not change the file.</p>
<pre><code class="lang-plaintext"> ...output omitted...
         resources:
           requests:
             memory: 20Mi
           limits:
             memory: 35Mi
</code></pre>
</li>
<li><p>Use the <code>oc apply</code> command to create the application. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc apply -f \
   ~/DO180/labs/reliability-limits/leakapp.yml
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/leakapp created
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                      READY   STATUS    RESTARTS   AGE
 leakapp-99bb64c8d-hk26k   1/1     Running   0          12s
</code></pre>
</li>
</ol>
</li>
<li><p>Watch the pod. OpenShift restarts the pod after 30 seconds.</p>
<ol>
<li><p>Use the <code>watch</code> command to monitor the <code>oc get pods</code> command. Wait for OpenShift to restart the pod, and then press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc get pods
 Every 2.0s: oc get pods                    workstation: Wed Mar  8 07:27:45 2023

 NAME                      READY   STATUS    RESTARTS      AGE
 leakapp-99bb64c8d-hk26k   1/1     Running   1 (15s ago)   48s
</code></pre>
</li>
<li><p>Retrieve the container status to verify that OpenShift restarted the pod due to an Out-Of-Memory (OOM) event.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods leakapp-99bb64c8d-hk26k \
   -o jsonpath='{.status.containerStatuses[0].lastState}' | jq .
 {
   "terminated": {
     "containerID": "cri-o://5800...1d04",
     "exitCode": 137,
     "finishedAt": "2023-03-08T12:29:24Z",
     "reason": "OOMKilled",
     "startedAt": "2023-03-08T12:28:53Z"
   }
 }
</code></pre>
</li>
</ol>
</li>
<li><p>Observe the pod status for a few minutes, until the <code>CrashLoopBackOff</code> status is displayed. During this period, OpenShift restarts the pod several times because of the memory leak.</p>
<p> Between each restart, OpenShift sets the pod status to <code>CrashLoopBackOff</code>, waits an increasing amount of time between retries, and then restarts the pod. The delay between restarts gives the operator the opportunity to fix the issue.</p>
<p> After various retries, OpenShift finally sets the <code>CrashLoopBackOff</code> wait timer to five minutes. During this wait time, the application is not available to your customers.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc get pods
 Every 2.0s: oc get pods                    workstation: Wed Mar  8 07:33:15 2023

 NAME                      READY   STATUS             RESTARTS      AGE
 leakapp-99bb64c8d-hk26k   0/1     CrashLoopBackOff   4 (82s ago)   5m25s
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command.</p>
</li>
<li><p>Fixing the memory leak would resolve the issue. However, it might take some time for the developers to fix the bug. In the meantime, set the memory limit to 600 MiB. With this setting, the pod can run for ten minutes before the application reaches the limit.</p>
<ol>
<li><p>Use the <code>oc set resources</code> command to set the new limit. Ignore the warning message.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc set resources deployment/leakapp \
   --limits memory=600Mi
 Warning: would violate PodSecurity "restricted:v1.24":
 ...output omitted...
 deployment.apps/leakapp resource requirements updated
</code></pre>
</li>
<li><p>Wait for the pod to start. You might have to rerun the command several times for the pod to report a <code>Running</code> status. The name of the pod on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc get pods
 NAME                      READY   STATUS    RESTARTS   AGE
 leakapp-6bc64dfcd-86fpc   1/1     Running   0          12s
</code></pre>
</li>
<li><p>Wait two minutes to verify that OpenShift no longer restarts the pod every 30 seconds.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc get pods
 Every 2.0s: oc get pods                    workstation: Wed Mar  8 07:38:15 2023

 NAME                      READY   STATUS    RESTARTS   AGE
 leakapp-6bc64dfcd-86fpc   1/1     Running   0          3m12s
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command.</p>
</li>
</ol>
</li>
<li><p>Review the memory that the pod consumes. You might have to rerun the command several times for the metrics to be available. The memory usage on your system probably differs.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc adm top pods
 NAME                      CPU(cores)   MEMORY(bytes)
 leakapp-6bc64dfcd-86fpc   0m           174Mi
</code></pre>
</li>
<li><p><strong>Optional</strong>. Wait seven more minutes. After this period, OpenShift restarts the pod, because it reached the 600 MiB memory limit.</p>
<ol>
<li><p>Open a new terminal window, and then run the <code>watch</code> command to monitor the <code>oc adm top pods</code> command.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc adm top pods
 Every 2.0s: oc adm top pods                workstation: Wed Mar  8 07:38:55 2023

 NAME                      CPU(cores)   MEMORY(bytes)
 leakapp-6bc64dfcd-86fpc   0m           176Mi
</code></pre>
<p> Leave the command running and do not interrupt it.</p>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> You might see a message that metrics are not yet available. If so, wait some time and try again.</p>
</li>
<li><p>In the first terminal, run the <code>watch</code> command to monitor the <code>oc get pods</code> command. Watch the output of the <code>oc adm top pods</code> command in the second terminal. When the memory usage reaches 600 MiB, the OOM subsystem kills the process inside the container, and OpenShift restarts the pod.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ watch oc get pods
 Every 2.0s: oc get pods                    workstation: Wed Mar  8 07:46:35 2023

 NAME                      READY   STATUS    RESTARTS     AGE
 leakapp-6bc64dfcd-86fpc   1/1     Running   1 (3s ago)   9m58s
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command.</p>
</li>
<li><p>Press <strong>Ctrl</strong>+<strong>C</strong> to quit the <code>watch</code> command in the second terminal. Close this second terminal when done.</p>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish reliability-limits
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Reserve Compute Capacity for Applications]]></title><description><![CDATA[Configure an application with compute resource requests that allow and prevent successful scheduling and scaling of its pods.
Outcomes

Observe that memory resource requests allocate cluster node memory.

Explore how adjusting resource requests impac...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-reserve-compute-capacity-for-applications</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-reserve-compute-capacity-for-applications</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:08:57 GMT</pubDate><content:encoded><![CDATA[<p>Configure an application with compute resource requests that allow and prevent successful scheduling and scaling of its pods.</p>
<p><strong>Outcomes</strong></p>
<ul>
<li><p>Observe that memory resource requests allocate cluster node memory.</p>
</li>
<li><p>Explore how adjusting resource requests impacts the number of replicas that can be scheduled on a node.</p>
</li>
</ul>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that the following conditions are true:</p>
<ul>
<li><p>The <code>reliability-requests</code> project exists.</p>
</li>
<li><p>The resource files are available in the course directory.</p>
</li>
<li><p>The classroom registry has the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/long-load:v1"><code>registry.ocp4.example.com:8443/redhattraining/long-load:v1</code></a> container image.</p>
</li>
</ul>
<p>The <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/long-load:v1"><code>registry.ocp4.example.com:8443/redhattraining/long-load:v1</code></a> container image contains an application with utility endpoints. These endpoints perform such tasks as crashing the process and toggling the server's health status.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start reliability-requests
</code></pre>
<p><strong>Procedure 6.3. Instructions</strong></p>
<ol>
<li><p>As the <code>admin</code> user, deploy the <code>long-load</code> application by applying the <code>long-load-deploy.yaml</code> file in the <code>reliability-requests</code> project.</p>
<ol>
<li><p>Log in as the <code>admin</code> user with the <code>redhatocp</code> password.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login https://api.ocp4.example.com:6443 -u admin
 ...output omitted...
</code></pre>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> In general, use accounts with the least required privileges to perform a task. In the classroom environment, this account is the <code>developer</code> user. However, cluster administrator privileges are required to view the cluster node metrics in this exercise.</p>
</li>
<li><p>Select the <code>reliability-requests</code> project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project reliability-requests
 Now using project "reliability-requests" on server "https://api.ocp4.example.com:6443".
</code></pre>
</li>
<li><p>Navigate to the <code>~/DO180/labs/reliability-requests</code> directory. Create a deployment, service, and route by using the <code>oc apply</code> command and the <code>long-load-deploy.yaml</code> file.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ cd DO180/labs/reliability-requests
 no output expected
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc apply -f long-load-deploy.yaml
 deployment.apps/long-load created
 service/long-load created
 route.route.openshift.io/long-load created
</code></pre>
</li>
<li><p>View the total memory request allocation for the node.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc describe nodes
 ...output omitted...
 Allocated resources:
   (Total limits may be over 100 percent, i.e., overcommitted.)
   Resource           Requests       Limits
   --------           --------       ------
   cpu                3158m (42%)    980m (13%)
   memory             12667Mi (66%)  1250Mi (6%)
 ...output omitted...
</code></pre>
<h3 id="heading-important"><strong>IMPORTANT</strong></h3>
<p> Projects and objects from previous exercises can cause the memory usage from this exercise to mismatch the intended results. Delete any unrelated projects before continuing.</p>
<p> If you still experience issues, re-create your classroom environment and try this exercise again.</p>
</li>
</ol>
</li>
<li><p>Add a resource request to the pod definition and scale the deployment beyond the cluster's capacity.</p>
<ol>
<li><p>Modify the <code>long-load-deploy.yaml</code> file by adding a resource request. The request allocates one gigabyte (1 G) to each of the application pods.</p>
<pre><code class="lang-plaintext"> spec:
   ...output omitted...
   template:
   ...output omitted...
     spec:
       containers:
       - image: registry.ocp4.example.com:8443/redhattraining/long-load:v1
         resources:
           requests:
             memory: 1G
 ...output omitted...
</code></pre>
</li>
<li><p>Apply the YAML file to modify the deployment with the resource request.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc apply -f long-load-deploy.yaml
 deployment.apps/long-load configured
 service/long-load unchanged
 route.route.openshift.io/long-load configured
</code></pre>
</li>
<li><p>Scale the deployment to have 10 replicas.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc scale deploy/long-load --replicas 10
 deployment.apps/long-load scaled
</code></pre>
</li>
<li><p>Observe that the cluster cannot schedule all of the pods on the single node. The pods with a <code>Pending</code> status cannot be scheduled.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc get pods
 NAME                         READY   STATUS    RESTARTS   AGE
 ...output omitted...
 long-load-86bb4b79f8-44zwd   0/1     Pending   0          58s
 ...output omitted...
</code></pre>
</li>
<li><p>Retrieve the cluster event log, and observe that insufficient memory is the cause of the failed scheduling.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc get events \
   --field-selector reason="FailedScheduling"
 ...output omitted... pod/long-load-86bb4b79f8-44zwd   0/1 nodes are available: 1 Insufficient memory. ...output omitted...
</code></pre>
</li>
<li><p>Alternatively, view the events for a pending pod to see the reason. In the following command, replace the pod name with one of the pending pods in your classroom.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc describe \
   pod/long-load-86bb4b79f8-44zwd
 ...output omitted...
 Events:
 ...output omitted...  0/1 nodes are available: 1 Insufficient memory. ...output omitted...
</code></pre>
</li>
<li><p>Observe that the node's requested memory usage is high.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc describe nodes
 ...output omitted...
 Allocated resources:
   (Total limits may be over 100 percent, i.e., overcommitted.)
   Resource           Requests          Limits
   --------           --------          ------
   cpu                3158m (42%)       980m (13%)
   memory             18830383Ki (97%)  1250Mi (6%)
 ...output omitted...
</code></pre>
</li>
</ol>
</li>
<li><p>Reduce the requested memory per pod so that the replicas can run on the node.</p>
<ol>
<li><p>Manually set the resource request to <code>250M</code>.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc set resources deploy/long-load \
   --requests memory=250M
 deployment.apps/long-load resource requirements updated
</code></pre>
</li>
<li><p>Delete the pods so that they are re-created with the new resource request.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc delete pod -l app=long-load
 pod "long-load-557b4d94f5-29brx" deleted
 ...output omitted...
</code></pre>
</li>
<li><p>Observe that all of the pods can start with the lowered memory request. Within a minute, the pods are marked as <code>Ready</code> and in a <code>Running</code> state, with no pods in a <code>Pending</code> status.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc get pods
 NAME                         READY   STATUS    RESTARTS   AGE
 long-load-557b4d94f5-68hbb   1/1     Running   0          3m14s
 long-load-557b4d94f5-bfk7c   1/1     Running   0          3m21s
 long-load-557b4d94f5-bnpzh   1/1     Running   0          3m21s
 long-load-557b4d94f5-chtv9   1/1     Running   0          3m21s
 long-load-557b4d94f5-drg2p   1/1     Running   0          3m14s
 long-load-557b4d94f5-hwsz6   1/1     Running   0          3m12s
 long-load-557b4d94f5-k5vqj   1/1     Running   0          3m21s
 long-load-557b4d94f5-lgstq   1/1     Running   0          3m21s
 long-load-557b4d94f5-r8hq4   1/1     Running   0          3m21s
 long-load-557b4d94f5-xrg7c   1/1     Running   0          3m21s
</code></pre>
</li>
<li><p>Observe that the memory usage of the node is lower.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ oc describe nodes
 Allocated resources:
   (Total limits may be over 100 percent, i.e., overcommitted.)
   Resource           Requests           Limits
   --------           --------           ------
   cpu                3158m (42%)        980m (13%)
   memory             15782312192 (79%)  1250Mi (6%)
 ...output omitted...
</code></pre>
</li>
<li><p>Return to the <code>/home/student/</code> directory.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-requests]$ cd /home/student/
 [student@workstation ~]$
</code></pre>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish reliability-requests
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Application Health Probes]]></title><description><![CDATA[Configure health probes in a deployment and verify that network clients are insulated from application failures.
Outcomes

Observe potential issues with an application that is not configured with health probes.

Configure startup, liveness, and readi...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-application-health-probes</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-application-health-probes</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:08:12 GMT</pubDate><content:encoded><![CDATA[<p>Configure health probes in a deployment and verify that network clients are insulated from application failures.</p>
<p><strong>Outcomes</strong></p>
<ul>
<li><p>Observe potential issues with an application that is not configured with health probes.</p>
</li>
<li><p>Configure startup, liveness, and readiness probes for the application.</p>
</li>
</ul>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that the following conditions are true:</p>
<ul>
<li><p>The <code>reliability-probes</code> project exists.</p>
</li>
<li><p>The resource files are available in the course directory.</p>
</li>
<li><p>The classroom registry has the <code>long-load</code> container image.</p>
</li>
</ul>
<p>The <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/long-load:v1"><code>registry.ocp4.example.com:8443/redhattraining/long-load:v1</code></a> container image contains an application with utility endpoints. These endpoints perform such tasks as crashing the process and toggling the server's health status.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start reliability-probes
</code></pre>
<p><strong>Procedure 6.2. Instructions</strong></p>
<ol>
<li><p>As the <code>developer</code> user, deploy the <code>long-load</code> application in the <code>reliability-probes</code> project.</p>
<ol>
<li><p>Log in as the <code>developer</code> user with the <code>developer</code> password.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login -u developer -p developer \
 https://api.ocp4.example.com:6443
 Login successful.
 ...output omitted...
</code></pre>
</li>
<li><p>Select the <code>reliability-probes</code> project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project reliability-probes
 Now using project "reliability-probes" on server "https://api.ocp4.example.com:6443".
</code></pre>
</li>
<li><p>Navigate to the <code>DO180/labs/reliability-probes</code> directory and then apply the <code>long-load-deploy.yaml</code> file to create the pod. Move to the next step within one minute.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ cd DO180/labs/reliability-probes
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc apply -f long-load-deploy.yaml
 deployment.apps/long-load created
 service/long-load created
 route.route.openshift.io/long-load created
</code></pre>
</li>
<li><p>Verify that the pods take several minutes to start by sending a request to a pod in the deployment.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc exec deploy/long-load -- \
   curl -s localhost:3000/health
 app is still starting
</code></pre>
</li>
<li><p>Observe that the pods are listed as ready even though the application is not ready.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc get pods
 NAME                         READY   STATUS    RESTARTS   AGE
 long-load-8564d998cc-579nx   1/1     Running   0          30s
 long-load-8564d998cc-ttqpg   1/1     Running   0          30s
 long-load-8564d998cc-wjtfw   1/1     Running   0          30s
</code></pre>
</li>
</ol>
</li>
<li><p>Add a startup probe to the pods so that the cluster knows when the pods are ready.</p>
<ol>
<li><p>Modify the <code>long-load-deploy.yaml</code> YAML file by defining a startup probe. The probe runs every three seconds and triggers a pod as failed after 30 failed attempts. The file should match the following excerpt:</p>
<pre><code class="lang-plaintext"> ...output omitted...
 spec:
   ...output omitted...
   template:
     ...output omitted...
     spec:
       containers:
       - image: registry.ocp4.example.com:8443/redhattraining/long-load:v1
         imagePullPolicy: Always
         name: long-load
         startupProbe:
           failureThreshold: 30
           periodSeconds: 3
           httpGet:
             path: /health
             port: 3000
         env:
 ...output omitted...
</code></pre>
</li>
<li><p>Scale down the deployment to zero replicas.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc scale deploy/long-load --replicas 0
 deployment.apps/long-load scaled
</code></pre>
</li>
<li><p>Apply the updated <code>long-load-deploy.yaml</code> file. Because the YAML file specifies the number of replicas, the deployment is scaled up. Move to the next step within one minute.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes] oc apply -f long-load-deploy.yaml
 deployment.apps/long-load configured
 service/long-load unchanged
 route.route.openshift.io/long-load configured
</code></pre>
</li>
<li><p>Observe that the pods do not show as ready until the application is ready and the startup probe succeeds.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc get pods
 NAME                         READY   STATUS    RESTARTS   AGE
 long-load-785b5b4fc8-7x5ln   0/1     Running   0          27s
 long-load-785b5b4fc8-f7pdk   0/1     Running   0          27s
 long-load-785b5b4fc8-r2nqj   0/1     Running   0          27s
</code></pre>
</li>
</ol>
</li>
<li><p>Add a liveness probe so that broken instances of the application are restarted.</p>
<ol>
<li><p>Start the load test script. The test begins to print <code>Ok</code> as the pods become available.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ ./load-test.sh
 app is still starting
 app is still starting
 app is still starting
 ...output omitted...
 Ok
 Ok
 Ok
 ...output omitted...
</code></pre>
<p> Keep the script running in a visible window.</p>
</li>
<li><p>In a new terminal window, use the <code>/togglesick</code> endpoint to make one of the pods unhealthy.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc exec \
   deploy/long-load -- curl -s localhost:3000/togglesick
 no output expected
</code></pre>
<p> The load test window begins to show <code>app is unhealthy</code>. Because only one pod is unhealthy, the remaining pods still respond with <code>Ok</code>.</p>
</li>
<li><p>Update the <code>long-load-deploy.yaml</code> file to add a liveness probe. The probe runs every three seconds and triggers the pod as failed after three failed attempts. Modify the <code>spec.template.spec.containers</code> object in the file to match the following excerpt.</p>
<pre><code class="lang-plaintext"> spec:
   ...output omitted...
   template:
     ...output omitted...
     spec:
       containers:
       - image: registry.ocp4.example.com:8443/redhattraining/long-load:v1
         ...output omitted...
         startupProbe:
           failureThreshold: 30
           periodSeconds: 3
           httpGet:
             path: /health
             port: 3000
         livenessProbe:
           failureThreshold: 3
           periodSeconds: 3
           httpGet:
             path: /health
             port: 3000
         env:
 ...output omitted...
</code></pre>
</li>
<li><p>Scale down the deployment to zero replicas.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc scale deploy/long-load --replicas 0
 deployment.apps/long-load scaled
</code></pre>
<p> The load test script shows that the application is not available.</p>
</li>
<li><p>Apply the updated <code>long-load-deploy.yaml</code> file to update the deployment, which triggers the deployment to re-create its pods.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc apply -f long-load-deploy.yaml
 deployment.apps/long-load configured
 service/long-load unchanged
 route.route.openshift.io/long-load configured
</code></pre>
</li>
<li><p>Wait for the load test window to show <code>Ok</code> for all responses, and then toggle one of the pods to be unhealthy.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc exec \
   deploy/long-load -- curl -s localhost:3000/togglesick
 no output expected
</code></pre>
<p> The load test window might show <code>app is unhealthy</code> a number of times before the pod is restarted.</p>
</li>
<li><p>Observe that the unhealthy pod is restarted after the liveness probe fails. After the pod is restarted, the load test window shows only <code>Ok</code>.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc get pods
 NAME                        READY   STATUS    RESTARTS       AGE
 long-load-fbb7468d9-8xm8j   1/1     Running   0              9m42s
 long-load-fbb7468d9-k66dm   1/1     Running   0              8m38s
 long-load-fbb7468d9-ncxkh   0/1     Running   1 (11s ago)    10m
</code></pre>
</li>
</ol>
</li>
<li><p>Add a readiness probe so that traffic goes only to pods that are ready and healthy.</p>
<ol>
<li><p>Scale down the deployment to zero replicas.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc scale deploy/long-load --replicas 0
 deployment.apps/long-load scaled
</code></pre>
</li>
<li><p>Use the <code>oc set probe</code> command to add the readiness probe.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc set probe deploy/long-load --readiness \
   --failure-threshold 1 --period-seconds 3 \
   --get-url http://:3000/health
 deployment.apps/long-load probes updated
</code></pre>
</li>
<li><p>Scale up the deployment to three replicas.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc scale deploy/long-load --replicas 3
 deployment.apps/long-load scaled
</code></pre>
</li>
<li><p>Observe the status of the pods by using a <code>watch</code> command.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ watch oc get pods
 NAME                        READY   STATUS    RESTARTS   AGE
 long-load-d5794d744-8hqlh   0/1     Running   0          48s
 long-load-d5794d744-hphgb   0/1     Running   0          48s
 long-load-d5794d744-lgkns   0/1     Running   0          48s
</code></pre>
<p> The command does not immediately finish, but continues to show updates to the pods' status. Leave this command running in a visible window.</p>
</li>
<li><p>Wait for the pods to show as ready. Then, in a new terminal window, make one of the pods unhealthy for five seconds by using the <code>/hiccup</code> endpoint.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ oc exec \
   deploy/long-load -- curl -s localhost:3000/hiccup?time=5
 no output expected
</code></pre>
<p> The pod status window shows that one of the pods is no longer ready. After five seconds, the pod is healthy again and shows as ready.</p>
<p> The load test window might show <code>app is unhealthy</code> one time before the pod is set as not ready. After the cluster determines that the pod is no longer ready, it stops sending traffic to the pod until either the pod is fixed or the liveness probe fails. Because the pod is sick only for five seconds, it is enough time for the readiness probe to fail, but not the liveness probe.</p>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> Optionally, repeat this step and observe as the temporarily sick pod's status changes.</p>
</li>
<li><p>Stop the load test and status commands by pressing <strong>Ctrl</strong>+<strong>c</strong> in their respective windows. Return to the <code>/home/student/</code> directory.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-probes]$ cd /home/student/
 [student@workstation ~]$
</code></pre>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish reliability-probes
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Guided Exercise: Application High Availability with Kubernetes]]></title><description><![CDATA[Simulate different types of application failures and observe how Kubernetes handles them.
Outcomes

Explore how the restartPolicy attribute affects crashing pods.

Observe the behavior of a slow-starting application that has no configured probes.

Us...]]></description><link>https://syarif.kosasih.my.id/guided-exercise-application-high-availability-with-kubernetes</link><guid isPermaLink="true">https://syarif.kosasih.my.id/guided-exercise-application-high-availability-with-kubernetes</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:07:28 GMT</pubDate><content:encoded><![CDATA[<p>Simulate different types of application failures and observe how Kubernetes handles them.</p>
<p><strong>Outcomes</strong></p>
<ul>
<li><p>Explore how the <code>restartPolicy</code> attribute affects crashing pods.</p>
</li>
<li><p>Observe the behavior of a slow-starting application that has no configured probes.</p>
</li>
<li><p>Use a deployment to scale the application, and observe the behavior of a broken pod.</p>
</li>
</ul>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that the following conditions are true:</p>
<ul>
<li><p>The <code>reliability-ha</code> project exists.</p>
</li>
<li><p>The resource files are available in the course directory.</p>
</li>
<li><p>The classroom registry has the <code>long-load</code> container image.</p>
</li>
</ul>
<p>The <code>long-load</code> container image contains an application with utility endpoints. These endpoints perform such tasks as crashing the process and toggling the server's health status.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start reliability-ha
</code></pre>
<p><strong>Procedure 6.1. Instructions</strong></p>
<ol>
<li><p>As the <code>developer</code> user, create a pod from a YAML manifest in the <code>reliability-ha</code> project.</p>
<ol>
<li><p>Log in as the <code>developer</code> user with the <code>developer</code> password.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc login https://api.ocp4.example.com:6443 -u developer
 ...output omitted...
</code></pre>
</li>
<li><p>Select the <code>reliability-ha</code> project.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ oc project reliability-ha
 Now using project "reliability-ha" on server "https://api.ocp4.example.com:6443".
</code></pre>
</li>
<li><p>Navigate to the lab materials directory and view the contents of the pod definition. In particular, <code>restartPolicy</code> is set to <code>Always</code>.</p>
<pre><code class="lang-plaintext"> [student@workstation ~]$ cd DO180/labs/reliability-ha
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ cat long-load.yaml
 apiVersion: v1
 kind: Pod
 metadata:
   name: long-load
 spec:
   containers:
   - image: registry.ocp4.example.com:8443/redhattraining/long-load:v1
     name: long-load
     securityContext:
       allowPrivilegeEscalation: false
   restartPolicy: Always
</code></pre>
</li>
<li><p>Create a pod by using the <code>oc apply</code> command.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc apply -f long-load.yaml
 pod/long-load created
</code></pre>
</li>
<li><p>Send a request to the pod to confirm that it is running and responding.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc exec long-load -- \
   curl -s localhost:3000/health
 Ok
</code></pre>
</li>
</ol>
</li>
<li><p>Trigger the pod to crash, and observe that the <code>restartPolicy</code> instructs the cluster to re-create the pod.</p>
<ol>
<li><p>Observe that the pod is running and has not restarted.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc get pods

 NAME        READY   STATUS    RESTARTS   AGE
 long-load   1/1     Running   0          1m
</code></pre>
</li>
<li><p>Send a request to the <code>/destruct</code> endpoint in the application. This request triggers the process to crash.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc exec long-load -- \
   curl -s localhost:3000/destruct
 command terminated with exit code 52
</code></pre>
</li>
<li><p>Observe that the pod is running and restarted one time.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc get pods
 NAME        READY   STATUS    RESTARTS      AGE
 long-load   1/1     Running   1 (34s ago)   4m16s
</code></pre>
</li>
<li><p>Delete the <code>long-load</code> pod.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc delete pod long-load
 pod "long-load" deleted
</code></pre>
<p> The pod is not re-created, because it was created manually, and not via a workload resource such as a deployment.</p>
</li>
</ol>
</li>
<li><p>Use a restart policy of <code>Never</code> to create the pod, and observe that it is not re-created on crashing.</p>
<ol>
<li><p>Modify the <code>long-load.yaml</code> file so that the <code>restartPolicy</code> is set to <code>Never</code>.</p>
<pre><code class="lang-plaintext"> ...output omitted...
   restartPolicy: Never
</code></pre>
</li>
<li><p>Create the pod with the updated YAML file.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc apply -f long-load.yaml
 pod/long-load created
</code></pre>
</li>
<li><p>Send a request to the pod to confirm that the pod is running and that the application is responding.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc exec long-load -- \
   curl -s localhost:3000/health
 Ok
</code></pre>
</li>
<li><p>Send a request to the <code>/destruct</code> endpoint in the application to crash it.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc exec long-load -- \
   curl -s localhost:3000/destruct
 command terminated with exit code 52
</code></pre>
</li>
<li><p>Observe that the pod is not restarted and is in an error state.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc get pods
 NAME        READY   STATUS   RESTARTS   AGE
 long-load   0/1     Error    0          2m36s
</code></pre>
</li>
<li><p>Delete the <code>long-load</code> pod.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc delete pod long-load
 pod "long-load" deleted
</code></pre>
</li>
</ol>
</li>
<li><p>Because the cluster does not know when the application inside the pod is ready to receive requests, you must add a startup delay to the application. Adding this capability by using probes is covered in a later exercise.</p>
<ol>
<li><p>Update the <code>long-load.yaml</code> file by adding a startup delay and use a restart policy of <code>Always</code>. Set the <code>START_DELAY</code> variable to 60,000 milliseconds (one minute) so that the file looks like the following excerpt:</p>
<pre><code class="lang-plaintext"> ...output omitted...
 spec:
   containers:
   - image: registry.ocp4.example.com:8443/redhattraining/long-load:v1
     imagePullPolicy: Always
     securityContext:
       allowPrivilegeEscalation: false
     name: long-load
     env:
       - name: START_DELAY
         value: "60000"
   restartPolicy: Always
</code></pre>
<h3 id="heading-note"><strong>NOTE</strong></h3>
<p> Although numbers are a valid YAML type, environment variables must be passed as strings. YAML syntax is also indentation-sensitive.</p>
<p> For these reasons, ensure that your file appears <em>exactly</em> as the preceding example.</p>
</li>
<li><p>Apply the YAML file to create the pod and proceed within one minute to the next step.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc apply -f long-load.yaml
 pod/long-load created
</code></pre>
</li>
<li><p>Within a minute of pod creation, verify the status of the pod. The status shows as ready even though it is not. Try to send a request to the application, and observe that it fails.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc get pods
 NAME        READY   STATUS    RESTARTS   AGE
 long-load   1/1     Running   0          16s
</code></pre>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc exec long-load -- \
   curl -s localhost:3000/health
 app is still starting
</code></pre>
</li>
<li><p>After waiting a minute for the application to start, send another a request to the pod to confirm that it is running and responding.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc exec long-load -- \
   curl -s localhost:3000/health
 Ok
</code></pre>
</li>
</ol>
</li>
<li><p>Use a deployment to scale up the number of deployed pods. Observe that deleting the pods causes service outages, even though the deployment handles re-creating the pods.</p>
<ol>
<li><p>Review the <code>long-load-deploy.yaml</code> file, which defines a deployment, service, and route. The deployment creates three replicas of the application pod.</p>
<p> In each pod, a <code>START_DELAY</code> environment variable is set to 15,000 milliseconds (15 seconds). In each pod, the application responds that it is not ready until after the delay.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ cat long-load-deploy.yaml
 ...output omitted...
     spec:
       containers:
       - image: registry.ocp4.example.com:8443/redhattraining/long-load:v1
         imagePullPolicy: Always
         name: long-load
         env:
         - name: START_DELAY
           value: "15000"
 ...output omitted...
</code></pre>
</li>
<li><p>Start the load test script, which sends a request to the <code>/health</code> API endpoint of the application every two seconds. Leave the script running in a visible terminal window.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ ./load-test.sh
 ...output omitted...
</code></pre>
</li>
<li><p>In a new terminal window, apply the <code>~/DO180/labs/reliability-ha/long-load-deploy.yaml</code> file.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ oc apply -f \
   ~/DO180/labs/reliability-ha/long-load-deploy.yaml
 deployment.apps/long-load created
 service/long-load created
 route.route.openshift.io/long-load created
</code></pre>
</li>
<li><p>Watch the output of the load test script as the pods and the application instances start. After a delay, the requests succeed.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 Ok
 Ok
 Ok
 ...output omitted...
</code></pre>
</li>
<li><p>By using the <code>/togglesick</code> API endpoint of the application, put one of the three pods into a broken state.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ curl \
   long-load-reliability-ha.apps.ocp4.example.com/togglesick
 no output expected
</code></pre>
</li>
<li><p>Watch the output of the load test script as some requests start failing. Because of the load balancer, the exact order of the output is random.</p>
<pre><code class="lang-plaintext"> ...output omitted...
 Ok
 app is unhealthy
 app is unhealthy
 Ok
 Ok
 ...output omitted...
</code></pre>
<p> Press <strong>Ctrl</strong>+<strong>C</strong> to end the load test script.</p>
</li>
<li><p>Return to the <code>/home/student/</code> directory.</p>
<pre><code class="lang-plaintext"> [student@workstation reliability-ha]$ cd /home/student/
 [student@workstation ~]$
</code></pre>
</li>
</ol>
</li>
</ol>
<p><strong>Finish</strong></p>
<p>On the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish reliability-ha
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Lab: Manage Storage for Application Configuration and Data]]></title><description><![CDATA[Deploy a web application and its database that share database credentials from a secret. The database should use the default storage for the cluster. Also deploy a file-sharing application that runs with multiple replicas and shares its storage volum...]]></description><link>https://syarif.kosasih.my.id/lab-manage-storage-for-application-configuration-and-data</link><guid isPermaLink="true">https://syarif.kosasih.my.id/lab-manage-storage-for-application-configuration-and-data</guid><category><![CDATA[openshift]]></category><dc:creator><![CDATA[Syarif]]></dc:creator><pubDate>Wed, 12 Jul 2023 11:06:18 GMT</pubDate><content:encoded><![CDATA[<p>Deploy a web application and its database that share database credentials from a secret. The database should use the default storage for the cluster. Also deploy a file-sharing application that runs with multiple replicas and shares its storage volume with a file uploader application. The file sharing and file uploader applications take configuration files from a config map and should use NFS file storage for shareability. The database should use local storage for increased and performance.</p>
<p><strong>Outcomes</strong></p>
<ul>
<li><p>Deploy a database server.</p>
</li>
<li><p>Deploy a web application.</p>
</li>
<li><p>Create a secret that contains the database server credentials.</p>
</li>
<li><p>Create a configuration map that contains an SQL file.</p>
</li>
<li><p>Add and remove a volume on the database server and the web application.</p>
</li>
<li><p>Expose the database server and the web application.</p>
</li>
<li><p>Scale up the web application.</p>
</li>
<li><p>Mount the configuration map as a volume.</p>
</li>
</ul>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to prepare your system for this exercise.</p>
<p>This command ensures that the cluster is accessible and that all exercise resources are available. It also creates the <code>storage-review</code> project, and it creates files that this lab uses, in the <code>/home/student/DO180/labs/storage-review</code> directory.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab start storage-review
</code></pre>
<p><strong>Procedure 5.5. Instructions</strong></p>
<p>The API URL of your OpenShift cluster is <a target="_blank" href="https://api.ocp4.example.com:6443">https://api.ocp4.example.com:6443</a>, and the <code>oc</code> command is already installed on your <code>workstation</code> machine.</p>
<p>Log in to the OpenShift cluster as the <code>developer</code> user with the <code>developer</code> password.</p>
<p>Use the <code>storage-review</code> project for your work.</p>
<ol>
<li><p>Log in to the OpenShift cluster and change to the <code>storage-review</code> project.</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Create a secret named <code>world-cred</code> that contains the following data:</p>
<p> | Field | Value |
 | --- | --- |
 | User | <code>redhat</code> |
 | Password | <code>redhat123</code> |
 | Database | <code>world_x</code> |</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Create a configuration map named <code>dbfiles</code> by using the <code>~/DO180/labs/storage-review/insertdata.sql</code> file.</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Create a database server deployment named <code>dbserver</code> by using the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/mysql-app:v1"><code>registry.ocp4.example.com:8443/redhattraining/mysql-app:v1</code></a> container image. Then, set the missing environment variables by using the <code>world-cred</code> secret.</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Add a volume to the <code>dbserver</code> deployment by using the following information:</p>
<p> | Field | Value |
 | --- | --- |
 | Name | <code>dbserver-lvm</code> |
 | Type | <code>persistentVolumeClaim</code> |
 | Claim mode | <code>rwo</code> |
 | Claim size | <code>1Gi</code> |
 | Mount path | <code>/var/lib/mysql</code> |
 | Claim class | <code>lvms-vg1</code> |
 | Claim name | <code>dbserver-lvm-pvc</code> |</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Create a service for the <code>dbserver</code> deployment by using the following information:</p>
<p> | Field | Value |
 | --- | --- |
 | Name | <code>mysql-service</code> |
 | Port | <code>3306</code> |
 | Target port | <code>3306</code> |</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Create a web application deployment named <code>file-sharing</code> by using the <a target="_blank" href="http://registry.ocp4.example.com:8443/redhattraining/php-webapp-mysql:v1"><code>registry.ocp4.example.com:8443/redhattraining/php-webapp-mysql:v1</code></a> container image. Scale the deployment to two replicas. Then, expose the deployment by using the following information:</p>
<p> | Field | Value |
 | --- | --- |
 | Name | <code>file-sharing</code> |
 | Port | <code>8080</code> |
 | Target port | <code>8080</code> |</p>
<p> Create a route named <code>file-sharing</code> to expose the <code>file-sharing</code> web application to external access. Access the <code>file-sharing</code> route in a web browser to test the connection between the web application and the database server.</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Mount the <code>dbfiles</code> configuration map to the <code>file-sharing</code> deployment as a volume named <code>config-map-pvc</code>. Set the mount path to the <code>/home/database-files</code> directory. Then, verify the content of the <code>insertdata.sql</code> file.</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Add a shared volume to the <code>file-sharing</code> deployment. Use the following information to create the volume:</p>
<p> | Field | Value |
 | --- | --- |
 | Name | <code>shared-volume</code> |
 | Type | <code>persistentVolumeClaim</code> |
 | Claim mode | <code>rwo</code> |
 | Claim size | <code>1Gi</code> |
 | Mount path | <code>/home/sharedfiles</code> |
 | Claim class | <code>nfs-storage</code> |
 | Claim name | <code>shared-pvc</code> |</p>
<p> Next, connect to a <code>file-sharing</code> deployment pod and then use the <code>cp</code> command to copy the <code>/home/database-files/insertdata.sql</code> file to the <code>/home/sharedfiles</code> directory. Then, remove the <code>config-map-pvc</code> volume from the <code>file-sharing</code> deployment.</p>
<p> <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Add the <code>shared-volume</code> PVC to the <code>dbserver</code> deployment. Then, connect to a <code>dbserver</code> deployment pod and verify the content of the <code>/home/sharedfiles/insertdata.sql</code> file.</p>
<p><a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
</li>
<li><p>Connect to the database server and execute the <code>/home/sharedfiles/insertdata.sql</code> file to add data to the <code>world_x</code> database. You can execute the file by using the following command:</p>
<pre><code class="lang-plaintext">mysql -u$MYSQL_USER -p$MYSQL_PASSWORD world_x &lt;/home/sharedfiles/insertdata.sql
</code></pre>
<p>Then, confirm connectivity between the web application and database server by accessing the <code>file-sharing</code> route in a web browser.</p>
<ol>
<li><table><tbody><tr><td><p></p></td></tr></tbody></table>


</li>
</ol>
</li>
</ol>
<p>    <a target="_blank" href="https://rol.redhat.com/rol/app/#">Show Solution</a></p>
<p><strong>Evaluation</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to grade your work. Correct any reported failures and rerun the command until successful.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab grade storage-review
</code></pre>
<p><strong>Finish</strong></p>
<p>As the <code>student</code> user on the <code>workstation</code> machine, use the <code>lab</code> command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.</p>
<pre><code class="lang-plaintext">[student@workstation ~]$ lab finish storage-review
</code></pre>
]]></content:encoded></item></channel></rss>