<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2024-03-23T15:08:59+07:00</updated><id>/feed.xml</id><title type="html">DevOps with Dimas Maryanto</title><subtitle>Tutorial Pemrograman, Backend, Frontend, Website, Mobile dan Devops Terlengkap di Indonesia.</subtitle><author><name>Dimas Maryanto</name></author><entry xml:lang="ansible"><title type="html">Silabus Ansible: Pemula sampai Mahir</title><link href="/posts/devops/automation/ansible/basic/00-silabus-ansible" rel="alternate" type="text/html" title="Silabus Ansible: Pemula sampai Mahir" /><published>2023-07-02T07:26:30+07:00</published><updated>2023-07-02T07:26:30+07:00</updated><id>/posts/devops/automation/ansible/basic/00-silabus-ansible</id><content type="html" xml:base="/posts/devops/automation/ansible/basic/00-silabus-ansible"><![CDATA[<p>Hai semuanya, kembali lagi di Channel <code class="language-plaintext highlighter-rouge">DevOps with Dimas Maryanto</code> jadi kali ini aku mau jelasin dulu Silabus yang akan kita pelajari terkait kelas <code class="language-plaintext highlighter-rouge">DevOps - Ansible untuk Pemula s/d Mahir</code></p>

<p>Materi yang di bahas pada section ini yaitu</p>

<!--more-->

<h2 id="pengenalan-ansible">Pengenalan Ansible</h2>

<p>Tahap pertama yaitu kita akan berkenalan dengan Teknologi Ansible sebagai Automation Platform</p>

<ol>
  <li>Apa itu IT Automation?</li>
  <li>Tool apa yang berguna untuk IT Automation?</li>
  <li>Apa itu RedHat Ansible?</li>
  <li>How to Ansible work’s?</li>
  <li>Install and Configuring Ansible</li>
  <li>Getting started with Ansible
    <ul>
      <li>What is Resource module?</li>
      <li>Getting information about the remote server with Fact</li>
      <li>Execute Ansible command with Ad-hoc</li>
      <li>Create first Ansible playbook</li>
    </ul>
  </li>
</ol>

<p>Ok mungkin sekian dulu yang bisa saya sampaikan terkati Silabus Belajar IT Automation Infrastructure as a Code menggunakan RedHat Ansible untuk Pemula sampai Mahir. Sampai jumpa di kelas!!</p>]]></content><author><name>Dimas Maryanto</name></author><category term="DevOps" /><category term="Automation" /><category term="Ansible" /><category term="Basic" /><summary type="html"><![CDATA[Hai semuanya, kembali lagi di Channel DevOps with Dimas Maryanto jadi kali ini aku mau jelasin dulu Silabus yang akan kita pelajari terkait kelas DevOps - Ansible untuk Pemula s/d Mahir Materi yang di bahas pada section ini yaitu]]></summary></entry><entry xml:lang="gitlab"><title type="html">Getting started: Create and run your first Gitlab CI/CD pipeline</title><link href="/posts/git/gitlab/gitlab-ci/03d-getting-started" rel="alternate" type="text/html" title="Getting started: Create and run your first Gitlab CI/CD pipeline" /><published>2023-06-18T15:30:55+07:00</published><updated>2023-06-18T15:30:55+07:00</updated><id>/posts/git/gitlab/gitlab-ci/03d-getting-started</id><content type="html" xml:base="/posts/git/gitlab/gitlab-ci/03d-getting-started"><![CDATA[<p>Hai semuanya, sekarang kita akan mencoba menggunakan Gitlab CI/CD pipeline. Tetapi ada beberapa prerequisites yang harus dipenuhi diantaranya:</p>

<p>Before you start, make sure you have:</p>

<ul>
  <li>A project in GitLab that you would like to use CI/CD for.</li>
  <li>The Maintainer or Owner role for the project.</li>
</ul>

<p>To create and run your first pipeline:</p>

<ul>
  <li>Ensure you have runners available to run your jobs. To view available runners: Go to <code class="language-plaintext highlighter-rouge">Settings &gt; CI/CD</code> and expand <code class="language-plaintext highlighter-rouge">Runners</code>.</li>
  <li>If you’re using <a href="gitLab.com">gitLab.com</a>, you can skip this step. <a href="gitLab.com">gitLab.com</a> provides shared runners for you. If you don’t have a runner
    <ol>
      <li><a href="https://docs.gitlab.com/runner/install/">Install GitLab Runner</a> on your local machine.</li>
      <li><a href="https://docs.gitlab.com/runner/register/">Register the runner</a> for your project. Choose the shell executor.</li>
    </ol>
  </li>
  <li>Create a <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> file at the root of your repository. This file is where you define the CI/CD jobs.</li>
</ul>

<p>When you commit the file to your repository, the runner runs your jobs. The job results are displayed in a pipeline.</p>

<p>Okay karena pembahasan kali ini akan lumayan panjang, jadi kita akan bagi-bagi menjadi beberapa bagian diantaranya seperti berikut:</p>

<ol>
  <li>Create a <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> file</li>
  <li>Running the Gitlab CI pipelines</li>
  <li>Tips for writing the <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code></li>
</ol>

<!--more-->

<h2 id="create-a-gitlab-ciyml-file">Create a <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> file</h2>

<p>File <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> basiclly it’s a <a href="https://en.wikipedia.org/wiki/YAML">YAML</a> format that you can specify to instruction of Gitlab CI/CD. in this file, you can define:</p>

<ul>
  <li>The structure and order of jobs that the runner should execute.</li>
  <li>The decisions the runner should make when specific conditions are encountered.</li>
</ul>

<p>To create a <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> file you can used:</p>

<ul>
  <li>Manually, by using text-editor such as vscode, vim, nodepad, etc</li>
  <li>
    <p>Build-in text-editor by gitlab</p>

    <script src="https://gist.github.com/dimMaryanto93/fd40c02b1cc0d4eccb7c03103397591b.js?file=03d-basic-gitlab-ci.yml"> </script>

    <p>This example shows four jobs: <code class="language-plaintext highlighter-rouge">build-job</code>, <code class="language-plaintext highlighter-rouge">test-job1</code>, <code class="language-plaintext highlighter-rouge">test-job2</code>, and <code class="language-plaintext highlighter-rouge">deploy-prod</code>. The comments listed in the <code class="language-plaintext highlighter-rouge">echo</code> commands are displayed in the UI when you view the jobs. The values for the <a href="https://docs.gitlab.com/ee/ci/variables/predefined_variables.html">predefined variables</a> <code class="language-plaintext highlighter-rouge">$GITLAB_USER_LOGIN</code> and <code class="language-plaintext highlighter-rouge">$CI_COMMIT_BRANCH</code> are populated when the jobs run.</p>
  </li>
  <li>Then submit, commit &amp; push</li>
</ul>

<p>Now take a look at your pipeline and the jobs within.</p>

<ol>
  <li>
    <p>Go to <strong>CI/CD &gt; Pipelines</strong>. A pipeline with three stages should be displayed:</p>

    <p><img src="/resources/posts/gitlab-ci/03d-getting-started/01-pipeline.png" alt="gitlab-pipeline" /></p>
  </li>
  <li>
    <p>View a visual representation of your pipeline by selecting the pipeline ID:</p>

    <p><img src="/resources/posts/gitlab-ci/03d-getting-started/01a-pipeline-detail.png" alt="gitlab-pipeline-detail" /></p>
  </li>
  <li>
    <p>View details of a job by selecting the job name.</p>

    <ul>
      <li>
        <p>This is <code class="language-plaintext highlighter-rouge">build-job</code>
  <img src="/resources/posts/gitlab-ci/03d-getting-started/01b-job-build.png" alt="job-build" /></p>
      </li>
      <li>
        <p>This is <code class="language-plaintext highlighter-rouge">build-test2</code>
  <img src="/resources/posts/gitlab-ci/03d-getting-started/01c-job-test2.png" alt="job-build" /></p>
      </li>
      <li>
        <p>This is <code class="language-plaintext highlighter-rouge">build-deploy-prod</code>
  <img src="/resources/posts/gitlab-ci/03d-getting-started/01d-job-deploy-prod.png" alt="job-build" /></p>
      </li>
    </ul>
  </li>
</ol>

<p>You have successfully created your first CI/CD pipeline in GitLab. Congratulations!</p>

<p>Now you can get started customizing your <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> and defining more advanced jobs.</p>

<h2 id="running-the-gitlab-ci-pipelines">Running the Gitlab CI pipelines</h2>

<p>By default, when you push or changed the file of <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> it’s trigger pipeline to run, but we have an other way to run it. Here is 4 deffrent method to the run pipeline:</p>

<ul>
  <li>Workflow (<code class="language-plaintext highlighter-rouge">rules</code>, <code class="language-plaintext highlighter-rouge">only</code>)</li>
  <li>Manually run pipeline</li>
  <li>Schedule to run pipeline</li>
  <li>Trigger using (<code class="language-plaintext highlighter-rouge">webhook</code>, <code class="language-plaintext highlighter-rouge">rest-api</code>)</li>
</ul>

<h3 id="updating-file-gitlab-ciyml">Updating file <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code></h3>

<p>Okay kita bahas satu-per-satu, mulai dari update file <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> yang sebelumnya seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/fd40c02b1cc0d4eccb7c03103397591b.js?file=03d-basic-gitlab-ci-edited.yml"> </script>

<p>Ketika di push maka secara otomatis akan jalan pipeline baru seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/02a-gitlab-ci-edited.png" alt="gitlab-pipeline-edited" /></p>

<p>The output will print look like this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hello, my name is Dimas Maryanto <span class="o">!</span> <span class="se">\n</span> i<span class="s1">'m trying to learn CI/CD feature with Gitlab CI
</span></code></pre></div></div>

<h3 id="using-workflow">Using workflow</h3>

<p>Sekarang kita coba untuk workflow method, dengan mengupdate file <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> menggunakan property <code class="language-plaintext highlighter-rouge">only</code> atau <code class="language-plaintext highlighter-rouge">rules</code> seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/fd40c02b1cc0d4eccb7c03103397591b.js?file=03d-basic-gitlab-ci-workflow.yml"> </script>

<p>Ketika di push maka secara otomatis akan jalan pipeline baru dan berikut adalah pipeline detailnya:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/02b-workflow-pipeline-detail.png" alt="gitlab-pipeline-detail-workflow" /></p>

<p>Nah terlihat disana terdapat 3 job yaitu <code class="language-plaintext highlighter-rouge">build-job</code>, <code class="language-plaintext highlighter-rouge">test-job2</code> dan <code class="language-plaintext highlighter-rouge">deploy-prod</code>. Terus untuk job <code class="language-plaintext highlighter-rouge">test-job1</code> kemana?</p>

<p>Job <code class="language-plaintext highlighter-rouge">test-job1</code> hanya akan muncul jika kita membuat <code class="language-plaintext highlighter-rouge">branch</code>, <code class="language-plaintext highlighter-rouge">tags</code> atau <code class="language-plaintext highlighter-rouge">commit message</code> dengan prefix <code class="language-plaintext highlighter-rouge">-release</code> seperti berikut:</p>

<p>Kita coba buat tag <code class="language-plaintext highlighter-rouge">2023.06.18.12.51-release</code> pada branch `main seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/02c-workflow-create-tag.png" alt="create-tags" /></p>

<p>Sekarang jika kita lihat pada pipeline detail yang terbaru maka jobnya jalan seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/02c-workflow-create-tag-pipeline.png" alt="workflow-tags" width="400" /></p>

<p>Dengan dengan membuat tag tersebut, kita menjalankan kembali job sebelumnya beserta <code class="language-plaintext highlighter-rouge">test-job1</code> tetapi tanpa job <code class="language-plaintext highlighter-rouge">deploy-prod</code></p>

<p>Sedangkan untuk menjalankan yang job <code class="language-plaintext highlighter-rouge">build-prod</code> kita bisa membuat Merge request dari branch dengan prefix <code class="language-plaintext highlighter-rouge">hotfix/</code> ke branch default yang which is <code class="language-plaintext highlighter-rouge">main</code>.</p>

<ul>
  <li>Buat branch baru misalnya dengan nama <code class="language-plaintext highlighter-rouge">hotfix/issue01</code> dari branch main</li>
  <li>Buat perubahan dan commit serta push</li>
  <li>Buat merge request ke main maka hasilnya seperti berikut:</li>
</ul>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/02d-workflow-mr.png" alt="workflow-merge-request" width="400" /></p>

<h3 id="manually-run-pipeline">Manually run pipeline</h3>

<p>Selain menggunakan script based, dan workflow Gitlab CI kita juga bisa menjalankan pipeline secara manual dengan click <code class="language-plaintext highlighter-rouge">Run pipeline</code> pada menu <code class="language-plaintext highlighter-rouge">Pipelines</code> seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/03a-manual-run-pipeline.png" alt="manual-run-pipeline" /></p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/03b-form-run-pipeline.png" alt="form-run-pipeline" /></p>

<p>Kemudian muncul form seperti berikut, jika tidak ada option yang kita define pada script <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> just click the button, hasilnya seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/03c-manual-run-pipeline.png" alt="form-run-pipeline" /></p>

<h3 id="schedule-to-run-pipeline">Schedule to run pipeline</h3>

<p>Lanjutan dari run pipeline secara manual tersebut, kita juga bisa meng-schedule pipeline dengan menggunakan cron pattern caranya</p>

<ul>
  <li>
    <p>Akses ke menu <strong>Pipelines -&gt; Schedule</strong> seperti berikut:</p>

    <p><img src="/resources/posts/gitlab-ci/03d-getting-started/03c-manual-run-pipeline.png" alt="schedule-pipeline" /></p>
  </li>
  <li>
    <p>Misalnya kita mau menjalankan pipeline tersebut setiap 5 menit, jadi pilih Interfal pattern <code class="language-plaintext highlighter-rouge">Custom</code> input seperti berikut <code class="language-plaintext highlighter-rouge">*/5 * * * *</code></p>
  </li>
  <li>
    <p>Kemudian save, seperti berikut:</p>
  </li>
</ul>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/04a-schedule-pipeline.png" alt="schedule-list" /></p>

<p>Dan perhatikan ke menu Pipeline 5 menit mendatang hasilnya seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/04b-schedule-run.png" alt="run-from-schedule" /></p>

<h3 id="trigger-using-webhook-rest-api">Trigger using (<code class="language-plaintext highlighter-rouge">webhook</code>, <code class="language-plaintext highlighter-rouge">rest-api</code>)</h3>

<p>Yang terkahir kita juga bisa me-trigger dari Webhook atau Rest-API menggunakan tools seperti <code class="language-plaintext highlighter-rouge">curl</code> atau bahkan Postman. Untuk membuat Gitlab CI yang bisa di triger kita membuat dulu TOKEN di menu <strong>Settings -&gt; CI/CD -&gt; expand Triger pipeline</strong> seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/05a-trigger-token.png" alt="create-token-trigger" /></p>

<p>Kemudian input nama/description contohnya <code class="language-plaintext highlighter-rouge">trigger-curl</code> dan kemudian click button <code class="language-plaintext highlighter-rouge">Add triger</code> maka akan muncul tokennya, coba simpan token tersebut.</p>

<p>Setelah itu kita bisa triger pipeline dengan perintah curl berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">curl <span class="nt">-X</span> POST <span class="se">\</span>
     <span class="nt">--fail</span> <span class="se">\</span>
     <span class="nt">-F</span> <span class="nv">token</span><span class="o">=</span>TOKEN <span class="se">\</span>
     <span class="nt">-F</span> <span class="nv">ref</span><span class="o">=</span>REF_NAME <span class="se">\</span>
     PROTOCOL://SERVER_GITLAB/api/v4/projects/PROJECT_ID/trigger/pipeline</code></pre></figure>

<p>Sekarang coba jalankan perintah berikut di terminal</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➡ curl <span class="nt">-X</span> POST <span class="se">\</span>
     <span class="nt">--fail</span> <span class="se">\</span>
     <span class="nt">-F</span> <span class="nv">token</span><span class="o">=</span>glptt-da5dbea331d2c78071752e4528ba52c34a9a9567 <span class="se">\</span>
     <span class="nt">-F</span> <span class="nv">ref</span><span class="o">=</span>main <span class="se">\</span>
     https://gitlab.dimas-maryanto.com/api/v4/projects/364/trigger/pipeline

<span class="o">{</span>
  <span class="s2">"id"</span>: 1029,
  <span class="s2">"iid"</span>: 12,
  <span class="s2">"project_id"</span>: 364,
  <span class="s2">"sha"</span>: <span class="s2">"93b7c2cfda83cda7b42bea5619c2756f7e57022e"</span>,
  <span class="s2">"ref"</span>: <span class="s2">"main"</span>,
  <span class="s2">"status"</span>: <span class="s2">"created"</span>,
  <span class="s2">"source"</span>: <span class="s2">"trigger"</span>,
  <span class="s2">"before_sha"</span>: <span class="s2">"0000000000000000000000000000000000000000"</span>,
  <span class="s2">"tag"</span>: <span class="nb">false</span>,
  <span class="s2">"yaml_errors"</span>: null,
  <span class="s2">"user"</span>: <span class="o">{</span>
    <span class="s2">"id"</span>: 2,
    <span class="s2">"username"</span>: <span class="s2">"dimasm93"</span>,
    <span class="s2">"web_url"</span>: <span class="s2">"https://gitlab.dimas-maryanto.com/dimasm93"</span>
  <span class="o">}</span>,
  <span class="s2">"detailed_status"</span>: <span class="o">{</span>
    <span class="s2">"icon"</span>: <span class="s2">"status_created"</span>,
    <span class="s2">"details_path"</span>: <span class="s2">"/examples/gitlab-ci-cd/test-gitlab-ci/-/pipelines/1029"</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Sekarang kita lihat hasilnya:</p>

<p><img src="/resources/posts/gitlab-ci/03d-getting-started/05b-triger-pipeline.png" alt="trigger-curl" /></p>

<h2 id="tips-for-writing-the-gitlab-ciyml">Tips for writing the <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code></h2>

<p>Here are some tips to get started working with the <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> file.</p>

<p>For the complete <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> syntax, see <a href="https://docs.gitlab.com/ee/ci/yaml/index.html">the full <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> keyword reference</a>.</p>

<ul>
  <li>
    <p>Use the <a href="https://docs.gitlab.com/ee/ci/pipeline_editor/index.html">pipeline editor</a> to edit your <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> file.</p>
  </li>
  <li>Each job contains a script section and belongs to a stage:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">stage</code> describes the sequential execution of jobs. If there are runners available, jobs in a single stage run in parallel.</li>
      <li>Use the <code class="language-plaintext highlighter-rouge">needs</code> keyword to run jobs out of stage order.</li>
    </ul>
  </li>
  <li>You can set additional configuration to customize how your jobs and stages perform:
    <ul>
      <li>Use the <code class="language-plaintext highlighter-rouge">rules</code> keyword to specify when to run or skip jobs. The <code class="language-plaintext highlighter-rouge">only</code> and <code class="language-plaintext highlighter-rouge">except</code> legacy keywords are still supported, but can’t be used with <code class="language-plaintext highlighter-rouge">rules</code> in the same job.</li>
      <li>Keep information across jobs and stages persistent in a pipeline with <code class="language-plaintext highlighter-rouge">cache</code> and <code class="language-plaintext highlighter-rouge">artifacts</code>. These keywords are ways to store dependencies and job output, even when using ephemeral runners for each job.</li>
      <li>Use the <code class="language-plaintext highlighter-rouge">default</code> keyword to specify additional configurations that are applied to all jobs. This keyword is often used to define <code class="language-plaintext highlighter-rouge">before_script</code> and <code class="language-plaintext highlighter-rouge">after_script</code> sections that should run on every job.</li>
    </ul>
  </li>
</ul>]]></content><author><name>Dimas Maryanto</name></author><category term="git" /><category term="gitlab" /><category term="gitlab-ci" /><summary type="html"><![CDATA[Hai semuanya, sekarang kita akan mencoba menggunakan Gitlab CI/CD pipeline. Tetapi ada beberapa prerequisites yang harus dipenuhi diantaranya: Before you start, make sure you have: A project in GitLab that you would like to use CI/CD for. The Maintainer or Owner role for the project. To create and run your first pipeline: Ensure you have runners available to run your jobs. To view available runners: Go to Settings &gt; CI/CD and expand Runners. If you’re using gitLab.com, you can skip this step. gitLab.com provides shared runners for you. If you don’t have a runner Install GitLab Runner on your local machine. Register the runner for your project. Choose the shell executor. Create a .gitlab-ci.yml file at the root of your repository. This file is where you define the CI/CD jobs. When you commit the file to your repository, the runner runs your jobs. The job results are displayed in a pipeline. Okay karena pembahasan kali ini akan lumayan panjang, jadi kita akan bagi-bagi menjadi beberapa bagian diantaranya seperti berikut: Create a .gitlab-ci.yml file Running the Gitlab CI pipelines Tips for writing the .gitlab-ci.yml]]></summary></entry><entry xml:lang="gitlab"><title type="html">Settings up Gitlab CI (on-premise)</title><link href="/posts/git/gitlab/gitlab-ci/03c-setup-gitlab-ci" rel="alternate" type="text/html" title="Settings up Gitlab CI (on-premise)" /><published>2023-06-17T21:12:16+07:00</published><updated>2023-06-17T21:12:16+07:00</updated><id>/posts/git/gitlab/gitlab-ci/03c-setup-gitlab-ci</id><content type="html" xml:base="/posts/git/gitlab/gitlab-ci/03c-setup-gitlab-ci"><![CDATA[<p>Hai semuanya, di materi kali ini kita akan membahas tentang Setup environment for Continues Integration (CI) menggunakan Gitlab CI di on-premise. Ok karena artikel ini akan lumayan panjang jadi kita akan bagi2 menjadi beberapa bagian yaitu</p>

<ol>
  <li>Requirement and prequisite</li>
  <li>Arsitektur</li>
  <li>Setup &amp; Konfigurasi software
    <ul>
      <li>Install gitlab</li>
      <li>Install &amp; setting docker engine</li>
      <li>Install gitlab runner</li>
      <li>Register gitlab-runner to gitlab</li>
    </ul>
  </li>
  <li>Tryout Gitlab CI script</li>
</ol>

<p>Ok langsung ja kita ke pembahasan pertama yaitu</p>

<!--more-->

<h2 id="requirement-and-prequisite">Requirement and prequisite</h2>

<p>Untuk menggunakan Gitlab CI ada beberapa hal yang perlu kita siapkan diantaranya minimal 2 virtual machine dengan specifikasi seperti berikut:</p>

<ol>
  <li>
    <p>VM Gitlab</p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">vcs_repository</span><span class="pi">:</span>
   <span class="na">os</span><span class="pi">:</span> <span class="s">Linux Distro</span>
       <span class="s">distro</span><span class="err">:</span> <span class="s">Ubuntu Server</span>
       <span class="s">vesion</span><span class="err">:</span> <span class="s1">'</span><span class="s">&gt;=</span><span class="nv"> </span><span class="s">20.04'</span>
   <span class="na">hardware</span><span class="pi">:</span>
       <span class="na">cpu</span><span class="pi">:</span> <span class="s">4 CPU</span>
       <span class="na">memory</span><span class="pi">:</span> <span class="s">8GB</span>
       <span class="na">storage</span><span class="pi">:</span> <span class="s">250GB</span>
           <span class="s">partitions</span><span class="err">:</span>
               <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">/</span>
                 <span class="na">size</span><span class="pi">:</span> <span class="s">75 GB</span>
               <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">/var</span>
                 <span class="na">size</span><span class="pi">:</span> <span class="s1">'</span><span class="s">&gt;=</span><span class="nv"> </span><span class="s">150GB'</span>
       <span class="err">    </span><span class="na">type</span><span class="pi">:</span> <span class="s">LVM</span>
   <span class="na">networks</span><span class="pi">:</span>
       <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">private ip</span>
         <span class="na">ip4</span><span class="pi">:</span> <span class="s">192.168.88.101/24</span>
         <span class="na">gateway</span><span class="pi">:</span> <span class="s">192.168.88.1</span>
         <span class="na">dns</span><span class="pi">:</span> 
           <span class="pi">-</span> <span class="s">8.8.8.8</span>
           <span class="pi">-</span> <span class="s">8.8.4.4</span>
   <span class="na">firewall-cmd</span><span class="pi">:</span>
       <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">SSH</span>
         <span class="na">port</span><span class="pi">:</span> <span class="s">22/tcp</span>
         <span class="na">policy</span><span class="pi">:</span> <span class="s">allow</span>
       <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Gitlab Repository</span>
         <span class="na">port</span><span class="pi">:</span> <span class="s">80/tcp, 443/tcp</span>   
         <span class="na">policy</span><span class="pi">:</span> <span class="s">allow</span>
   <span class="na">packages</span><span class="pi">:</span>
       <span class="pi">-</span> <span class="s">gitlab-ce</span>
       <span class="pi">-</span> <span class="s">OpenSSH-Server</span>   
</code></pre></div>    </div>
  </li>
  <li>
    <p>VM gitlab-runner + docker</p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">workers</span><span class="pi">:</span>
   <span class="na">os</span><span class="pi">:</span> <span class="s">Linux Distro</span>
       <span class="s">distro</span><span class="err">:</span> <span class="s">CentOS</span>
       <span class="s">vesion</span><span class="err">:</span> <span class="s1">'</span><span class="s">&gt;=</span><span class="nv"> </span><span class="s">7.9'</span>
   <span class="na">hardware</span><span class="pi">:</span>
       <span class="c1">## sesuaikan specifikasi hardwarenya dengan kebutuhan build</span>
       <span class="c1">## karena ada beberapa bahasa pemograman membutuhkan lebih dari 4GB RAM dan jumlah cpu</span>
       <span class="na">cpu</span><span class="pi">:</span> <span class="s">2 CPU</span>
       <span class="na">memory</span><span class="pi">:</span> <span class="s">4GB</span>
       <span class="na">storage</span><span class="pi">:</span> <span class="s">70GB</span>
           <span class="s">partitions</span><span class="err">:</span>
               <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">/</span>
                 <span class="na">size</span><span class="pi">:</span> <span class="s">20 GB</span>
               <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">/var</span>
                 <span class="na">size</span><span class="pi">:</span> <span class="s1">'</span><span class="s">&gt;=</span><span class="nv"> </span><span class="s">50GB'</span>
       <span class="err">    </span><span class="na">type</span><span class="pi">:</span> <span class="s">LVM</span>
   <span class="na">networks</span><span class="pi">:</span>
       <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">private ip</span>
         <span class="na">ip4</span><span class="pi">:</span> <span class="s">192.168.88.102/24</span>
         <span class="na">gateway</span><span class="pi">:</span> <span class="s">192.168.88.1</span>
         <span class="na">dns</span><span class="pi">:</span> 
           <span class="pi">-</span> <span class="s">8.8.8.8</span>
           <span class="pi">-</span> <span class="s">8.8.4.4</span>
   <span class="na">packages</span><span class="pi">:</span>
       <span class="pi">-</span> <span class="s">OpenSSH-Server</span>
       <span class="pi">-</span> <span class="s">docker-ce</span>
       <span class="pi">-</span> <span class="s">gitlab-runner</span>
</code></pre></div>    </div>
  </li>
</ol>

<p>Untuk membuat virtual-machine temen-temen boleh menggunakan hypervisor provider apapun misalnya; Oracle VirtualBox, VMware player, qemu dan lain-lain. Kalo saya sendiri menggunakan proxmox yang saya install di PC dengan spesifikasi seperti berikut:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">proxmox</span><span class="pi">:</span>
  <span class="na">os</span><span class="pi">:</span> <span class="s">Proxmox </span><span class="m">7.8</span>
  <span class="na">hardware</span><span class="pi">:</span>
    <span class="na">cpu</span><span class="pi">:</span> <span class="s">Intel core i9-9900 (8core 16thread)</span>
    <span class="na">memory</span><span class="pi">:</span> <span class="s">64GB</span>
    <span class="na">storage</span><span class="pi">:</span>
      <span class="na">SSD</span><span class="pi">:</span>
        <span class="na">size</span><span class="pi">:</span> <span class="s">1TB</span>
        <span class="na">partitions</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">lvm</span>
          <span class="na">size</span><span class="pi">:</span> <span class="s">200 GB</span>
          <span class="na">format</span><span class="pi">:</span> <span class="s">proxmox os</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">lvm-thin</span>
          <span class="na">size</span><span class="pi">:</span> <span class="s">600 GB</span>
          <span class="na">format</span><span class="pi">:</span> <span class="s">LVM Thin</span>
  <span class="na">networks</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Microtik RouterBoard RBD52G</span>
      <span class="na">ip4</span><span class="pi">:</span> <span class="s">192.168.88.1</span>
</code></pre></div></div>

<p>Seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03c-setup-gitlab-ci/proxmox.png" alt="proxmox" /></p>

<h2 id="arsitektur">Arsitektur</h2>

<p>Okay sebelum kita install software-software tersebut kita lihat dulu secara architectur yang digunakan agar kita bisa memahami flownya, yaitu seperti berikut:</p>

<p>This diagram shows how runners are registered and how jobs are requested and handled:</p>

<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<div class="mermaid">
sequenceDiagram
  participant GitLab
  participant GitLabRunner
  participant Executor

  opt registration
    GitLabRunner -&gt;&gt;+ GitLab: POST /api/v4/runners with registration_token
    GitLab --&gt;&gt;- GitLabRunner: Registered with runner_token
  end

  loop job requesting and handling
    GitLabRunner -&gt;&gt;+ GitLab: POST /api/v4/jobs/request with runner_token
    GitLab --&gt;&gt;+ GitLabRunner: job payload with job_token
    GitLabRunner -&gt;&gt;+ Executor: Job payload
    Executor -&gt;&gt;+ GitLab: clone sources with job_token
    Executor -&gt;&gt;+ GitLab: download artifacts with job_token
    Executor --&gt;&gt;- GitLabRunner: return job output and status
    GitLabRunner --&gt;&gt;- GitLab: updating job output and status with job_token
  end
</div>

<p><strong>GitLab Runner</strong>: The application that you install that executes GitLab CI jobs on a target computing platform.</p>

<ul>
  <li><strong>runner</strong>: The agent that runs the code on the host platform and displays in the UI. If a runner is registered with the same token, the runner could represent a collection of runners and runner managers.</li>
  <li><strong>runner manager</strong>: A type of runner that can create multiple runners for autoscaling. Specific to the type of executor used.</li>
  <li><strong>runner worker</strong>: The process created by the runner on the host computing platform to run jobs.</li>
</ul>

<p>GitLab Runner implements a number of executors that can be used to run your builds in different scenarios.</p>

<ol>
  <li><strong>SSH</strong>, is using Connect using ssh protocol to execute jobs</li>
  <li><strong>Shell</strong>, is a simple executor that you use to execute builds locally on the machine where GitLab Runner is installed.</li>
  <li>Hypervisor (VirtualBox, Paralles), is using VirtualMachine manager to execute the job</li>
  <li><strong>Docker</strong>, GitLab Runner uses the Docker executor to run jobs on Docker images.</li>
  <li><strong>Kubernetes</strong>, Use the Kubernetes executor to use Kubernetes clusters for your builds. The executor calls the Kubernetes cluster API and creates a pod for each GitLab CI job.</li>
</ol>

<p>Tahap selanjutnya temen-temen bisa pilih salah-satu, klo saya sendiri lebih sering menggunakan Docker executor sebagai main gitlab runner executornya so jadi kita bisa langsung install.</p>

<h2 id="setup--konfigurasi-software">Setup &amp; Konfigurasi software</h2>

<p>Untuk gitlab intances, kita bisa menggunakan Gitlab SaaS (online) atau on-premise (local). Untuk installasi gitlab on-premise kita bisa menggunakan yang sebelumnya jadi kita bisa skip atau bisa lanjutkan ke proses install gitlab-runner.</p>

<p>Untuk installing gitlab runner kita bisa menggunakan Linux Repository distribution yaitu dengan menggunakan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>yum <span class="nb">install</span> <span class="nt">-y</span> vim git tmux curl wget net-tools
curl <span class="nt">-L</span> <span class="s2">"https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh"</span> | <span class="nb">sudo </span>bash <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">sudo </span>yum <span class="nt">-y</span> <span class="nb">install </span>gitlab-runner</code></pre></figure>

<p>Before you install Docker Engine for the first time on a new host machine, you need to set up the Docker repository. Afterward, you can install and update Docker from the repository. Install the <code class="language-plaintext highlighter-rouge">yum-utils</code> package (which provides the <code class="language-plaintext highlighter-rouge">yum-config-manager</code> utility) and set up the repository.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>yum <span class="nb">install</span> <span class="nt">-y</span> yum-utils <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">sudo </span>yum-config-manager <span class="se">\</span>
    <span class="nt">--add-repo</span> <span class="se">\</span>
    https://download.docker.com/linux/centos/docker-ce.repo</code></pre></figure>

<p>Install Docker Engine</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>yum <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\</span>
 docker-ce <span class="se">\</span>
 docker-ce-cli <span class="se">\</span>
 containerd.io <span class="se">\</span>
 docker-compose-plugin
 
<span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="nt">--now</span> docker</code></pre></figure>

<p>Setelah itu pastikan configurasi selinux di update menjadi permissive dengan mengedit file <code class="language-plaintext highlighter-rouge">/etc/selinux/config</code> untuk property <code class="language-plaintext highlighter-rouge">SELINUX=enforce</code> menjadi <code class="language-plaintext highlighter-rouge">SELINUX=permissive</code> dan kemudian restart.</p>

<p>Jangan lupa tambahkan rule pada firewall seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">firewall-cmd <span class="nt">--zone</span><span class="o">=</span>public <span class="nt">--add-masquerade</span> <span class="nt">--permanent</span> 
firewall-cmd <span class="nt">--zone</span><span class="o">=</span>public <span class="nt">--add-port</span><span class="o">=</span>2375/tcp <span class="nt">--permanent</span>
firewall-cmd <span class="nt">--reload</span></code></pre></figure>

<p>Setelah di install docker dan gitlab-runner package, kita Register gitlab-runner ke Gitlab Repository ada pun yang harus di perhatikan adalah</p>

<ol>
  <li>Registered as Global</li>
  <li>Registered by group</li>
  <li>Registered by project</li>
</ol>

<p>Pilih yang mana? ini tergantung dari kebutuhan ada yang ingin semua project pake gitlab runner brati kita register sebagai Global (Menu <code class="language-plaintext highlighter-rouge">Admin -&gt; Runners</code>), ada yang per project (Menu <code class="language-plaintext highlighter-rouge">Your project -&gt; Settings -&gt; CI/CD -&gt; Runners</code>) jadi kita pilih by project. Karena disini saya mau general kita pilih yang Global. yang kita perlukan adalah <code class="language-plaintext highlighter-rouge">URL</code> dan <code class="language-plaintext highlighter-rouge">Registration token</code> seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03c-setup-gitlab-ci/gitlab-runner-register.png" alt="gitlat-runner-registery" /></p>

<p>Sekarang kita register, gitlab runner agent ke gitlab dengan menggunakan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">export </span><span class="nv">GITLAB_URL</span><span class="o">=</span><span class="s1">'&lt;your-gitlab-ip-or-domain&gt;'</span>
<span class="nb">export </span><span class="nv">GITLAB_RUNNER_TOKEN</span><span class="o">=</span><span class="s1">'&lt;your-gitlab-runner-token&gt;'</span>
<span class="nb">export </span><span class="nv">GITLAB_RUNNER_EXTRA_HOST</span><span class="o">=</span><span class="s1">'private.nexus-registry.docker.local:&lt;ip-nexus-oss-server&gt;'</span>
<span class="nb">export </span><span class="nv">GITLAB_RUNNER_DOCKER_VOLUMES</span><span class="o">=(</span> <span class="s2">"/certs/client"</span> <span class="s2">"/cache"</span> <span class="o">)</span>

<span class="nb">sudo </span>gitlab-runner register <span class="se">\</span>
<span class="nt">-r</span><span class="o">=</span><span class="k">${</span><span class="nv">GITLAB_RUNNER_TOKEN</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--name</span><span class="o">=</span>gitlab-runner-docker-executor <span class="se">\</span>
<span class="nt">--non-interactive</span> <span class="se">\</span>
<span class="nt">--url</span><span class="o">=</span><span class="k">${</span><span class="nv">GITLAB_URL</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--clone-url</span><span class="o">=</span><span class="k">${</span><span class="nv">GITLAB_URL</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--executor</span><span class="o">=</span><span class="s2">"docker"</span> <span class="se">\</span>
<span class="nt">--docker-tlsverify</span><span class="o">=</span><span class="nb">false</span> <span class="se">\</span>
<span class="nt">--docker-image</span><span class="o">=</span><span class="s2">"alpine:latest"</span> <span class="se">\</span>
<span class="nt">--docker-disable-entrypoint-overwrite</span><span class="o">=</span><span class="nb">false</span> <span class="se">\</span>
<span class="nt">--docker-oom-kill-disable</span><span class="o">=</span><span class="nb">false</span> <span class="se">\</span>
<span class="nt">--docker-extra-hosts</span><span class="o">=</span><span class="k">${</span><span class="nv">GITLAB_RUNNER_EXTRA_HOST</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--docker-volumes</span><span class="o">=</span><span class="k">${</span><span class="nv">GITLAB_RUNNER_DOCKER_VOLUMES</span><span class="p">[@]</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">--env</span><span class="o">=</span><span class="s2">"DOCKER_TLS_CERTDIR="</span> <span class="se">\</span>
<span class="nt">--docker-privileged</span><span class="o">=</span><span class="nb">true</span> <span class="se">\</span>
<span class="nt">--tag-list</span><span class="o">=</span><span class="s2">"docker"</span></code></pre></figure>

<p>Jika sudah maka gitlab-runner akan terdaftar seperti berikut:</p>

<p><img src="/resources/posts/gitlab-ci/03c-setup-gitlab-ci/gitlab-runner-list.png" alt="gitlat-runner-list" /></p>

<h2 id="tryout-gitlab-ci-script">Tryout Gitlab CI script</h2>

<p>Setelah kita install package gitlab, gitlab-runner, executor (docker) dan register gitlab runner agent ke gitlab instance tahap selanjutnya kita coba test menggunakan simple configuration. Berikut adalah step-by-step nya</p>

<ol>
  <li>
    <p>Buat repository, contohnya name <code class="language-plaintext highlighter-rouge">test-gitlab-ci</code> kemudian visiblilty kita buat <code class="language-plaintext highlighter-rouge">public</code> serta untuk project configuration check pada <code class="language-plaintext highlighter-rouge">initilization repo with README</code> click <code class="language-plaintext highlighter-rouge">Create project</code></p>
  </li>
  <li>
    <p>Kemudian coba buat file baru dengan nama <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> seperti berikut:
  <script src="https://gist.github.com/dimMaryanto93/fd40c02b1cc0d4eccb7c03103397591b.js?file=03c-test-gitlab-ci.yml"> </script></p>
  </li>
  <li>
    <p>Dan coba commit, serta push ke branch <code class="language-plaintext highlighter-rouge">main</code>. Jika sudah temen-temen bisa lihat di menu Pipeline seperti berikut:
  <img src="/resources/posts/gitlab-ci/03c-setup-gitlab-ci/pipeline.png" alt="pipeline" /></p>
  </li>
  <li>
    <p>Terdapat 1 pipeline yang sedang berjalan, kita coba lihat detailnya dengan click button <code class="language-plaintext highlighter-rouge">running</code> maka seperti berikut:
  <img src="/resources/posts/gitlab-ci/03c-setup-gitlab-ci/pipeline-detail.png" alt="pipeline-detail" /></p>
  </li>
  <li>
    <p>Dalam detail pipeline tersebut terlihat sedang ada 1 job yang sedang berjalan, kita coba lihat detail dengan click button <code class="language-plaintext highlighter-rouge">job1</code> maka seperti berikut:
  <img src="/resources/posts/gitlab-ci/03c-setup-gitlab-ci/job-detail.png" alt="job-detail" /></p>
  </li>
  <li>
    <p>Nah terlihat pada job, menjalankan script yang kita tulis pada file <code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> menghasilkan output:</p>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nv">$ </span><span class="nb">echo</span> <span class="s1">'Hi my name is Dimas Maryanto'</span>
  Hi my name is Dimas Maryanto

  Cleaning up project directory and file based variables
  00:01
  Job succeeded
</code></pre></div></div>

<p>Nah ini artinya, kita sudah bisa menggunakan Continues Integration dengan menggunakan Gitlab CI.</p>]]></content><author><name>Dimas Maryanto</name></author><category term="git" /><category term="gitlab" /><category term="gitlab-ci" /><summary type="html"><![CDATA[Hai semuanya, di materi kali ini kita akan membahas tentang Setup environment for Continues Integration (CI) menggunakan Gitlab CI di on-premise. Ok karena artikel ini akan lumayan panjang jadi kita akan bagi2 menjadi beberapa bagian yaitu Requirement and prequisite Arsitektur Setup &amp; Konfigurasi software Install gitlab Install &amp; setting docker engine Install gitlab runner Register gitlab-runner to gitlab Tryout Gitlab CI script Ok langsung ja kita ke pembahasan pertama yaitu]]></summary></entry><entry xml:lang="gitlab"><title type="html">Introduction of Gitlab DevSecOps Platform</title><link href="/posts/git/gitlab/gitlab-ci/03b-introduction-gitlab-ci" rel="alternate" type="text/html" title="Introduction of Gitlab DevSecOps Platform" /><published>2023-06-17T20:36:43+07:00</published><updated>2023-06-17T20:36:43+07:00</updated><id>/posts/git/gitlab/gitlab-ci/03b-introduction-gitlab-ci</id><content type="html" xml:base="/posts/git/gitlab/gitlab-ci/03b-introduction-gitlab-ci"><![CDATA[<p>Hai semuanya, di materi kali ini kita akan membahas salah satu tools implementasi dari Continues Integration (CI) yaitu menggunakan Gitlab DevSecOps Platform.</p>

<p>Okay karena pembahasan kali ini akan lumayan panjang jadi kita bagi-bagi menjadi beberapa section diantaranya:</p>

<ol>
  <li>Gitlab DevSecOps Platform</li>
  <li>Gitlab CI/CD workflow</li>
  <li>What can Gitlab CI/CD do?</li>
</ol>

<!--more-->

<h2 id="gitlab-devops-platform">Gitlab DevOps Platform</h2>

<div class="feature__wrapper">

  
    <div class="feature__item--right">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-devsecops-platform.png" alt="gitlab-devsecops-platform" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Gitlab Features</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Fundamentally changing the way Development, Security, and Ops teams collaborate and build software - GitLab provides all of the essential DevSecOps tools in one DevSecOps platform. <br /><br />From idea to production, GitLab helps teams improve cycle time from weeks to minutes, reduce development costs, speed time to market, and deliver more secure and compliant applications.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  

</div>

<div class="feature__wrapper">

  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-plan.png" alt="gitlab-plan" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Planning</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Regardless of your process, GitLab provides powerful planning tools to keep everyone synchronized.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-create.png" alt="gitlab-create" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Create</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Create, view, and manage code and project data through powerful branching tools.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-verify.png" alt="gitlab-verify" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Verify</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Keep strict quality standards for production code with automatic testing and reporting.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-package.png" alt="gitlab-package" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Package</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Create a consistent and dependable software supply chain with built-in package management.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-secure.png" alt="gitlab-secure" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Secure</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Security capabilities, integrated into your development lifecycle.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-release.png" alt="gitlab-release" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Deploy</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>GitLab’s integrated CD solution allows you to ship code with zero-touch, be it on one or one thousand servers.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-monitor.png" alt="gitlab-monitor" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Monitor</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Help reduce the severity and frequency of incidents.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/gitlab-govern.png" alt="gitlab-govern" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Govern</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Manage security vulnerabilities, policies, and compliance across your organization.</p>

            </div>
          

          
        </div>
      </div>
    </div>
  

</div>

<h2 id="gitlab-cicd-workflow">Gitlab CI/CD workflow</h2>

<p>Gitlab CI menawarkan 3 konsep yaitu <strong>Continues Integration</strong>, <strong>Continues Delivery</strong> dan <strong>Continues Deployment</strong>. Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more, so you can test, build, and publish your software with no third-party application or integration needed because Gitlab CI is the part of Gitlab.</p>

<p>GitLab CI/CD fits in a common development workflow.</p>

<p>You can start by discussing a code implementation in an issue and working locally on your proposed changes. 
Then you can push your commits to a feature branch in a remote repository that’s hosted in GitLab. 
The push triggers the CI/CD pipeline for your project. Then, GitLab CI/CD:</p>

<p>Runs automated scripts (sequentially or in parallel) to:</p>
<ul>
  <li>Build and test your application.</li>
  <li>Preview the changes in a Review App, the same as you would see on your localhost.</li>
</ul>

<p>After the implementation works as expected:</p>
<ul>
  <li>Get your code reviewed and approved.</li>
  <li>Merge the feature branch into the default branch.</li>
  <li>GitLab CI/CD deploys your changes automatically to a production environment.</li>
  <li>If something goes wrong, you can roll back your changes.</li>
</ul>

<p><img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/basic-gitlab-ci.png" alt="basic-gitlab-ci-workflow" /></p>

<p>This workflow shows the major steps in the GitLab process. You don’t need any external tools to deliver your software and you can visualize all the steps in the GitLab UI.</p>

<h2 id="what-can-gitlab-cicd-do">What can Gitlab CI/CD do?</h2>

<p>If you look deeper into the workflow, you can see the features available in GitLab at each stage of the DevOps lifecycle.</p>

<p><img src="/resources/posts/gitlab-ci/03b-intro-gitlab-ci/advanced-gitlab-ci.png" alt="advanced-gitlab-ci-workflow" /></p>

<p>Stages continues integration:</p>

<ul>
  <li><strong>Code quality</strong>, To measure/analyze your source code’s quality and complexity.</li>
  <li><strong>Unit tests</strong>, To test your source code’s with automated</li>
  <li><strong>Dependency scanning</strong>, To measure/analyze your dependencies is verify and not contains vulnerability</li>
</ul>

<p>Stages continues delivery/deployment:</p>

<ul>
  <li><strong>Build &amp; Package</strong>, To compile then wrap your source code’s into package, it’s can be executeable from anywere</li>
  <li><strong>Shipping</strong>, After build script succeed, we can store that artifact to registry such as Container registry, NPM registry, Maven repository and etc.</li>
  <li><strong>Deploy</strong>, After artifact stored on registry/repository, we can used that object to run the application</li>
</ul>]]></content><author><name>Dimas Maryanto</name></author><category term="git" /><category term="gitlab" /><category term="gitlab-ci" /><summary type="html"><![CDATA[Hai semuanya, di materi kali ini kita akan membahas salah satu tools implementasi dari Continues Integration (CI) yaitu menggunakan Gitlab DevSecOps Platform. Okay karena pembahasan kali ini akan lumayan panjang jadi kita bagi-bagi menjadi beberapa section diantaranya: Gitlab DevSecOps Platform Gitlab CI/CD workflow What can Gitlab CI/CD do?]]></summary></entry><entry xml:lang="gitlab"><title type="html">What is Continues Integration/Continues Delivery (CI/CD)?</title><link href="/posts/git/gitlab/gitlab-ci/03a-what-is-cicd" rel="alternate" type="text/html" title="What is Continues Integration/Continues Delivery (CI/CD)?" /><published>2023-06-17T16:52:30+07:00</published><updated>2023-06-17T16:52:30+07:00</updated><id>/posts/git/gitlab/gitlab-ci/03a-what-is-cicd</id><content type="html" xml:base="/posts/git/gitlab/gitlab-ci/03a-what-is-cicd"><![CDATA[<p>Hai semuanya, di materi kali ini kita akan membahas seputar <strong>Continues Integration and Continues Delivery</strong> alias <strong>CI/CD</strong> dalam suatu SDLC atau singkatan dari <strong>Software Development Lifecycle</strong>.</p>

<p>Pada suatu project/product berbasis software development ini memiliki beberapa tahapan mulai dari coding, testing, dan deployment. Hal ini menjadi tantangan tersendiri jika melibatkan beberapa team/divisi/perusahaan dalam suatu development project/product tersebut.</p>

<p><img src="/resources/posts/gitlab-ci/03a-what-cicd/cicd.svg" alt="ci-ci" /></p>

<p>Saat ini banyak perusahaan/instansi menggunakan proses CI/CD untuk menghilankan kerumitan (simplify) dalam proses release suatu project/product agar bisa lebih cepet dan autopilot (automation deployment).</p>

<p>Sebelum kita membahas lebih jauh, ada beberapa hal yang kita perlu pahami terlebih dahulu tentang CI/CD diantaranya:</p>

<ol>
  <li>What is Continues Integration &amp; Continues Delivery/Deployment (CI/CD)?</li>
  <li>What is the difference between CI and CD?</li>
  <li>How does CI/CD relate to DevOps?</li>
  <li>Benefit of implemented CI/CD in SDLC</li>
  <li>What are the benefits of CI/CD?</li>
  <li>CI/CD software tools</li>
</ol>

<p>Okay tanpa berlama lama yuk kita bahas satu-per-satu</p>

<!--more-->

<h2 id="what-is-continues-integration--continues-deliverydeployment-cicd">What is Continues Integration &amp; Continues Delivery/Deployment (CI/CD)?</h2>

<blockquote>
  <p>CI and CD stand for continuous integration and continuous delivery/continuous deployment. CI/CD is a method to frequently deliver apps to customers by introducing automation into the stages of app development.</p>
</blockquote>

<p>Main concepts attributed to CI/CD are</p>

<ol>
  <li>Continuous integration,</li>
  <li>Continuous delivery, and</li>
  <li>Continuous deployment.</li>
</ol>

<p>CI/CD is a solution to the problems integrating new code can cause for development and operations teams. 
Specifically, CI/CD introduces ongoing automation and continuous monitoring throughout the lifecycle of apps, from integration and testing phases to delivery and deployment. 
Taken together, these connected practices are often referred to as a “CI/CD pipeline” and are supported by development and operations teams working together in an agile way.</p>

<p>Why is CI/CD important?</p>

<p>CI/CD allows organizations to ship software quickly and efficiently. CI/CD facilitates an effective process for getting products to market faster than ever before, continuously delivering code into production, and ensuring an ongoing flow of new features and bug fixes via the most efficient delivery method.</p>

<h2 id="what-is-the-difference-between-ci-and-cd">What is the difference between CI and CD?</h2>

<p>Kita telah mengenal Continues integration dan Continues Delivery/Deployment alias CI/CD, tetapi apa sih sebetulnya perbedaan diantaranya? yuk kita bahas satu-per-satu mulai dari Continues Integration.</p>

<p><strong>Continuous Integration</strong>, Consider an application that has its code stored in a Git repository. Developers push code changes every day, multiple times a day. For every push to the repository, you can create a set of scripts to build and test your application automatically. These scripts help decrease the chances that you introduce errors in your application.</p>

<p>Each change submitted to an application, even to development branches, is built and tested automatically and continuously. These tests ensure the changes pass all tests, guidelines, and code compliance standards you established for your application.</p>

<p><strong>Continuous Delivery</strong>, is a step beyond Continuous Integration. Not only is your application built and tested each time a code change is pushed to the codebase, the application is also deployed continuously. However, with continuous delivery, you trigger the deployments manually.</p>

<p>Continuous Delivery checks the code automatically, but it requires human intervention to manually and strategically trigger the deployment of the changes.</p>

<p><strong>Continuous Deployment</strong>, is another step beyond Continuous Integration, similar to Continuous Delivery. The difference is that instead of deploying your application manually, you set it to be deployed automatically. Human intervention is not required.</p>

<p>For more details, here is the diagram ci/cd workflow</p>

<p><img src="/resources/posts/gitlab-ci/03a-what-cicd/ci-cd-workflow.png" alt="ci-ci-workflow" /></p>

<h2 id="how-does-cicd-relate-to-devops">How does CI/CD relate to DevOps?</h2>

<p>DevOps is a set of practices and tools designed to increase an organization’s ability to deliver applications and services faster than traditional software development processes. 
The increased speed of DevOps helps an organization serve its customers more successfully and be more competitive in the market. In a DevOps environment, successful organizations “bake security in” to all phases of the development life cycle, a practice called DevSecOps.</p>

<p>The key practice of DevSecOps is integrating security into all DevOps workflows. By conducting security activities early and consistently throughout the software development life cycle (SDLC), organizations can ensure that they catch vulnerabilities as early as possible, and are better able to make informed decisions about risk and mitigation. 
In more traditional security practices, security is not addressed until the production stage, which is no longer compatible with the faster and more agile DevOps approach. 
Today, security tools must fit seamlessly into the developer workflow and the CI/CD pipeline in order to keep pace with DevOps and not slow development velocity.</p>

<p><img src="/resources/posts/gitlab-ci/03a-what-cicd/devops-tools.jpeg" alt="devops-tools" /></p>

<p>The CI/CD pipeline is part of the broader DevOps/DevSecOps framework. In order to successfully implement and run a CI/CD pipeline, organizations need tools to prevent points of friction that slow down integration and delivery. 
Teams require an integrated toolchain of technologies to facilitate collaborative and unimpeded development efforts.</p>

<h2 id="what-are-the-benefits-of-cicd">What are the benefits of CI/CD?</h2>

<ul>
  <li>Automated testing enables continuous delivery, which ensures software quality and security and increases the profitability of code in production.</li>
  <li>CI/CD pipelines enable a much shorter time to market for new product features, creating happier customers and lowering strain on development.</li>
  <li>The great increase in overall speed of delivery enabled by CI/CD pipelines improves an organization’s competitive edge.</li>
  <li>Automation frees team members to focus on what they do best, yielding the best end products.</li>
  <li>Organizations with a successful CI/CD pipeline can attract great talent. By moving away from traditional waterfall methods, engineers and developers are no longer bogged down with repetitive activities that are often highly dependent on the completion of other tasks.</li>
</ul>

<h2 id="cicd-software-tools">CI/CD software tools</h2>

<p>Ada beberapa software tools yang dapat digunakan untuk membuat CI/CD Pipeline. Diantaranya sebagai berikut:</p>

<div class="feature__wrapper">

  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03a-what-cicd/tools-jenkins.png" alt="tools-jenkins" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Jenkins</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Jenkins ini bersifat open source dan menggunakan bahasa pemrograman Java. Tool ini dapat digunakan pada berbagai sistem operasi seperti Windows, macOS, dan Linux serta dapat di deploy cloud maupun on-premise</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03a-what-cicd/tools-gitlab-ci.png" alt="tools-gitlab-ci" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Gitlab CI</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Gitlab CI adalah bagian dari Gitlab Platform yang dibuat oleh gitlab itu sendiri dengan menggunakan bahasa Golang (go). Tool ini dapat digunakan di berbagai macam sistem operasi seperti Windows, macOS, dan linux. <br />Kita bisa mengguankan Gitlab CI yang telah tersedia (Shared runner) atau self managed (Private runner)</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03a-what-cicd/tools-github-action.png" alt="tools-github-action" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Github Action</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Github Action adalah bagian dari Github Platform yang dibuat oleh github yang sekarang telah di akuisisi oleh Microsoft. Tools ini hanya dapat di gunakan secara cloud (github.com) dan kita bisa gunakan secara gratis/free</p>

            </div>
          

          
        </div>
      </div>
    </div>
  
    <div class="feature__item">
      <div class="archive__item">
        

        
          <div class="archive__item-teaser">
            <img src="/resources/posts/gitlab-ci/03a-what-cicd/tools-travis-ci.png" alt="tools-travis-ci" />
            
          </div>
        

        <div class="archive__item-body text-left">
          
            <h2 class="archive__item-title">Travis CI</h2>
          

          
            <div class="archive__item-excerpt text-justify">
              <p>Travis CI adalah cloud-based CI/CD yang biasanya digunakan sebelum lahirnya Github Action yang memiliki jargon Code less dan deploy more. Tools ini juga selain hanya tersedia di cloud juga saat ini menjadi platform CI/CD yang berbayar</p>

            </div>
          

          
        </div>
      </div>
    </div>
  

</div>]]></content><author><name>Dimas Maryanto</name></author><category term="git" /><category term="gitlab" /><category term="gitlab-ci" /><summary type="html"><![CDATA[Hai semuanya, di materi kali ini kita akan membahas seputar Continues Integration and Continues Delivery alias CI/CD dalam suatu SDLC atau singkatan dari Software Development Lifecycle. Pada suatu project/product berbasis software development ini memiliki beberapa tahapan mulai dari coding, testing, dan deployment. Hal ini menjadi tantangan tersendiri jika melibatkan beberapa team/divisi/perusahaan dalam suatu development project/product tersebut. Saat ini banyak perusahaan/instansi menggunakan proses CI/CD untuk menghilankan kerumitan (simplify) dalam proses release suatu project/product agar bisa lebih cepet dan autopilot (automation deployment). Sebelum kita membahas lebih jauh, ada beberapa hal yang kita perlu pahami terlebih dahulu tentang CI/CD diantaranya: What is Continues Integration &amp; Continues Delivery/Deployment (CI/CD)? What is the difference between CI and CD? How does CI/CD relate to DevOps? Benefit of implemented CI/CD in SDLC What are the benefits of CI/CD? CI/CD software tools Okay tanpa berlama lama yuk kita bahas satu-per-satu]]></summary></entry><entry xml:lang="gitlab"><title type="html">Silabus Gitlab CI: Pemula s/d Mahir</title><link href="/posts/git/gitlab/gitlab-ci/03-silabus-gitlab-ci" rel="alternate" type="text/html" title="Silabus Gitlab CI: Pemula s/d Mahir" /><published>2023-06-02T20:18:43+07:00</published><updated>2023-06-02T20:18:43+07:00</updated><id>/posts/git/gitlab/gitlab-ci/03-silabus-gitlab-ci</id><content type="html" xml:base="/posts/git/gitlab/gitlab-ci/03-silabus-gitlab-ci"><![CDATA[<p>Hai semuanya, selamat datang kembali di kelas <strong>GitOps dengan Gitlab untuk Pemula s/d Mahir</strong> materi kali ini kita membahas tentang Continues Integration (CI) dengan menggunakan Gitlab Platform yaitu Gitlab CI.</p>

<p>Pada materi kali ada beberapa topic yang akan kita pelajari yaitu</p>

<!--more-->

<h2 id="basic-concepts-of-gitlab-ci">Basic concepts of Gitlab CI</h2>

<p>GitLab CI/CD uses a number of concepts to describe and run your build and deploy.</p>

<ol>
  <li>What is Gitlab CI</li>
  <li>Seting up Gitlab &amp; Gitlab Runner</li>
  <li>Build a pipeline</li>
  <li>Using CI/CD Variables
    <ul>
      <li>Predefined variables</li>
      <li>User defined variables (custom)</li>
    </ul>
  </li>
  <li>Using environments</li>
  <li>Job artifacts</li>
  <li>Cache depedency</li>
  <li>Job/Pipeline efficiency</li>
  <li>Test case for Unit testing automation</li>
</ol>

<h2 id="configuration-of-gitlab-ci">Configuration of Gitlab CI</h2>

<ol>
  <li>Schedule pipeline</li>
  <li>Pipeline triggers</li>
  <li>Merge request pipeline</li>
  <li>Opimize Gitlab and Gitlab Runner for large repositories</li>
</ol>

<h2 id="feature-of-gitlab-ci">Feature of Gitlab CI</h2>

<ol>
  <li><strong>Auto DevOps</strong>, Set up your app’s entire lifecycle.</li>
  <li><strong>CI services</strong>, Link Docker containers with your base image.</li>
  <li><strong>Auto Deploy</strong>, Deploy your application to a production environment in a Kubernetes cluster.</li>
  <li>Build docker image</li>
  <li>Canary deployments</li>
  <li>Deploy boards</li>
  <li>Gitlab release</li>
  <li>Code quality</li>
</ol>

<p>Biasanya Gitlab CI digunakan untuk melakukan Automation seperti build, test, deploy and monitor suatu aplikasi yang dibuat oleh Developer. Karena materinya banyak sekali jadi kita akan breakdown semua meteri tersebut mejadi beberapa bagian. So mungkin sekian dulu apa yang bisa saya sampaikan terkait Silabus belajar Gitlab CI untuk Automation. 👋</p>]]></content><author><name>Dimas Maryanto</name></author><category term="git" /><category term="gitlab" /><category term="gitlab-ci" /><summary type="html"><![CDATA[Hai semuanya, selamat datang kembali di kelas GitOps dengan Gitlab untuk Pemula s/d Mahir materi kali ini kita membahas tentang Continues Integration (CI) dengan menggunakan Gitlab Platform yaitu Gitlab CI. Pada materi kali ada beberapa topic yang akan kita pelajari yaitu]]></summary></entry><entry xml:lang="k8s"><title type="html">Working with Deployment object</title><link href="/posts/devops/orchestration/kubernetes/workloads/05b-deployment" rel="alternate" type="text/html" title="Working with Deployment object" /><published>2023-04-29T11:51:37+07:00</published><updated>2023-04-29T11:51:37+07:00</updated><id>/posts/devops/orchestration/kubernetes/workloads/05b-deployment</id><content type="html" xml:base="/posts/devops/orchestration/kubernetes/workloads/05b-deployment"><![CDATA[<p>Hai semuanya, materi sebelumnya kita sudah mencoba menggunakan Kubernetes workload resources dengan Object Deployment yang paling simple. Sekarang kita akan membahas yang lebih detail tentang Object Deployment. Karena pembahasan kali ini lumayan panjang jadi kita bagi2 jadi beberapa bagian diantaranya:</p>

<ol>
  <li>What is Deployment Object?</li>
  <li>Create a Deployment</li>
  <li>Interaction with Deployment object
    <ul>
      <li>Updating a Deployment</li>
      <li>Rolling Back a Deployment</li>
      <li>Scalling the pods with a Deployment</li>
      <li>Pause and Resume rollout of a Deployment</li>
    </ul>
  </li>
  <li>Deployment status
    <ul>
      <li><code class="language-plaintext highlighter-rouge">type: progressing</code></li>
      <li><code class="language-plaintext highlighter-rouge">type: complete</code></li>
      <li><code class="language-plaintext highlighter-rouge">type: failed</code></li>
      <li><code class="language-plaintext highlighter-rouge">type: pending</code></li>
    </ul>
  </li>
</ol>

<p>Okay tanpa berlama-lama yuk langsung aja kita bahas materi yang pertama:</p>

<!--more-->

<h2 id="what-is-deployment-object">What is Deployment Object</h2>

<p>Seperti yang telah saya bahas di materi sebelumnya, Deployment adalah salah satu Workload resources yang digunakan untuk me-manage Pod dan container yang paling cocok untuk aplikasi Stateless atau tidak menyimpan data.</p>

<p>A Deployment provides declarative updates for Pods and ReplicaSets.</p>

<p>You describe a desired state in a Deployment, and the Deployment Controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments.</p>

<p><img src="/resources/posts/kubernetes/05b-deployment/deployment-flow.png" alt="deployment-flow" /></p>

<p>The following are typical use cases for Deployments:</p>

<ol>
  <li>Create a Deployment to rollout a ReplicaSet. The ReplicaSet creates Pods in the background. Check the status of the rollout to see if it succeeds or not.</li>
  <li>Declare the new state of the Pods by updating the <code class="language-plaintext highlighter-rouge">PodTemplateSpec</code> of the Deployment. A new ReplicaSet is created and the Deployment manages moving the Pods from the old ReplicaSet to the new one at a controlled rate. Each new ReplicaSet updates the revision of the Deployment.</li>
  <li>Rollback to an earlier Deployment revision if the current state of the Deployment is not stable. Each rollback updates the revision of the Deployment.</li>
  <li>Scale up the Deployment to facilitate more load.</li>
  <li>Pause the rollout of a Deployment to apply multiple fixes to its <code class="language-plaintext highlighter-rouge">PodTemplateSpec</code> and then resume it to start a new rollout.</li>
  <li>Use the status of the Deployment as an indicator that a rollout has stuck.</li>
  <li>Clean up older ReplicaSets that you don’t need anymore.</li>
</ol>

<h2 id="create-deployment-using-yaml-file">Create Deployment using yaml file</h2>

<p>Untuk membuat object deployment bisa menggunakan imperative command (<code class="language-plaintext highlighter-rouge">kubectl create deploy</code>) dan declarative seperti membuat file extension <code class="language-plaintext highlighter-rouge">.yaml</code> atau <code class="language-plaintext highlighter-rouge">.json</code> yang kemudian di execute menggunakan perintah <code class="language-plaintext highlighter-rouge">kubectl apply -f filename.yaml</code>.</p>

<p>Berikut adalah basic Deployment spec yang digunakan untuk membuat/menjalankan 3 buah pod dengan container image <code class="language-plaintext highlighter-rouge">nginx</code> seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/96f6954c9a27a6b1934113b10223196a.js?file=05b-basic-deploy-nginx.yaml"> </script>

<p>Kemudian coba jalankan menggunakan perintah:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl apply <span class="nt">-f</span> basic-deployment.yaml</code></pre></figure>

<p>Jika kita lihat hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➡ kubectl apply <span class="nt">-f</span> 03-workloads/01-basic-deploy/basic-deployment.yaml
deployment.apps/nginx-deploy created

➜ kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   3/3     3            3           3m21s

➜ kubectl get rs
NAME                     DESIRED   CURRENT   READY   AGE
nginx-deploy-c9bcb48d4   3         3         3       3m39s

➜ kubectl get pod
NAME                           READY   STATUS    RESTARTS   AGE
nginx-deploy-c9bcb48d4-5s7zs   1/1     Running   0          82s
nginx-deploy-c9bcb48d4-nrsr7   1/1     Running   0          3m54s
nginx-deploy-c9bcb48d4-rbc8s   1/1     Running   0          82s
</code></pre></div></div>

<p>In this example:</p>

<ol>
  <li>
    <p>A Deployment named <code class="language-plaintext highlighter-rouge">nginx-deploy</code> is created, indicated by the <code class="language-plaintext highlighter-rouge">.metadata.name</code> field. This name will become the basis for the ReplicaSets and Pods which are created later. See <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#writing-a-deployment-spec">Writing a Deployment Spec</a> for more details.</p>
  </li>
  <li>
    <p>The Deployment creates a ReplicaSet that creates three replicated Pods, indicated by the <code class="language-plaintext highlighter-rouge">.spec.replicas</code> field.</p>
  </li>
  <li>
    <p>The <code class="language-plaintext highlighter-rouge">.spec.selector</code> field defines how the created ReplicaSet finds which Pods to manage. In this case, you select a label that is defined in the Pod template (<code class="language-plaintext highlighter-rouge">app: nginx</code>, <code class="language-plaintext highlighter-rouge">env: test</code>). However, more sophisticated selection rules are possible, as long as the Pod template itself satisfies the rule.</p>
  </li>
  <li>
    <p>The <code class="language-plaintext highlighter-rouge">template</code> field contains the following sub-fields:</p>

    <ol>
      <li>The Pods are labeled <code class="language-plaintext highlighter-rouge">app: nginx</code> using the <code class="language-plaintext highlighter-rouge">.metadata.labels</code> field.</li>
      <li>The Pod template’s specification, or <code class="language-plaintext highlighter-rouge">.template.spec</code> field, indicates that the Pods run one container, <code class="language-plaintext highlighter-rouge">nginx</code>, which runs the <code class="language-plaintext highlighter-rouge">nginx</code> Docker <a href="https://hub.docker.com/_/nginx">Hub image</a> at version [mainline].</li>
      <li>Create one container and name it <code class="language-plaintext highlighter-rouge">nginx</code> using the <code class="language-plaintext highlighter-rouge">.spec.template.spec.containers[0].name</code> field.</li>
    </ol>
  </li>
</ol>

<h2 id="interaction-with-development-object">Interaction with Development object</h2>

<p>Untuk berinteraksi dengan object deployment ada beberapa function/command yang kita bisa gunakan seperti</p>

<ol>
  <li>Melihat log pada suatu pod,</li>
  <li>Meng-execute command pada suatu pod dari sekumpulan pod,</li>
  <li>Merestart seluruh pod dalam deployment,</li>
  <li>Updating a deployment spec,</li>
  <li>Rolling back to previews history version,</li>
  <li>Scalling deployment</li>
  <li>Proportional scalling deployment (autoscalling)</li>
</ol>

<p>Okay sekarang kita coba satu-per-satu yuk, Untuk melihat logs pada suatu pod yang ada pada suatu deployment kita bisa menggunakan perintah <code class="language-plaintext highlighter-rouge">kubectl logs deploy/&lt;deploy-name&gt;</code> contohnya seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl logs deploy/nginx-deploy</code></pre></figure>

<p>Jika dijalankan maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   3/3     3            3           111s

➜ kubectl get pod
NAME                           READY   STATUS    RESTARTS   AGE
nginx-deploy-c9bcb48d4-dzg7p   1/1     Running   0          7m41s
nginx-deploy-c9bcb48d4-nrq4k   1/1     Running   0          7m41s
nginx-deploy-c9bcb48d4-qgf9d   1/1     Running   0          7m41s

➜ kubectl logs deploy/nginx-deploy
Found 3 pods, using pod/nginx-deploy-c9bcb48d4-dzg7p
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking <span class="k">for </span>shell scripts <span class="k">in</span> /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 <span class="k">in</span> /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration <span class="nb">complete</span><span class="p">;</span> ready <span class="k">for </span>start up
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: using the <span class="s2">"epoll"</span> event method
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: nginx/1.23.4
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: built by gcc 10.2.1 20210110 <span class="o">(</span>Debian 10.2.1-6<span class="o">)</span>
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: OS: Linux 5.10.57
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: getrlimit<span class="o">(</span>RLIMIT_NOFILE<span class="o">)</span>: 1048576:1048576
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: start worker processes
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: start worker process 29
2023/04/09 02:31:40 <span class="o">[</span>notice] 1#1: start worker process 30
</code></pre></div></div>

<p>Nah jika temen-temen perhatikan, pada deployment <code class="language-plaintext highlighter-rouge">nginx-deploy</code> memiliki lebih dari 1 pod tetapi yang ditampilkan adalah pod yang pertama by default yaitu <code class="language-plaintext highlighter-rouge">pod/nginx-deploy-c9bcb48d4-dzg7p</code></p>

<p>Selanjutnya, jika kita mau meng-execute command dalam container dari object deployment bisa menggunakan perintah <code class="language-plaintext highlighter-rouge">kubectl exec deploy/&lt;deploy-name&gt; -- &lt;command&gt;</code> seperti berikut contohnya:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl <span class="nb">exec </span>deploy/nginx-deploy <span class="nt">--</span> curl https://jsonplaceholder.typicode.com/todos/1 <span class="nt">-v</span></code></pre></figure>

<p>Maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl <span class="nb">exec </span>deploy/nginx-deploy <span class="nt">--</span> curl https://jsonplaceholder.typicode.com/todos/1 <span class="nt">-v</span>
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:--     0<span class="k">*</span>   Trying 104.21.54.83:443...
<span class="o">&gt;</span> GET /todos/1 HTTP/2
<span class="o">&gt;</span> Host: jsonplaceholder.typicode.com
<span class="o">&gt;</span> user-agent: curl/7.74.0
<span class="o">&gt;</span> accept: <span class="k">*</span>/<span class="k">*</span>
<span class="o">&gt;</span>
&lt; report-to: <span class="o">{</span><span class="s2">"endpoints"</span>:[<span class="o">{</span><span class="s2">"url"</span>:<span class="s2">"https:</span><span class="se">\/\/</span><span class="s2">a.nel.cloudflare.com</span><span class="se">\/</span><span class="s2">report</span><span class="se">\/</span><span class="s2">v3?s=vGRPnjpH6UP1fT0COF95QYK5RIuA2jrZPx1H6jsOVkWrVhLGjRAZYkd1izYBf04YbE4JXWKihCdw1YLrZJZBxAIMLCCW7ViJ6QUbOx%2F06hsARokb7XjEJ%2FUoacL9So%2BACJ%2BGsdUqgOuXf9w5HYUp"</span><span class="o">}]</span>,<span class="s2">"group"</span>:<span class="s2">"cf-nel"</span>,<span class="s2">"max_age"</span>:604800<span class="o">}</span>
&lt; nel: <span class="o">{</span><span class="s2">"success_fraction"</span>:0,<span class="s2">"report_to"</span>:<span class="s2">"cf-nel"</span>,<span class="s2">"max_age"</span>:604800<span class="o">}</span>
&lt; server: cloudflare
&lt; cf-ray: 7b4f65c4a8254b80-SIN
&lt; alt-svc: <span class="nv">h3</span><span class="o">=</span><span class="s2">":443"</span><span class="p">;</span> <span class="nv">ma</span><span class="o">=</span>86400, h3-29<span class="o">=</span><span class="s2">":443"</span><span class="p">;</span> <span class="nv">ma</span><span class="o">=</span>86400
&lt;
<span class="o">{</span> <span class="o">[</span>83 bytes data]
<span class="o">{</span>
  <span class="s2">"userId"</span>: 1,
  <span class="s2">"id"</span>: 1,
  <span class="s2">"title"</span>: <span class="s2">"delectus aut autem"</span>,
  <span class="s2">"completed"</span>: <span class="nb">false
</span>100    83  100    83    0     0   1136      0 <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:--  1136
<span class="k">*</span> Connection <span class="c">#0 to host jsonplaceholder.typicode.com left intact</span>
</code></pre></div></div>

<p>Kemudian jika kita mau me-restart semua pod sekaligus dalam object deployment kita bisa menggunakan perintah <code class="language-plaintext highlighter-rouge">kubectl rollout restart deploy/&lt;deploy-name&gt;</code> seperti berikut contohnya:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout restart deploy/nginx-deploy</code></pre></figure>

<p>Jika dijalankan maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout restart deploy/nginx-deploy <span class="o">&amp;&amp;</span> <span class="se">\</span>
cmdand&gt; kubectl get pod <span class="nt">-w</span>
deployment.apps/nginx-deploy restarted
NAME                           READY   STATUS              RESTARTS   AGE
nginx-deploy-c9bcb48d4-dzg7p   1/1     Running             0          14m
nginx-deploy-c9bcb48d4-nrq4k   1/1     Running             0          14m
nginx-deploy-c9bcb48d4-qgf9d   1/1     Running             0          14m
nginx-deploy-fdd7c9d69-zw8xn   0/1     ContainerCreating   0          0s
nginx-deploy-fdd7c9d69-zw8xn   1/1     Running             0          16s
nginx-deploy-c9bcb48d4-nrq4k   1/1     Terminating         0          14m
nginx-deploy-fdd7c9d69-28pm7   0/1     ContainerCreating   0          0s
nginx-deploy-c9bcb48d4-nrq4k   0/1     Terminating         0          14m
nginx-deploy-fdd7c9d69-28pm7   1/1     Running             0          16s
nginx-deploy-c9bcb48d4-qgf9d   1/1     Terminating         0          14m
nginx-deploy-fdd7c9d69-jh872   0/1     ContainerCreating   0          0s
nginx-deploy-fdd7c9d69-jh872   1/1     Running             0          1s
nginx-deploy-c9bcb48d4-dzg7p   1/1     Terminating         0          14m
nginx-deploy-c9bcb48d4-dzg7p   0/1     Terminating         0          14m
</code></pre></div></div>

<p>Okay nah itu adalah salah satu interacation yang paling simple pada object deployment, Untuk update deployment spec, rolling back to previews version akan di bahas pada section selanjutnya ya supaya tidak terlalu panjang.</p>

<h3 id="updating-a-deployment">Updating a Deployment</h3>

<p>Ada beberapa cara melakukan update suatu Deployment object pada kubernetes</p>

<ol>
  <li>Using <code class="language-plaintext highlighter-rouge">kubectl set</code> command</li>
  <li>Using <code class="language-plaintext highlighter-rouge">kubectl edit deploy/&lt;deploy-name&gt;</code></li>
  <li>Using declarative file kemudian menjalakan <code class="language-plaintext highlighter-rouge">kubectl apply -f</code> command</li>
</ol>

<p>For example, saya mau update image deployment versionnya dari <code class="language-plaintext highlighter-rouge">mainline</code> menjadi <code class="language-plaintext highlighter-rouge">stable-alpine</code> jadi perintahnya seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl <span class="nb">set </span>image deploy/nginx-deploy nginx-deploy<span class="o">=</span>nginx:stable-alpine</code></pre></figure>

<p>Atau alternative lainnya, kita bisa edit secara langsung di kubernetes clusternya dengan menggunakan perintah</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl edit deploy nginx-deploy</code></pre></figure>

<p>Nah jika kita jalankan outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜  kubectl <span class="nb">set </span>image deploy/nginx-deploy nginx-deploy<span class="o">=</span>nginx:stable-alpine
deployment.apps/nginx-deploy image updated

➜  kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
nginx-deploy-5c7b8c97f6   3         3         3       2m8s
nginx-deploy-c9bcb48d4    0         0         0       168m

➜  kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-5c7b8c97f6-jgt2p   1/1     Running   0          2m54s
nginx-deploy-5c7b8c97f6-k7jnf   1/1     Running   0          3m4s
nginx-deploy-5c7b8c97f6-mzg4m   1/1     Running   0          3m16s

➜  kubernetes git:<span class="o">(</span>main<span class="o">)</span> kubectl describe pod/nginx-deploy-5c7b8c97f6-jgt2p
Name:             nginx-deploy-5c7b8c97f6-jgt2p
Namespace:        default
Node:             minikube/192.168.105.9
Labels:           <span class="nv">app</span><span class="o">=</span>nginx
                  <span class="nb">env</span><span class="o">=</span><span class="nb">test
                  </span>pod-template-hash<span class="o">=</span>5c7b8c97f6
Status:           Running
IP:               10.244.0.5
IPs:
  IP:           10.244.0.5
Controlled By:  ReplicaSet/nginx-deploy-5c7b8c97f6
Containers:
  nginx-deploy:
    Image:          nginx:stable-alpine
    Port:           80/TCP
    State:          Running
      Started:      Fri, 07 Apr 2023 17:29:38 +0700
    Ready:          True
    Restart Count:  0
    Environment:    &lt;none&gt;
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Events:
  Type    Reason     Age    From               Message
  <span class="nt">----</span>    <span class="nt">------</span>     <span class="nt">----</span>   <span class="nt">----</span>               <span class="nt">-------</span>
  Normal  Scheduled  3m32s  default-scheduler  Successfully assigned default/nginx-deploy-5c7b8c97f6-jgt2p to minikube
  Normal  Pulling    3m32s  kubelet            Pulling image <span class="s2">"nginx:stable-alpine"</span>
  Normal  Pulled     3m22s  kubelet            Successfully pulled image <span class="s2">"nginx:stable-alpine"</span> <span class="k">in </span>9.54521492s <span class="o">(</span>9.545224254s including waiting<span class="o">)</span>
  Normal  Created    3m22s  kubelet            Created container nginx-deploy
  Normal  Started    3m22s  kubelet            Started container nginx-deploy
</code></pre></div></div>

<p>Get more details on your updated Deployment:</p>

<ol>
  <li>
    <p>After the rollout succeeds, you can view the Deployment by running <code class="language-plaintext highlighter-rouge">kubectl get deployments</code>. The output is similar to this:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> NAME           READY   UP-TO-DATE   AVAILABLE   AGE
 nginx-deploy   3/3     3            3           3h6m
</code></pre></div>    </div>
  </li>
  <li>
    <p>Run <code class="language-plaintext highlighter-rouge">kubectl get rs</code> to see that the Deployment updated the Pods by creating a new ReplicaSet and scaling it up to <code class="language-plaintext highlighter-rouge">3</code> replicas, as well as scaling down the old ReplicaSet to <code class="language-plaintext highlighter-rouge">0</code> replicas.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> NAME                      DESIRED   CURRENT   READY   AGE
 nginx-deploy-5c7b8c97f6   3         3         3       6m33s
 nginx-deploy-c9bcb48d4    0         0         0       173m
</code></pre></div>    </div>
  </li>
  <li>
    <p>Run <code class="language-plaintext highlighter-rouge">kubectl get pod</code>, Running get pods should now show only the new Pods:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> NAME                            READY   STATUS    RESTARTS   AGE
 nginx-deploy-5c7b8c97f6-jgt2p   1/1     Running   0          7m30s
 nginx-deploy-5c7b8c97f6-k7jnf   1/1     Running   0          7m40s
 nginx-deploy-5c7b8c97f6-mzg4m   1/1     Running   0          7m52s
</code></pre></div>    </div>
  </li>
</ol>

<p>Next time you want to update these Pods, you only need to update the Deployment’s Pod template again.</p>

<p>Deployment ensures that only a certain number of Pods are down while they are being updated. By default, it ensures that at least <code class="language-plaintext highlighter-rouge">75%</code> of the desired number of Pods are up (<code class="language-plaintext highlighter-rouge">25%</code> max unavailable).</p>

<p>For example, if you look at the above Deployment closely, you will see that it first creates a new Pod, then deletes an old Pod, and creates another new one. It does not kill old Pods until a sufficient number of new Pods have come up, and does not create new Pods until a sufficient number of old Pods have been killed. It makes sure that at least <code class="language-plaintext highlighter-rouge">3</code> Pods are available and that at max <code class="language-plaintext highlighter-rouge">4</code> Pods in total are available. In case of a Deployment with <code class="language-plaintext highlighter-rouge">4</code> replicas, the number of Pods would be between <code class="language-plaintext highlighter-rouge">3</code> and <code class="language-plaintext highlighter-rouge">5</code>.</p>

<h3 id="rolling-back-a-deployment">Rolling Back a Deployment</h3>

<p>Sometimes, you may want to rollback a Deployment; for example, when the Deployment is not stable, such as crash looping. By default, all of the Deployment’s rollout history is kept in the system so that you can rollback anytime you want (you can change that by modifying revision history limit).</p>

<p>Suppose that you made a typo while updating the Deployment, by putting the image name as <code class="language-plaintext highlighter-rouge">nginx:1.161</code> instead of <code class="language-plaintext highlighter-rouge">nginx:1.16.1</code>:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl <span class="nb">set </span>image deployment/nginx-deploy nginx-deploy<span class="o">=</span>nginx:1.161</code></pre></figure>

<p>Berikut outputnya:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl <span class="nb">set </span>image deployment/nginx-deploy nginx-deploy<span class="o">=</span>nginx:1.161
deployment.apps/nginx-deploy image updated

➜ kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   3/3     1            3           7m13s

➜ kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
nginx-deploy-5c7b8c97f6   3         3         3       7m11s
nginx-deploy-65cbcc896b   1         1         0       36s
nginx-deploy-c9bcb48d4    0         0         0       7m27s

➜ kubectl get pod
NAME                            READY   STATUS         RESTARTS   AGE
nginx-deploy-5c7b8c97f6-6xzfr   1/1     Running        0          7m34s
nginx-deploy-5c7b8c97f6-tvfxv   1/1     Running        0          7m32s
nginx-deploy-5c7b8c97f6-vt5lf   1/1     Running        0          7m33s
nginx-deploy-65cbcc896b-7q6mc   0/1     ErrImagePull   0          59s
</code></pre></div></div>

<p>The rollout gets stuck. You can verify it by checking the rollout status:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout status deploy/nginx-deploy</code></pre></figure>

<p>The output look like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout status deploy/nginx-deploy
Waiting <span class="k">for </span>deployment <span class="s2">"nginx-deploy"</span> rollout to finish: 1 out of 3 new replicas have been updated...
</code></pre></div></div>

<p>Press <code class="language-plaintext highlighter-rouge">Ctrl-C</code> to stop the above rollout status watch. First, check the revisions of this Deployment:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout <span class="nb">history </span>deploy/nginx-deploy</code></pre></figure>

<p>The output look like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout <span class="nb">history </span>deploy/nginx-deploy
deployment.apps/nginx-deploy
REVISION  CHANGE-CAUSE
1         &lt;none&gt;
2         &lt;none&gt;
3         &lt;none&gt;
</code></pre></div></div>

<p>To see the details of each revision, run:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout <span class="nb">history </span>deploy/nginx-deploy <span class="nt">--revision</span><span class="o">=</span>2</code></pre></figure>

<p>The output look like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout <span class="nb">history </span>deploy/nginx-deploy <span class="nt">--revision</span><span class="o">=</span>2
deployment.apps/nginx-deploy with revision <span class="c">#2</span>
Pod Template:
  Labels:	<span class="nv">app</span><span class="o">=</span>nginx
	<span class="nb">env</span><span class="o">=</span><span class="nb">test
	</span>pod-template-hash<span class="o">=</span>5c7b8c97f6
  Containers:
   nginx-deploy:
    Image:	nginx:stable-alpine
    Port:	80/TCP
    Host Port:	0/TCP
    Environment:	&lt;none&gt;
    Mounts:	&lt;none&gt;
  Volumes:	&lt;none&gt;
</code></pre></div></div>

<p>Follow the steps given below to rollback the Deployment from the current version to the previous version, which is version 3.</p>

<p>Now you’ve decided to undo the current rollout and rollback to the previous revision:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout undo deploy/nginx-deploy</code></pre></figure>

<p>The output is similar to this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout undo deploy/nginx-deploy
deployment.apps/nginx-deploy rolled back

➜ kubectl rollout status deploy/nginx-deploy
deployment <span class="s2">"nginx-deploy"</span> successfully rolled out

➜ kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   3/3     3            3           15m

➜ kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
nginx-deploy-5c7b8c97f6   3         3         3       15m
nginx-deploy-65cbcc896b   0         0         0       9m4s
nginx-deploy-c9bcb48d4    0         0         0       15m

➜ kubectl describe deploy nginx-deploy
Name:                   nginx-deploy
Namespace:              default
Labels:                 <span class="nv">app</span><span class="o">=</span>nginx
                        <span class="nb">env</span><span class="o">=</span><span class="nb">test
</span>Annotations:            deployment.kubernetes.io/revision: 4
Selector:               <span class="nv">app</span><span class="o">=</span>nginx,env<span class="o">=</span><span class="nb">test
</span>Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  <span class="nv">app</span><span class="o">=</span>nginx
           <span class="nb">env</span><span class="o">=</span><span class="nb">test
  </span>Containers:
   nginx-deploy:
    Image:        nginx:stable-alpine
    Port:         80/TCP
    Host Port:    0/TCP
NewReplicaSet:   nginx-deploy-5c7b8c97f6 <span class="o">(</span>3/3 replicas created<span class="o">)</span>
Events:
  Type    Reason             Age    From                   Message
  <span class="nt">----</span>    <span class="nt">------</span>             <span class="nt">----</span>   <span class="nt">----</span>                   <span class="nt">-------</span>
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 3
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 1
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 2 from 3
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 2 from 1
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 1 from 2
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 3 from 2
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 0 from 1
  Normal  ScalingReplicaSet  9m42s  deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-65cbcc896b to 1
  Normal  ScalingReplicaSet  97s    deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-65cbcc896b to 0 from 1
</code></pre></div></div>

<p>Alternatively, you can rollback to a specific revision by specifying it with <code class="language-plaintext highlighter-rouge">--to-revision</code>:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout undo deploy/nginx-deploy <span class="nt">--to-revision</span> 1</code></pre></figure>

<p>The output is similar to this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout undo deploy/nginx-deploy <span class="nt">--to-revision</span> 1
deployment.apps/nginx-deploy rolled back

➜ kubectl rollout status deploy/nginx-deploy
deployment <span class="s2">"nginx-deploy"</span> successfully rolled out

➜ kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   3/3     3            3           19m

➜ kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
nginx-deploy-5c7b8c97f6   0         0         0       19m
nginx-deploy-65cbcc896b   0         0         0       12m
nginx-deploy-c9bcb48d4    3         3         3       19m

➜ kubectl describe deploy nginx-deploy
Name:                   nginx-deploy
Namespace:              default
Labels:                 <span class="nv">app</span><span class="o">=</span>nginx
                        <span class="nb">env</span><span class="o">=</span><span class="nb">test
</span>Annotations:            deployment.kubernetes.io/revision: 5
Selector:               <span class="nv">app</span><span class="o">=</span>nginx,env<span class="o">=</span><span class="nb">test
</span>Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  <span class="nv">app</span><span class="o">=</span>nginx
           <span class="nb">env</span><span class="o">=</span><span class="nb">test
  </span>Containers:
   nginx-deploy:
    Image:        nginx:mainline
    Port:         80/TCP
    Host Port:    0/TCP

NewReplicaSet:   nginx-deploy-c9bcb48d4 <span class="o">(</span>3/3 replicas created<span class="o">)</span>
Events:
  Type    Reason             Age                From                   Message
  <span class="nt">----</span>    <span class="nt">------</span>             <span class="nt">----</span>               <span class="nt">----</span>                   <span class="nt">-------</span>
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 3
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 1
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 2 from 3
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 2 from 1
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 1 from 2
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 3 from 2
  Normal  ScalingReplicaSet  19m                deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-c9bcb48d4 to 0 from 1
  Normal  ScalingReplicaSet  12m                deployment-controller  Scaled up replica <span class="nb">set </span>nginx-deploy-65cbcc896b to 1
  Normal  ScalingReplicaSet  4m54s              deployment-controller  Scaled down replica <span class="nb">set </span>nginx-deploy-65cbcc896b to 0 from 1
  Normal  ScalingReplicaSet  61s <span class="o">(</span>x6 over 63s<span class="o">)</span>  deployment-controller  <span class="o">(</span>combined from similar events<span class="o">)</span>: Scaled down replica <span class="nb">set </span>nginx-deploy-5c7b8c97f6 to 0 from 1
</code></pre></div></div>

<h3 id="scalling-the-pods-with-a-deployment">Scalling the pods with a Deployment</h3>

<p>Selain kita bisa meng-update specifikasi pod dan container, kita juga bisa melakukan scalling suatu Deployment object dengan menggunakan beberapa cara yaitu</p>

<ol>
  <li>Using <code class="language-plaintext highlighter-rouge">kubectl scale deploy/&lt;deploy-name&gt; --replicas=&lt;number-of-instance&gt;</code> command</li>
  <li>Using <code class="language-plaintext highlighter-rouge">kubectl edit deploy/&lt;deploy-name&gt;</code></li>
  <li>Update <code class="language-plaintext highlighter-rouge">deployment.yaml</code> file then using <code class="language-plaintext highlighter-rouge">kubectl apply -f</code></li>
</ol>

<p>For example, saya mau update secara langsung dengan perintahnya seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl scale deploy/nginx-deploy <span class="nt">--replicas</span><span class="o">=</span>5</code></pre></figure>

<p>Jika kita coba jalankan maka seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➡ kubectl scale deploy/nginx-deploy <span class="nt">--replicas</span><span class="o">=</span>5
deployment.apps/nginx-deploy scaled

➜  kubernetes git:<span class="o">(</span>main<span class="o">)</span> kubectl get deploy
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   5/5     5            5           3m20s

➜  kubernetes git:<span class="o">(</span>main<span class="o">)</span> kubectl get rs
NAME                     DESIRED   CURRENT   READY   AGE
nginx-deploy-c9bcb48d4   5         5         5       3m34s

➜  kubernetes git:<span class="o">(</span>main<span class="o">)</span> kubectl get pod
NAME                           READY   STATUS    RESTARTS   AGE
nginx-deploy-c9bcb48d4-blnpp   1/1     Running   0          69s
nginx-deploy-c9bcb48d4-bsgsr   1/1     Running   0          3m46s
nginx-deploy-c9bcb48d4-rh76q   1/1     Running   0          3m46s
nginx-deploy-c9bcb48d4-sg97l   1/1     Running   0          3m46s
nginx-deploy-c9bcb48d4-tvtq8   1/1     Running   0          69s
</code></pre></div></div>

<h3 id="rollingupdate-a-deployment">RollingUpdate a Deployment</h3>

<p>RollingUpdate Deployments support running multiple versions of an application at the same time. When you or an autoscaler scales a RollingUpdate Deployment that is in the middle of a rollout (either in progress or paused), the Deployment controller balances the additional replicas in the existing active ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called proportional scaling.</p>

<p>For example, you are running a Deployment with 10 replicas, <code class="language-plaintext highlighter-rouge">maxSurge=3</code>, and <code class="language-plaintext highlighter-rouge">maxUnavailable=2</code>. Configuration look like:</p>

<script src="https://gist.github.com/dimMaryanto93/96f6954c9a27a6b1934113b10223196a.js?file=05b-rollingupdate-deployment.yaml"> </script>

<p>Kemudian coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl apply <span class="nt">-f</span> rollingupdate-deployment.yaml</code></pre></figure>

<p>Maka outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl apply <span class="nt">-f</span> 03-workloads/01-basic-deploy/rollingupdate-deployment.yaml
deployment.apps/rollingupdate-nginx-deploy created

➜ kubectl get deploy rollingupdate-nginx-deploy
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
rollingupdate-nginx-deploy   10/10   10           10          2m25s

NAME                                   DESIRED   CURRENT   READY   AGE
rollingupdate-nginx-deploy-cd8ddf7d8   10        10        10      9s

➜  kubernetes git:<span class="o">(</span>main<span class="o">)</span> ✗ kubectl get pod
NAME                                         READY   STATUS    RESTARTS   AGE
rollingupdate-nginx-deploy-cd8ddf7d8-7ffkl   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-7p5x2   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-f2pcm   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-fxvbb   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-hw67p   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-j2zls   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-rwln8   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-tw8m5   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-v5kt2   1/1     Running   0          30s
rollingupdate-nginx-deploy-cd8ddf7d8-zzt44   1/1     Running   0          30s
</code></pre></div></div>

<p>Sekarang kita coba update image menjadi latest dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl <span class="nb">set </span>image deploy/rollingupdate-nginx-deploy <span class="nv">nginx</span><span class="o">=</span>nginx:latest <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl get rs <span class="nt">-w</span></code></pre></figure>

<p>Maka outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl <span class="nb">set </span>image deploy/rollingupdate-nginx-deploy <span class="nv">nginx</span><span class="o">=</span>nginx:latest <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl get rs <span class="nt">-w</span>
deployment.apps/rollingupdate-nginx-deploy image updated

NAME                                    DESIRED   CURRENT   READY   AGE
rollingupdate-nginx-deploy-cd8ddf7d8    10        10        10      0s
rollingupdate-nginx-deploy-cd8ddf7d8    8         8         8       1s
rollingupdate-nginx-deploy-77599d4db8   10        10        8       3s
rollingupdate-nginx-deploy-cd8ddf7d8    2         2         2       4s
rollingupdate-nginx-deploy-cd8ddf7d8    0         0         0       4s
rollingupdate-nginx-deploy-77599d4db8   10        10        10      5s
</code></pre></div></div>

<h3 id="pause-and-resume-rollout-of-a-deployment">Pause and Resume rollout of a Deployment</h3>

<p>When you update a Deployment, or plan to, you can pause rollouts for that Deployment before you trigger one or more updates. When you’re ready to apply those changes, you resume rollouts for the Deployment. This approach allows you to apply multiple fixes in between pausing and resuming without triggering unnecessary rollouts.</p>

<p>For example:</p>

<p>Get the rollout status:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl get rs</code></pre></figure>

<p>Jika dijalankan outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl get deploy
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
rollingupdate-nginx-deploy   10/10   10           10          33m

➜ kubectl get rs
NAME                                    DESIRED   CURRENT   READY   AGE
rollingupdate-nginx-deploy-77599d4db8   10        10        10      26m
</code></pre></div></div>

<p>Pause by running the following command:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout pause deploy/rollingupdate-nginx-deploy</code></pre></figure>

<p>Then when you update the deployment, such as image version using <code class="language-plaintext highlighter-rouge">kubectl set image deploy/rollingupdate-nginx-deploy nginx=nginx:1.16.1</code> The output look like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout pause deploy/rollingupdate-nginx-deploy
deployment.apps/rollingupdate-nginx-deploy paused

➜ kubectl <span class="nb">set </span>image deploy/rollingupdate-nginx-deploy <span class="nv">nginx</span><span class="o">=</span>nginx:1.16.1
deployment.apps/rollingupdate-nginx-deploy image updated

➜ kubectl rollout <span class="nb">history </span>deploy/rollingupdate-nginx-deploy
deployment.apps/rollingupdate-nginx-deploy
REVISION  CHANGE-CAUSE
1         &lt;none&gt;
2         &lt;none&gt;

➜ kubectl rollout status deploy/rollingupdate-nginx-deploy
Waiting <span class="k">for </span>deployment <span class="s2">"rollingupdate-nginx-deploy"</span> rollout to finish: 0 out of 10 new replicas have been updated...

➜  kubernetes git:<span class="o">(</span>main<span class="o">)</span> kubectl describe deploy rollingupdate-nginx-deploy
Name:                   rollingupdate-nginx-deploy
Namespace:              default
CreationTimestamp:      Sat, 08 Apr 2023 15:52:55 +0700
Labels:                 <span class="nv">app</span><span class="o">=</span>nginx
                        <span class="nb">env</span><span class="o">=</span><span class="nb">test
</span>Annotations:            deployment.kubernetes.io/revision: 2
Selector:               <span class="nv">app</span><span class="o">=</span>nginx,env<span class="o">=</span><span class="nb">test
</span>Replicas:               10 desired | 0 updated | 10 total | 10 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  2 max unavailable, 3 max surge
Pod Template:
  Labels:  <span class="nv">app</span><span class="o">=</span>nginx
           <span class="nb">env</span><span class="o">=</span><span class="nb">test
  </span>Containers:
   nginx:
    Image:        nginx:1.16.1
    Port:         80/TCP
    Host Port:    0/TCP
Conditions:
  Type           Status   Reason
  <span class="nt">----</span>           <span class="nt">------</span>   <span class="nt">------</span>
  Available      True     MinimumReplicasAvailable
  Progressing    Unknown  DeploymentPaused
OldReplicaSets:  rollingupdate-nginx-deploy-77599d4db8 <span class="o">(</span>10/10 replicas created<span class="o">)</span>
NewReplicaSet:   &lt;none&gt;
</code></pre></div></div>

<p>Notice that no new rollout started, because the object has been pause. to solve this you need run resume rollout with this command:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl rollout resume deploy/rollingupdate-nginx-deploy</code></pre></figure>

<p>Maka outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ kubectl rollout status deploy/rollingupdate-nginx-deploy
deployment <span class="s2">"rollingupdate-nginx-deploy"</span> successfully rolled out

➜ kubectl rollout <span class="nb">history </span>deploy/rollingupdate-nginx-deploy
deployment.apps/rollingupdate-nginx-deploy
REVISION  CHANGE-CAUSE
1         &lt;none&gt;
2         &lt;none&gt;
3         &lt;none&gt;

➜ kubectl describe deploy/rollingupdate-nginx-deploy
Name:                   rollingupdate-nginx-deploy
Namespace:              default
CreationTimestamp:      Sat, 08 Apr 2023 15:52:55 +0700
Labels:                 <span class="nv">app</span><span class="o">=</span>nginx
                        <span class="nb">env</span><span class="o">=</span><span class="nb">test
</span>Annotations:            deployment.kubernetes.io/revision: 3
Selector:               <span class="nv">app</span><span class="o">=</span>nginx,env<span class="o">=</span><span class="nb">test
</span>Replicas:               10 desired | 10 updated | 10 total | 10 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  2 max unavailable, 3 max surge
Pod Template:
  Labels:  <span class="nv">app</span><span class="o">=</span>nginx
           <span class="nb">env</span><span class="o">=</span><span class="nb">test
  </span>Containers:
   nginx:
    Image:        nginx:1.16.1
    Port:         80/TCP
    Host Port:    0/TCP
Conditions:
  Type           Status  Reason
  <span class="nt">----</span>           <span class="nt">------</span>  <span class="nt">------</span>
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
NewReplicaSet:   rollingupdate-nginx-deploy-679cf9c85d <span class="o">(</span>10/10 replicas created<span class="o">)</span>
</code></pre></div></div>

<h2 id="status-of-a-deployment-object">Status of a Deployment object</h2>

<p>A Deployment enters various states during its lifecycle.</p>

<ol>
  <li>It can be <code class="language-plaintext highlighter-rouge">progressing</code> while rolling out a new ReplicaSet,</li>
  <li>it can be <code class="language-plaintext highlighter-rouge">complete</code>,</li>
  <li>or it can <code class="language-plaintext highlighter-rouge">fail</code> to progress.</li>
</ol>

<p>To check status you can use this command:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl describe deploy/&lt;object-name&gt;</code></pre></figure>

<p>Untuk informasi status temen-temen bisa check di property <code class="language-plaintext highlighter-rouge">conditions:</code> seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ ➡ kubectl describe deploy/nginx-deploy
<span class="c"># &lt;...&gt;</span>
Conditions:
  Type           Status  Reason
  <span class="nt">----</span>           <span class="nt">------</span>  <span class="nt">------</span>
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
</code></pre></div></div>]]></content><author><name>Dimas Maryanto</name></author><category term="DevOps" /><category term="Orchestration" /><category term="Kubernetes" /><category term="Workloads" /><summary type="html"><![CDATA[Hai semuanya, materi sebelumnya kita sudah mencoba menggunakan Kubernetes workload resources dengan Object Deployment yang paling simple. Sekarang kita akan membahas yang lebih detail tentang Object Deployment. Karena pembahasan kali ini lumayan panjang jadi kita bagi2 jadi beberapa bagian diantaranya: What is Deployment Object? Create a Deployment Interaction with Deployment object Updating a Deployment Rolling Back a Deployment Scalling the pods with a Deployment Pause and Resume rollout of a Deployment Deployment status type: progressing type: complete type: failed type: pending Okay tanpa berlama-lama yuk langsung aja kita bahas materi yang pertama:]]></summary></entry><entry xml:lang="k8s"><title type="html">Study cases: Microservice apps (Springboot Rest API)</title><link href="/posts/devops/orchestration/kubernetes/pods/04b-study-cases-microservice-backend-apps" rel="alternate" type="text/html" title="Study cases: Microservice apps (Springboot Rest API)" /><published>2023-02-26T16:19:54+07:00</published><updated>2023-02-26T16:19:54+07:00</updated><id>/posts/devops/orchestration/kubernetes/pods/04b-study-cases-microservice-backend-apps</id><content type="html" xml:base="/posts/devops/orchestration/kubernetes/pods/04b-study-cases-microservice-backend-apps"><![CDATA[<p>Hai semuanya, di materi study cases untuk Pod and Container specification kali ini adalah lanjutan dari sebelumnya yang lebih advanced lagi yaitu Create and build microservices dengan framework Springboot Rest API dengan architecture seperti berikut:</p>

<p><img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/microservice-architecture.png" alt="architecture-deploy" /></p>

<p>Okay nah terlihat sedikit berbeda dengan application monolith sebelumnya, disini setiap service akan saling berkomunikasi dengan menggunakan protocol yang lightweight (ringan) seperti Rest API, grpc, messaging bus, database shared dan lain-lain. Pada study kasus kali ini terlihat pada diagram tersebut masih menggunakan physical / virtual-machine deployement kita akan migrasikan menggunakan orchestration container system dengan Kubernetes. Adapun tahap-tahap yang perlu kita lakukan yaitu</p>

<ol>
  <li>Develop aplikasi</li>
  <li>How code works (Code Review)</li>
  <li>The new architecture for orchestration container system</li>
  <li>Containerize apps</li>
  <li>Deploy to Kubernetes
    <ol>
      <li>Running as a Pod with namespace</li>
      <li>Connecting other service from the another namespace</li>
      <li>Specify container probes (health check)</li>
      <li>Specify resource request and limit</li>
    </ol>
  </li>
  <li>Implement API Gateway using nginx reverse proxy</li>
</ol>

<p>Ok tanpa berlama-lama yuk langsung aja kita bahas materi yang pertama:</p>

<!--more-->

<h2 id="development-aplikasi">Development aplikasi</h2>

<p>Dalam mendevelop aplikasi, ada beberapa hal yang perlu di persiapakan yaitu Software Development Kit dan backing service seperti Database, source-code version control dan DevTools yaitu</p>

<ol>
  <li>Git</li>
  <li>Java Development Kit (JDK) versi 17 keatas</li>
  <li>MySQL Database</li>
  <li>PostgreSQL Database</li>
  <li>Apache Maven</li>
  <li>Text editor seperti InteliJ IDEA, Visual Studio Code dan lain-lain</li>
  <li>Rest API client seperti Postman, curl dan lain-lain</li>
  <li>Docker</li>
</ol>

<p>Jadi temen-temen perlu install software development kita tersebut untuk cara installnya sudah pernah saya bahas di kelas <a href="https://youtube.dimas-maryanto.com/posts/devops/docker/dockerfile/study-cases/08c-build-springboot">DevOps - Docker untuk Pemula s/d Mahir</a>. Jika sudah temen bisa check dengan command seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » java <span class="nt">-version</span>
java version <span class="s2">"19.0.1"</span> 2022-10-18
Java<span class="o">(</span>TM<span class="o">)</span> SE Runtime Environment <span class="o">(</span>build 19.0.1+10-21<span class="o">)</span>
Java HotSpot<span class="o">(</span>TM<span class="o">)</span> 64-Bit Server VM <span class="o">(</span>build 19.0.1+10-21, mixed mode, sharing<span class="o">)</span>

~ » mvn <span class="nt">-v</span>
Apache Maven 3.9.0 <span class="o">(</span>9b58d2bad23a66be161c4664ef21ce219c2c8584<span class="o">)</span>
Maven home: /usr/local/Cellar/maven/3.9.0/libexec
Java version: 19.0.1, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home
Default locale: en_ID, platform encoding: UTF-8
OS name: <span class="s2">"mac os x"</span>, version: <span class="s2">"13.2"</span>, <span class="nb">arch</span>: <span class="s2">"x86_64"</span>, family: <span class="s2">"mac"</span>

~ » psql <span class="nt">--version</span>
psql <span class="o">(</span>PostgreSQL<span class="o">)</span> 14.7 <span class="o">(</span>Homebrew<span class="o">)</span>

~ » mysql <span class="nt">--version</span>
mysql  Ver 8.0.32 <span class="k">for </span>macos13.0 on x86_64 <span class="o">(</span>Homebrew<span class="o">)</span>

~ » curl <span class="nt">--version</span>
curl 7.86.0 <span class="o">(</span>x86_64-apple-darwin22.0<span class="o">)</span> libcurl/7.86.0 <span class="o">(</span>SecureTransport<span class="o">)</span> LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.47.0
Release-Date: 2022-10-26
</code></pre></div></div>

<p>Setelah temen-temen menginstall semua Software Development Kit, kemudian yang kita butuhkan adalah source-code. Untuk source-code temen-temen bisa clone dari <a href="https://github.com/DevOpsWithDimas/kubernetes-springboot-microservice-apps">github repo berikut</a> perintahnya seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">git clone git@github.com:DevOpsWithDimas/kubernetes-springboot-microservice-apps.git</code></pre></figure>

<p>Setelah di clone kita coba jalankan projectnya, tetapi pertama kita perlu configure dulu databasenya. supaya gak ribet kita akan menggunakan <code class="language-plaintext highlighter-rouge">docker-compose.yaml</code> seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-docker-compose.depedency.yaml"> </script>

<p>Kemudian coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">docker compose up <span class="nt">-d</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
docker compose ps</code></pre></figure>

<p>Maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devops/k8s-springboot-microservice <span class="o">[</span>main●] » docker compose ps
NAME                                     IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
k8s-springboot-microservice-mysql-1      mysql:8.0           <span class="s2">"docker-entrypoint.s…"</span>   mysql               47 seconds ago      Up 41 seconds       0.0.0.0:3306-&gt;3306/tcp, 33060/tcp
k8s-springboot-microservice-postgres-1   postgres:15         <span class="s2">"docker-entrypoint.s…"</span>   postgres            47 seconds ago      Up 42 seconds       0.0.0.0:5432-&gt;5432/tcp
</code></pre></div></div>

<p>Setelah semua database running, sekarang kita jalankan masing-masing service dengan menggunakan perintah <code class="language-plaintext highlighter-rouge">mvn clean -pl &lt;module-name&gt; spring-boot:run</code> seperti berikut</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn clean <span class="nt">-pl</span> customer spring-boot:run</code></pre></figure>

<p>maka outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devops/k8s-springboot-microservice <span class="o">[</span>main●] » mvn clean <span class="nt">-pl</span> customer spring-boot:run
  <span class="nb">.</span>   ____          _            __ _ _
 /<span class="se">\\</span> / ___<span class="s1">'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '</span>_ | <span class="s1">'_| | '</span>_ <span class="se">\/</span> _<span class="sb">`</span> | <span class="se">\ \ \ \</span>
 <span class="se">\\</span>/  ___<span class="o">)</span>| |_<span class="o">)</span>| | | | | <span class="o">||</span> <span class="o">(</span>_| |  <span class="o">)</span> <span class="o">)</span> <span class="o">)</span> <span class="o">)</span>
  <span class="s1">'  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.2)

2023-02-12T12:05:11.295+07:00  INFO 9448 --- [  restartedMain] c.m.d.udemy.customer.MainApplication     : Starting MainApplication using Java 19.0.1 with PID 9448 (/Users/dimasm93/Developer/dimas-maryanto.com/youtube/_projects/devops/k8s-springboot-microservice/customer/target/classes started by dimasm93 in /Users/dimasm93/Developer/dimas-maryanto.com/youtube/_projects/devops/k8s-springboot-microservice/customer)
2023-02-12T12:05:11.298+07:00  INFO 9448 --- [  restartedMain] c.m.d.udemy.customer.MainApplication     : No active profile set, falling back to 1 default profile: "default"
2023-02-12T12:05:11.392+07:00  INFO 9448 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set '</span>spring.devtools.add-properties<span class="s1">' to '</span><span class="nb">false</span><span class="s1">' to disable

2023-02-12T12:05:13.303+07:00  INFO 9448 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9090 (http)
2023-02-12T12:05:13.319+07:00  INFO 9448 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-02-12T12:05:13.319+07:00  INFO 9448 --- [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.5]
2023-02-12T12:05:13.400+07:00  INFO 9448 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-02-12T12:05:13.402+07:00  INFO 9448 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2007 ms
2023-02-12T12:05:13.612+07:00  INFO 9448 --- [  restartedMain] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 9.5.1 by Redgate
2023-02-12T12:05:14.208+07:00  INFO 9448 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-02-12T12:05:14.248+07:00  INFO 9448 --- [  restartedMain] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:mysql://localhost:3306/customer4p1 (MySQL 8.0)
2023-02-12T12:05:14.373+07:00  INFO 9448 --- [  restartedMain] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.030s)
2023-02-12T12:05:14.435+07:00  INFO 9448 --- [  restartedMain] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table `customer4p1`.`flyway_schema_history` ...
2023-02-12T12:05:14.575+07:00  INFO 9448 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Current version of schema `customer4p1`: &lt;&lt; Empty Schema &gt;&gt;
2023-02-12T12:05:14.590+07:00  INFO 9448 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Migrating schema `customer4p1` to version "20230211170102 - schema-customer"
2023-02-12T12:05:14.694+07:00  INFO 9448 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `customer4p1`, now at version v20230211170102 (execution time 00:00.131s)
2023-02-12T12:05:14.806+07:00  INFO 9448 --- [  restartedMain] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2023-02-12T12:05:16.662+07:00  INFO 9448 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9090 (http) with context path ''
2023-02-12T12:05:16.666+07:00  INFO 9448 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2023-02-12T12:05:16.686+07:00  WARN 9448 --- [  restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-02-12T12:05:16.706+07:00  INFO 9448 --- [  restartedMain] c.m.d.udemy.customer.MainApplication     : Started MainApplication in 6.034 seconds (process running for 6.653)
</span></code></pre></div></div>

<p>Sekarang kita coba check service custemer bisa meresponse api yang kita request dengan menggunakan perintah curl seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">curl <span class="nt">--location</span> <span class="nt">--request</span> GET <span class="s1">'localhost:9090/api/customer/v1/findById/cust01'</span></code></pre></figure>

<p>Maka jika dijalankan outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Last login: Sun Feb 12 11:33:28 on ttys002
~ » curl <span class="nt">--location</span> <span class="nt">--request</span> GET <span class="s1">'localhost:9090/api/customer/v1/findById/cust01'</span> <span class="nt">-v</span>
Note: Unnecessary use of <span class="nt">-X</span> or <span class="nt">--request</span>, GET is already inferred.
<span class="k">*</span>   Trying 127.0.0.1:9090...
<span class="k">*</span> Connected to localhost <span class="o">(</span>127.0.0.1<span class="o">)</span> port 9090 <span class="o">(</span><span class="c">#0)</span>
<span class="o">&gt;</span> GET /api/customer/v1/findById/cust01 HTTP/1.1
&lt; HTTP/1.1 200
&lt; Content-Type: application/json
&lt; Transfer-Encoding: chunked
&lt; Date: Sun, 12 Feb 2023 05:12:26 GMT

<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"cust01"</span>,<span class="s2">"userId"</span>:<span class="s2">"dimasm93"</span>,<span class="s2">"fullname"</span>:<span class="s2">"Dimas Maryanto"</span>,<span class="s2">"alamat"</span>:<span class="s2">"Bandung, Jawa Barat"</span><span class="o">}</span>%
</code></pre></div></div>

<p>Itu artinya sudah ok, selanjutnya kita coba jalankan service order dengan perintah seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn clean <span class="nt">-pl</span> orders spring-boot:run</code></pre></figure>

<p>Maka outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devops/k8s-springboot-microservice <span class="o">[</span>main●] » mvn clean <span class="nt">-pl</span> orders spring-boot:run
  <span class="nb">.</span>   ____          _            __ _ _
 /<span class="se">\\</span> / ___<span class="s1">'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '</span>_ | <span class="s1">'_| | '</span>_ <span class="se">\/</span> _<span class="sb">`</span> | <span class="se">\ \ \ \</span>
 <span class="se">\\</span>/  ___<span class="o">)</span>| |_<span class="o">)</span>| | | | | <span class="o">||</span> <span class="o">(</span>_| |  <span class="o">)</span> <span class="o">)</span> <span class="o">)</span> <span class="o">)</span>
  <span class="s1">'  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.2)

2023-02-12T12:16:07.346+07:00  INFO 11255 --- [  restartedMain] c.m.dimas.udemy.orders.MainApplication   : Starting MainApplication using Java 19.0.1 with PID 11255 (/Users/dimasm93/Developer/dimas-maryanto.com/youtube/_projects/devops/k8s-springboot-microservice/orders/target/classes started by dimasm93 in /Users/dimasm93/Developer/dimas-maryanto.com/youtube/_projects/devops/k8s-springboot-microservice/orders)
2023-02-12T12:16:07.350+07:00  INFO 11255 --- [  restartedMain] c.m.dimas.udemy.orders.MainApplication   : No active profile set, falling back to 1 default profile: "default"
2023-02-12T12:16:09.296+07:00  INFO 11255 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9091 (http)
2023-02-12T12:16:09.322+07:00  INFO 11255 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-02-12T12:16:09.608+07:00  INFO 11255 --- [  restartedMain] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 9.5.1 by Redgate
2023-02-12T12:16:10.187+07:00  INFO 11255 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-02-12T12:16:10.217+07:00  INFO 11255 --- [  restartedMain] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:postgresql://localhost:5432/order4p1 (PostgreSQL 15.2)
2023-02-12T12:16:10.364+07:00  INFO 11255 --- [  restartedMain] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.047s)
2023-02-12T12:16:10.460+07:00  INFO 11255 --- [  restartedMain] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "public"."flyway_schema_history" ...
2023-02-12T12:16:10.605+07:00  INFO 11255 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Current version of schema "public": &lt;&lt; Empty Schema &gt;&gt;
2023-02-12T12:16:10.627+07:00  INFO 11255 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "20230211171555 - create-order"
2023-02-12T12:16:10.696+07:00  INFO 11255 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "public", now at version v20230211171555 (execution time 00:00.107s)
2023-02-12T12:16:12.807+07:00  INFO 11255 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9091 (http) with context path ''
2023-02-12T12:16:12.813+07:00  WARN 11255 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : Unable to start LiveReload server
2023-02-12T12:16:12.866+07:00  INFO 11255 --- [  restartedMain] c.m.dimas.udemy.orders.MainApplication   : Started MainApplication in 6.225 seconds (process running for 6.76)
</span></code></pre></div></div>

<p>Sekarang kita coba check service order dengan menggunakan perintah curl berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">curl <span class="nt">--location</span> <span class="nt">--request</span> POST <span class="s1">'localhost:9091/api/order/v1/checkout'</span> <span class="se">\</span>
<span class="nt">--header</span> <span class="s1">'Content-Type: application/json'</span> <span class="se">\</span>
<span class="nt">--data-raw</span> <span class="s1">'{
    "userId": "cust01",
    "item": "Macbook Pro 13\" (A1723)",
    "qty": "2"
}'</span> <span class="nt">-v</span>

Note: Unnecessary use of <span class="nt">-X</span> or <span class="nt">--request</span>, POST is already inferred.
<span class="k">*</span>   Trying 127.0.0.1:9091...
<span class="k">*</span> Connected to localhost <span class="o">(</span>127.0.0.1<span class="o">)</span> port 9091 <span class="o">(</span><span class="c">#0)</span>
<span class="o">&gt;</span> POST /api/order/v1/checkout HTTP/1.1
<span class="o">&gt;</span> Content-Type: application/json
<span class="o">&gt;</span> Content-Length: 82
<span class="o">&gt;</span>
<span class="k">*</span> Mark bundle as not supporting multiuse
&lt; HTTP/1.1 200
&lt; Content-Type: application/json
&lt; Date: Sun, 12 Feb 2023 05:19:32 GMT

<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"1a02d9bd-8413-43f8-b6ac-bf3b7f8f3438"</span>,<span class="s2">"createdDate"</span>:<span class="s2">"2023-02-12T12:19:31.905439"</span>,<span class="s2">"customer"</span>:<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"cust01"</span>,<span class="s2">"userId"</span>:<span class="s2">"dimasm93"</span>,<span class="s2">"fullname"</span>:<span class="s2">"Dimas Maryanto"</span>,<span class="s2">"alamat"</span>:<span class="s2">"Bandung, Jawa Barat"</span><span class="o">}</span>,<span class="s2">"item"</span>:<span class="s2">"Macbook Pro 13</span><span class="se">\"</span><span class="s2"> (A1723)"</span>,<span class="s2">"qty"</span>:2<span class="o">}</span>%</code></pre></figure>

<p>Ok ini artinya sudah okay semua.</p>

<h2 id="how-code-works-code-review">How code works (Code Review)</h2>

<p>Setelah kita mencoba menjalankan program tersebut tahap selanjutnya adalah memahami bagaimana aplikasi bisa running dengan cara code review. Hal ini juga menjadi yang terpenting ketika proses deliver dari Programmer/Developer ke DevOps Engineer untuk di deploy ke environment.</p>

<p>Sebagai seorang DevOps kita harus mengetahui dan mengerti setiap service dari microservice yang telah di deliver oleh programmer untuk di implementasikan, Dengan cara melakukan assesment, diskusi, atau technical meeting dengan team Developer/Programmer. Salah satu prosedure yang biasanya saya lakukan adalah</p>

<ol>
  <li>Developer/Programmer menjelaskan overview architecture service</li>
  <li>Developer/Programmer menjelaskan service communication</li>
  <li>Developer/Programmer menjelaskan how to configure communication between service</li>
  <li>DevOps menyimpulkan &amp; Memberikan saran terkait perancangan architecture baru</li>
  <li>DevOps mengimplementasikan perancangan architecture tersebut ke environment</li>
  <li>Developer/Programmer dan DevOps melakukan Testing functional secara berdampingan</li>
  <li>DevOps melakukan Performance/Stress testing</li>
</ol>

<p>Okay kita tidak akan membahas semuanya ya, karena keterbatasan waktu. Jadi kita bahas beberapa yang dirasa penting seperti point no <code class="language-plaintext highlighter-rouge">1</code>, <code class="language-plaintext highlighter-rouge">2</code>, <code class="language-plaintext highlighter-rouge">3</code>, dan <code class="language-plaintext highlighter-rouge">4</code>. Pada point no 1, kita sudah bahas dibahas section awal jadi kita skip. Selanjutnya kita bahas point no 2 yaitu Service Communication.</p>

<p>Service communication ini pada dasarnya menjelaskan setiap service memiliki dependency ke mana saja dan seperti apa komunikasinya. Pada dasarnya service communication ada beberapa cara yaitu menggunakan Shared Database, Rest API, RPC (khususnya grpc), dan Messaging bus. Untuk service <code class="language-plaintext highlighter-rouge">customer</code> dan <code class="language-plaintext highlighter-rouge">orders</code> ini basicly kita menggunakan Rest API, Okay untuk lebih jelas kita lihat diagram berikut:</p>

<ol>
  <li>
    <p>Customer API - find by id
  <img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/01-flow-customer-findbyid.png" alt="customer-findbyid" /></p>
  </li>
  <li>
    <p>Orders API - create new order
  <img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/02-flow-create-new-orders.png" alt="create-new-order" /></p>
  </li>
</ol>

<p>Jadi klo kita perhatikan diagram no 1, flownya sangat simple hanya menggunakan database tetapi untuk no 2 selain database perlu call service customerAPI melalui Rest API. Yang jadi pertanyaan selanjutnya bagaimana konfigurasi koneksinya? Okay sekarang kita coba bedah kodingnya / code review.</p>

<p>Kalo kita lihat di project <code class="language-plaintext highlighter-rouge">orders</code> seperti berikut:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// orders/src/main/java/com/maryanto/dimas/udemy/orders/controller/OrderController.java</span>
<span class="kn">package</span> <span class="nn">com.maryanto.dimas.udemy.orders.controller</span><span class="o">;</span>

<span class="nd">@Slf4j</span>
<span class="nd">@RestController</span>
<span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/api/order/v1"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">OrderController</span> <span class="o">{</span>

  <span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/checkout"</span><span class="o">)</span>
    <span class="kd">public</span> <span class="nc">ResponseEntity</span><span class="o">&lt;?&gt;</span> <span class="n">placeOrder</span><span class="o">(</span><span class="nd">@RequestBody</span> <span class="nc">RequestOrderDTO</span> <span class="n">order</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">ResponseEntity</span><span class="o">&lt;</span><span class="nc">CustomerDTO</span><span class="o">&gt;</span> <span class="n">responseCustomer</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">serviceCustomer</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">order</span><span class="o">.</span><span class="na">getUserId</span><span class="o">());</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">responseCustomer</span><span class="o">.</span><span class="na">getStatusCode</span><span class="o">()</span> <span class="o">!=</span> <span class="nc">HttpStatus</span><span class="o">.</span><span class="na">OK</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="nc">ResponseEntity</span><span class="o">.</span><span class="na">badRequest</span><span class="o">().</span><span class="na">body</span><span class="o">(</span><span class="s">"Customer not found!"</span><span class="o">);</span>
        <span class="o">}</span>

        <span class="nc">CustomerDTO</span> <span class="n">customer</span> <span class="o">=</span> <span class="n">responseCustomer</span><span class="o">.</span><span class="na">getBody</span><span class="o">();</span>
        <span class="nc">Order</span> <span class="n">purchaseOrder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Order</span><span class="o">();</span>
        <span class="c1">// set value here!</span>
        <span class="k">try</span> <span class="o">{</span>
          <span class="n">purchaseOrder</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">repo</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">purchaseOrder</span><span class="o">);</span>
          <span class="nc">OrderDTO</span> <span class="n">output</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">OrderDTO</span><span class="o">();</span>
          <span class="c1">// set value here!</span>
          <span class="k">return</span> <span class="nc">ResponseEntity</span><span class="o">.</span><span class="na">ok</span><span class="o">(</span><span class="n">output</span><span class="o">);</span>
        <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">log</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"Can't proses checkout"</span><span class="o">,</span> <span class="n">ex</span><span class="o">);</span>
            <span class="k">return</span> <span class="nc">ResponseEntity</span><span class="o">.</span><span class="na">internalServerError</span><span class="o">()</span>
              <span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"Transaction can't be processed!!! \nPlease report to adminstrator"</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="c1">// orders/src/main/java/com/maryanto/dimas/udemy/orders/service/CustomerService.java</span>
<span class="kn">package</span> <span class="nn">com.maryanto.dimas.udemy.orders.service</span><span class="o">;</span>

<span class="nd">@Service</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CustomerService</span> <span class="o">{</span>
  <span class="nd">@Autowired</span>
  <span class="kd">public</span> <span class="nf">CustomerService</span><span class="o">(</span>
          <span class="nc">RestTemplate</span> <span class="n">rest</span><span class="o">,</span>
          <span class="nd">@Value</span><span class="o">(</span><span class="s">"${services.customer.host}"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">host</span><span class="o">,</span>
          <span class="nd">@Value</span><span class="o">(</span><span class="s">"${services.customer.port}"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">port</span><span class="o">,</span>
          <span class="nd">@Value</span><span class="o">(</span><span class="s">"${services.customer.proto}"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">proto</span><span class="o">,</span>
          <span class="nd">@Value</span><span class="o">(</span><span class="s">"${services.customer.context-path}"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">contextPath</span><span class="o">)</span> <span class="o">{</span>
      <span class="k">this</span><span class="o">.</span><span class="na">customerHost</span> <span class="o">=</span> <span class="n">host</span><span class="o">;</span>
      <span class="k">this</span><span class="o">.</span><span class="na">customerPort</span> <span class="o">=</span> <span class="n">port</span><span class="o">;</span>
      <span class="k">this</span><span class="o">.</span><span class="na">customerProto</span> <span class="o">=</span> <span class="n">proto</span><span class="o">;</span>
      <span class="k">this</span><span class="o">.</span><span class="na">customerContextPath</span> <span class="o">=</span> <span class="n">contextPath</span><span class="o">;</span>
      <span class="k">this</span><span class="o">.</span><span class="na">rest</span> <span class="o">=</span> <span class="n">rest</span><span class="o">;</span>
  <span class="o">}</span>

  <span class="kd">public</span> <span class="nc">ResponseEntity</span><span class="o">&lt;</span><span class="nc">CustomerDTO</span><span class="o">&gt;</span> <span class="nf">findById</span><span class="o">(</span><span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">String</span> <span class="n">baseUrl</span> <span class="o">=</span> <span class="nc">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span>
              <span class="s">"%s://%s:%s%s/api/customer/v1/findById/"</span><span class="o">,</span>
              <span class="k">this</span><span class="o">.</span><span class="na">customerProto</span><span class="o">,</span> <span class="k">this</span><span class="o">.</span><span class="na">customerHost</span><span class="o">,</span> <span class="k">this</span><span class="o">.</span><span class="na">customerPort</span><span class="o">,</span> <span class="k">this</span><span class="o">.</span><span class="na">customerContextPath</span><span class="o">);</span>
      <span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">rest</span><span class="o">.</span><span class="na">getForEntity</span><span class="o">(</span><span class="n">baseUrl</span> <span class="o">+</span> <span class="s">"{userId}"</span><span class="o">,</span> <span class="nc">CustomerDTO</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre></figure>

<p>Dan selain itu juga, berikut adalah file <code class="language-plaintext highlighter-rouge">application.yaml</code> untuk menyimpan semua environment variable yang dipanggil pada source code tersebut:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="c1"># orders/src/main/resources/application.yaml</span>
<span class="na">services</span><span class="pi">:</span>
  <span class="na">customer</span><span class="pi">:</span>
    <span class="na">host</span><span class="pi">:</span> <span class="s">${SERVICE_CUSTOMER_HOST:localhost}</span>
    <span class="na">port</span><span class="pi">:</span> <span class="s">${SERVICE_CUSTOMER_PORT:9090}</span>
    <span class="na">context-path</span><span class="pi">:</span> <span class="s">${SERVICE_CUSTOMER_CONTEXT_PATH:}</span>
    <span class="na">proto</span><span class="pi">:</span> <span class="s">${SERVICE_CUSTOMER_PROTO:http}</span></code></pre></figure>

<p>Okay sekarang perhatikan penggalan code diatas, jadi cara kita mengconfigurasi koneksi ke service <code class="language-plaintext highlighter-rouge">customerAPI</code> yaitu menggunakan envionment variable yang tertera pada <code class="language-plaintext highlighter-rouge">application.yaml</code> seperti <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_HOST</code>, <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_PORT</code>, <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_CONTEXT_PATH</code>, <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_PROTO</code> So kita bisa pasang/override nilainya pada saat dijalankan diatas container.</p>

<p>Nah setelah kita breakdown cara kerja atau code review, semoga temen-temen bisa memahami dan mulai merumuskan architecture yang bisa menunjang workload tersebut.</p>

<h2 id="the-new-architecture">The new architecture</h2>

<p>Setelah kita melihat, diskusi, technical meeting, serta code review tahap selanjutnya adalah merumuskan architecture yang sesuai dengan workload dari service tersebut.</p>

<p>Karena aplikasi yang dibuat merupakan microservice architecture yang memiliki backing service (dependency) seperti database, atau bahkan service lainnya Maka kita perlu buat scope dan boundaries dari services tersebut. Adapun scope dan boundaries tersebut dibagi menjadi Primary dan Secondary backing service</p>

<blockquote>
  <p><strong>Primary backing service</strong> yaitu Aplikasi yang tidak akan bisa startup ketika di running dalam suatu environment jika tanpa/menggunakan service tersebut (Mandatory), sedangkan <strong>Secondary backing service</strong> yaitu Aplikasi masih bisa berjalan tetapi secara functional belum lengkap.</p>
</blockquote>

<p>Karena tujuan kita adalah deploy ke orchestration container system menggunakan kubernetes jadi, langsung aja disini saya gambarkan menggunakan pendekatan kubernetes object resource seperti berikut:</p>

<p><img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/03-architecture-k8s-object.png" alt="architecture-k8s-objects" /></p>

<p>Berdasarkan diagram tersebut kita akan bagi menjadi 3 namespace yaitu <code class="language-plaintext highlighter-rouge">default</code>, <code class="language-plaintext highlighter-rouge">orders</code> dan <code class="language-plaintext highlighter-rouge">customer</code>. Dalam masing-masing namespace memiliki service yang kita pisahkan berdasarkan scopenya yaitu</p>

<ol>
  <li>Namespace <code class="language-plaintext highlighter-rouge">default</code>, terdiri dari pod dengan workload: <code class="language-plaintext highlighter-rouge">nginx</code> berfungsi untuk routing (API Gateway) ke service-service seperti <code class="language-plaintext highlighter-rouge">order</code> dan <code class="language-plaintext highlighter-rouge">customer</code></li>
  <li>Namespace <code class="language-plaintext highlighter-rouge">customer</code>, terdiri dari pod dengan workload: <code class="language-plaintext highlighter-rouge">customerAPI</code> dan <code class="language-plaintext highlighter-rouge">MySQL</code> sebagai primary backing service</li>
  <li>Namespace <code class="language-plaintext highlighter-rouge">order</code>, terdiri dari pod dengan workload: <code class="language-plaintext highlighter-rouge">orderAPI</code> dan <code class="language-plaintext highlighter-rouge">PostgreSQL</code> sebagai primary backing service.</li>
</ol>

<h2 id="containerize-apps">Containerize apps</h2>

<p>Setelah kita men-design architecturenya untuk deploy ke orchestration container system seperti kubernetes. Tahap awal meng-implementasikan semua konsep tersebut adalah melakukan kontainerisasi (container image). Di tahap ini adalah paling dasar sebelum kita deploy diatas kubernetes, jika service/aplikasi tidak bisa dibuild ke container image maka sudah dipastikan tidak akan bisa lanjut ke tahap selanjutnya.</p>

<p>Okay langsung aja kita mulai buat containernya. Tetapi sebelum itu kita lihat lagi bagaimana cara deploy manual seperti section sebelumnya. Apa yang kita perlukan untuk menjalankan service tersebut???</p>

<ol>
  <li>Java Development Kit (jdk-17 or later)</li>
  <li>Binary execute (jar)</li>
</ol>

<p>Untuk vendor JDK yang kita gunakan di local environment menggunakan Oracle JDK 19, nah ini sebisa mungkin untuk versi dari SDK harus sama persis dengan yang terdapat di container. Karena Oracle JDK tidak tersedia secara public di docker hub, kita akan menggunakan vendor yang open-source yaitu OpenJDK dengan version yang sama yaitu <a href="https://hub.docker.com/_/openjdk/tags?page=1&amp;name=19-oracle">openjdk-19</a></p>

<p>Sedangkan untuk binary execute atau file bundle yang telah dicomple kita bisa peroleh dengan menjalankan perintah:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn clean <span class="nt">-DskipTests</span> package</code></pre></figure>

<p>Jika dijalankan hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devops/k8s-springboot-microservice <span class="o">[</span>main] » mvn clean <span class="nt">-DskipTests</span> package
<span class="o">[</span>INFO] Reactor Summary <span class="k">for </span>springboot-microservice 0.0.1-SNAPSHOT:
<span class="o">[</span>INFO] 
<span class="o">[</span>INFO] springboot-microservice ............................ SUCCESS <span class="o">[</span>  1.777 s]

<span class="o">[</span>INFO] <span class="nt">---</span> jar:3.3.0:jar <span class="o">(</span>default-jar<span class="o">)</span> @ customer-api <span class="nt">---</span>
<span class="o">[</span>INFO] Building jar: /Users/dimasm93/Developer/dimas-maryanto.com/youtube/_projects/devops/k8s-springboot-microservice/customer/target/customer-api.jar
<span class="o">[</span>INFO] customer-api ....................................... SUCCESS <span class="o">[</span>  6.182 s]

<span class="o">[</span>INFO] <span class="nt">---</span> jar:3.3.0:jar <span class="o">(</span>default-jar<span class="o">)</span> @ orders-api <span class="nt">---</span>
<span class="o">[</span>INFO] Building jar: /Users/dimasm93/Developer/dimas-maryanto.com/youtube/_projects/devops/k8s-springboot-microservice/orders/target/orders-api.jar
<span class="o">[</span>INFO] orders-api ......................................... SUCCESS <span class="o">[</span>  2.735 s]
<span class="o">[</span>INFO] <span class="nt">------------------------------------------------------------------------</span>
<span class="o">[</span>INFO] BUILD SUCCESS
</code></pre></div></div>

<p>Okay setelah semua kebutuhan terpenuhi, tahap selanjutnya kita buat <code class="language-plaintext highlighter-rouge">Dockerfile</code> seperti berikut:</p>

<ol>
  <li>
    <p>Dockerfile untuk customerAPI, simpan dalam folder <code class="language-plaintext highlighter-rouge">customer/Dockerfile</code> seperti berikut:
  <script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-dockerfile-customer-api"> </script></p>
  </li>
  <li>
    <p>Dockerfile untuk orderAPI, simpan dalam folder <code class="language-plaintext highlighter-rouge">order/Dockerfile</code> seperti berikut:
  <script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-dockerfile-order-api"> </script></p>
  </li>
  <li>
    <p>Dan yang terakhir, tambahkan service <code class="language-plaintext highlighter-rouge">customerAPI</code> dan <code class="language-plaintext highlighter-rouge">orderAPI</code> dalam <code class="language-plaintext highlighter-rouge">docker-compose.yaml</code> seperti berikut:
  <script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-docker-compose-build.yaml"> </script></p>
  </li>
</ol>

<p>Sekerang coba jalankan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">docker compose build</code></pre></figure>

<p>Jika dijalankan hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devops/k8s-springboot-microservice <span class="o">[</span>main] » docker compose build customerAPI orderAPI
<span class="o">[</span>+] Building 5.1s <span class="o">(</span>7/7<span class="o">)</span> FINISHED
<span class="o">=&gt;</span> <span class="o">[</span>internal] load metadata <span class="k">for </span>docker.io/library/openjdk:19-oraclelinux8                                                                  4.7s
 <span class="o">=&gt;</span> <span class="o">[</span>1/2] FROM docker.io/library/openjdk:19-oraclelinux8@sha256:a5f2327c217367af3729670628c7ad66799cd890bde4e14fad02c2ae59552424           0.0s
 <span class="o">=&gt;</span> <span class="o">[</span>internal] load build context                                                                                                          0.0s
 <span class="o">=&gt;</span> <span class="o">=&gt;</span> transferring context: 145B                                                                                                          0.0s
 <span class="o">=&gt;</span> CACHED <span class="o">[</span>2/2] ADD target/orders-api.jar spring-boot.jar                                                                                 0.0s
 <span class="o">=&gt;</span> exporting to image                                                                                                                     0.1s
 <span class="o">=&gt;</span> <span class="o">=&gt;</span> naming to repository.dimas-maryanto.com:8087/dimmaryanto93/example/order-api:latest

<span class="o">=&gt;</span> <span class="o">[</span>internal] load metadata <span class="k">for </span>docker.io/library/openjdk:19-oraclelinux8                                                                  4.7s
 <span class="o">=&gt;</span> <span class="o">[</span>1/2] FROM docker.io/library/openjdk:19-oraclelinux8@sha256:a5f2327c217367af3729670628c7ad66799cd890bde4e14fad02c2ae59552424           0.0s
 <span class="o">=&gt;</span> <span class="o">[</span>internal] load build context                                                                                                          0.0s
 <span class="o">=&gt;</span> <span class="o">=&gt;</span> transferring context: 145B  
<span class="o">=&gt;</span> CACHED <span class="o">[</span>2/2] ADD target/customer-api.jar spring-boot.jar                                                                                0.0s
 <span class="o">=&gt;</span> exporting to image                                                                                                                     1.8s
 <span class="o">=&gt;</span> <span class="o">=&gt;</span> naming to repository.dimas-maryanto.com:8087/dimmaryanto93/example/customer-api:latest

devops/k8s-springboot-microservice <span class="o">[</span>main] » docker images
REPOSITORY                                                              TAG           IMAGE ID       CREATED          SIZE
repository.dimas-maryanto.com:8087/dimmaryanto93/example/order-api      latest        f27ba96797db   17 minutes ago   522MB
repository.dimas-maryanto.com:8087/dimmaryanto93/example/customer-api   latest        9d589fe904f0   26 minutes ago   523MB
</code></pre></div></div>

<p>Setelah container image di build, sekarang coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">docker compose up <span class="nt">-d</span></code></pre></figure>

<p>Maka seperti berikut outputnya:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devops/k8s-springboot-microservice <span class="o">[</span>main] » docker compose up <span class="nt">-d</span>
<span class="o">[</span>+] Running 7/7
 ⠿ Network k8s-springboot-microservice_default          Created        0.2s
 ⠿ Volume <span class="s2">"k8s-springboot-microservice_pg_data"</span>         Created        0.0s
 ⠿ Volume <span class="s2">"k8s-springboot-microservice_mysql_data"</span>      Created        0.0s
 ⠿ Container k8s-springboot-microservice-mysql-1        Started        3.2s
 ⠿ Container k8s-springboot-microservice-postgres-1     Started        3.0s
 ⠿ Container k8s-springboot-microservice-customerAPI-1  Started        4.9s
 ⠿ Container k8s-springboot-microservice-orderAPI-1     Started        4.9s

devops/k8s-springboot-microservice <span class="o">[</span>main] » docker compose ps
NAME                                     IMAGE                                                                       COMMAND                  SERVICE             CREATED              STATUS              PORTS
k8s-springboot-microservice-mysql-1      repository.dimas-maryanto.com:8086/mysql:8.0                                <span class="s2">"docker-entrypoint.s…"</span>   mysql               About a minute ago   Up 58 seconds       0.0.0.0:3306-&gt;3306/tcp, 33060/tcp
k8s-springboot-microservice-orderAPI-1   repository.dimas-maryanto.com:8087/dimmaryanto93/example/order-api:latest   <span class="s2">"java -Djava.securit…"</span>   orderAPI            About a minute ago   Up 56 seconds       0.0.0.0:9091-&gt;9091/tcp
k8s-springboot-microservice-postgres-1   repository.dimas-maryanto.com:8086/postgres:15                              <span class="s2">"docker-entrypoint.s…"</span>   postgres            About a minute ago   Up 58 seconds       0.0.0.0:5432-&gt;5432/tcp
</code></pre></div></div>

<p>Jika semua service sudah running dengan baik, sekarang coba temen-temen test lagi service tersebut apakah berjalan dengan baik di atas single container? jika sudah ok. Yeeey selamat temen-temen udah melewati level 1.</p>

<p>Berikutnya adalah temen-temen bisa push ke container registry. boleh ke DockerHub atau private registry dengan menggunakan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">docker compose push customerAPI <span class="o">&amp;&amp;</span> <span class="se">\</span>
docker compose push orderAPI </code></pre></figure>

<h2 id="create-kubernetes-cluster-on-local">Create kubernetes cluster on local</h2>

<p>Setelah container image di-build dan publish ke container registry, tahap selanjutnya adalah deploy ke kubernetes cluster. Tetapi sebelum itu siapkan dulu kubernetes cluster untuk workload tersebut. Settingan cluster untuk microservice ini agak berbeda dengan sebelumnya yaitu seperti berikut:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">nodes</span><span class="pi">:</span> 
  <span class="na">controlplane</span><span class="pi">:</span> 
    <span class="na">cpus</span><span class="pi">:</span> <span class="s1">'</span><span class="s">2</span><span class="nv"> </span><span class="s">cores'</span>
    <span class="na">memory</span><span class="pi">:</span> <span class="s1">'</span><span class="s">2</span><span class="nv"> </span><span class="s">GB'</span>
  <span class="na">worker-1</span><span class="pi">:</span>
    <span class="na">cpus</span><span class="pi">:</span> <span class="s1">'</span><span class="s">2</span><span class="nv"> </span><span class="s">cores'</span>
    <span class="na">memory</span><span class="pi">:</span> <span class="s1">'</span><span class="s">4</span><span class="nv"> </span><span class="s">GB'</span>
  <span class="na">worker-2</span><span class="pi">:</span>
    <span class="na">cpus</span><span class="pi">:</span> <span class="s1">'</span><span class="s">2</span><span class="nv"> </span><span class="s">cores'</span>
    <span class="na">memory</span><span class="pi">:</span> <span class="s1">'</span><span class="s">4</span><span class="nv"> </span><span class="s">GB'</span>
</code></pre></div></div>

<p>Jadi kita akan buat menggunakan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">minikube start <span class="nt">-p</span> springboot-microservice <span class="se">\</span>
<span class="nt">--cpus</span> 2 <span class="se">\</span>
<span class="nt">--memory</span> 4G <span class="se">\</span>
<span class="nt">--insecure-registry</span> 192.168.88.50:8086 <span class="se">\</span>
<span class="nt">--nodes</span> 3

minikube profile springboot-microservice

minikube addons <span class="nb">enable </span>registry-creds <span class="o">&amp;&amp;</span> <span class="se">\</span>
minikube addons configure registry-creds

minikube addons <span class="nb">enable </span>metrics-server</code></pre></figure>

<p>Jika dijalankan hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » minikube start <span class="nt">-p</span> springboot-microservice <span class="se">\</span>
<span class="nt">--cpus</span> 2 <span class="se">\</span>
<span class="nt">--memory</span> 4G <span class="se">\</span>
<span class="nt">--insecure-registry</span> 192.168.88.50:8086 <span class="se">\</span>
<span class="nt">--nodes</span> 3
😄  <span class="o">[</span>springboot-microservice] minikube v1.29.0 on Darwin 13.2.1
✨  Using the hyperkit driver based on user configuration
👍  Starting control plane node springboot-microservice <span class="k">in </span>cluster springboot-microservice
🔥  Creating hyperkit VM <span class="o">(</span><span class="nv">CPUs</span><span class="o">=</span>2, <span class="nv">Memory</span><span class="o">=</span>4096MB, <span class="nv">Disk</span><span class="o">=</span>20000MB<span class="o">)</span> ...
📦  Preparing Kubernetes v1.26.1 on containerd 1.6.15 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring CNI <span class="o">(</span>Container Networking Interface<span class="o">)</span> ...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎  Verifying Kubernetes components...
🌟  Enabled addons: default-storageclass, storage-provisioner

👍  Starting worker node springboot-microservice-m02 <span class="k">in </span>cluster springboot-microservice
🔥  Creating hyperkit VM <span class="o">(</span><span class="nv">CPUs</span><span class="o">=</span>2, <span class="nv">Memory</span><span class="o">=</span>4096MB, <span class="nv">Disk</span><span class="o">=</span>20000MB<span class="o">)</span> ...

👍  Starting worker node springboot-microservice-m03 <span class="k">in </span>cluster springboot-microservice
🔥  Creating hyperkit VM <span class="o">(</span><span class="nv">CPUs</span><span class="o">=</span>2, <span class="nv">Memory</span><span class="o">=</span>4096MB, <span class="nv">Disk</span><span class="o">=</span>20000MB<span class="o">)</span> ...

🔎  Verifying Kubernetes components...
🏄  Done! kubectl is now configured to use <span class="s2">"springboot-microservice"</span> cluster and <span class="s2">"default"</span> namespace by default

~ » minikube profile springboot-microservice
✅  minikube profile was successfully <span class="nb">set </span>to springboot-microservice

~ » minikube addons <span class="nb">enable </span>registry-creds
❗  registry-creds is a 3rd party addon and is not maintained or verified by minikube maintainers, <span class="nb">enable </span>at your own risk.
❗  registry-creds does not currently have an associated maintainer.
    ▪ Using image docker.io/upmcenterprises/registry-creds:1.10
🌟  The <span class="s1">'registry-creds'</span> addon is enabled

~ » minikube addons configure registry-creds
Do you want to <span class="nb">enable </span>AWS Elastic Container Registry? <span class="o">[</span>y/n]: n

Do you want to <span class="nb">enable </span>Google Container Registry? <span class="o">[</span>y/n]: n

Do you want to <span class="nb">enable </span>Docker Registry? <span class="o">[</span>y/n]: y
<span class="nt">--</span> Enter docker registry server url: 192.168.88.50:8086
<span class="nt">--</span> Enter docker registry username: admin
<span class="nt">--</span> Enter docker registry password:

Do you want to <span class="nb">enable </span>Azure Container Registry? <span class="o">[</span>y/n]: n
✅  registry-creds was successfully configured

~ » kubectl get node
NAME                          STATUS   ROLES           AGE     VERSION
springboot-microservice       Ready    control-plane   4m52s   v1.26.1
springboot-microservice-m02   Ready    &lt;none&gt;          3m4s    v1.26.1
springboot-microservice-m03   Ready    &lt;none&gt;          86s     v1.26.1

~ » minikube addons <span class="nb">enable </span>metrics-server
💡  metrics-server is an addon maintained by Kubernetes. For any concerns contact minikube on GitHub.
You can view the list of minikube maintainers at: https://github.com/kubernetes/minikube/blob/master/OWNERS
    ▪ Using image registry.k8s.io/metrics-server/metrics-server:v0.6.2
🌟  The <span class="s1">'metrics-server'</span> addon is enabled
</code></pre></div></div>

<p>Jika pada pod <code class="language-plaintext highlighter-rouge">registry-creds</code> error, temen-temen bisa menggunakan alternative lain yaitu dengan membuat sebuah secret dengan perintah serperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl create secret docker-registry regcred <span class="se">\</span>
<span class="nt">--docker-server</span><span class="o">=</span>&lt;your-registry-server&gt; <span class="se">\</span>
<span class="nt">--docker-username</span><span class="o">=</span>&lt;your-name&gt; <span class="se">\</span>
<span class="nt">--docker-password</span><span class="o">=</span>&lt;your-pword&gt; <span class="se">\</span>
<span class="nt">--docker-email</span><span class="o">=</span>&lt;your-email&gt;</code></pre></figure>

<p>where:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">&lt;your-registry-server&gt;</code> is your Private Docker Registry FQDN. Use <code class="language-plaintext highlighter-rouge">https://index.docker.io/v1/</code> for DockerHub otherwise <code class="language-plaintext highlighter-rouge">192.168.88.50:8086</code> for private registry</li>
  <li><code class="language-plaintext highlighter-rouge">&lt;your-name&gt;</code> is your Docker username.</li>
  <li><code class="language-plaintext highlighter-rouge">&lt;your-pword&gt;</code> is your Docker password.</li>
  <li><code class="language-plaintext highlighter-rouge">&lt;your-email&gt;</code> is your Docker email.</li>
</ul>

<p>Dan setelah itu, jika mau menjalankan pod dari insecure registry temen-temen perlu nambahkan property <code class="language-plaintext highlighter-rouge">imagePullSecrets</code> seperti berikut contohnya:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Pod</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">private-reg</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">containers</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">private-reg-container</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">&lt;your-private-image&gt;</span>
  <span class="na">imagePullSecrets</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">regcred</span></code></pre></figure>

<p>Setelah cluster kubernetes ready, kita coba membuat simple 2 pod yang simple menggunakan <code class="language-plaintext highlighter-rouge">nginx</code> dan <code class="language-plaintext highlighter-rouge">httpd</code> setelah itu kita coba test cni antara ke dua pod tersebut dengan perintah seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl run web1 <span class="nt">--image</span> 192.168.88.50:8086/nginx:mainline <span class="nt">--port</span> 80 <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl expose pod/web1 <span class="nt">--port</span> 80 <span class="nt">--type</span> ClusterIP

kubectl run web2 <span class="nt">--image</span> 192.168.88.50:8086/httpd:latest <span class="nt">--port</span> 80 <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl expose pod/web2 <span class="nt">--port</span> 80 <span class="nt">--type</span> ClusterIP

kubectl <span class="nb">exec </span>web1 <span class="nt">--</span> curl http://web2</code></pre></figure>

<p>Jika dijalankan maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl run web1 <span class="nt">--image</span> 192.168.88.50:8086/nginx:mainline <span class="nt">--port</span> 80 <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl expose pod/web1 <span class="nt">--port</span> 80 <span class="nt">--type</span> ClusterIP
pod/web1 created
service/web1 exposed

~ » kubectl get pod
NAME   READY   STATUS              RESTARTS   AGE
web1   1/1     Running             0          56s

~ » kubectl run web2 <span class="nt">--image</span> 192.168.88.50:8086/httpd:latest <span class="nt">--port</span> 80 <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl expose pod/web2 <span class="nt">--port</span> 80 <span class="nt">--type</span> ClusterIP
pod/web2 created
service/web2 exposed

~ » kubectl get pod
NAME   READY   STATUS              RESTARTS   AGE
web1   1/1     Running             0          71s
web2   1/1     Running             0          30s

~ » kubectl <span class="nb">exec </span>web1 <span class="nt">--</span> curl http://web2
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    45  100    45    0     0    918      0 <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:&lt;html&gt;&lt;body&gt;&lt;h1&gt;It works!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;
<span class="nt">--</span> <span class="nt">--</span>:--:--   918
</code></pre></div></div>

<p>Jika temen-temen perhatikan pada saat membuat cluster, mengapa cluster ini menggunakan memory yang lebih besar yaitu <code class="language-plaintext highlighter-rouge">4G</code> di setiap nodenya, Jadi menentukan resource tidak hanya di sisi Pod dan Containernya saja tetapi juga pada cluster nodenya juga kita harus sesuaikan.</p>

<h2 id="deploy-to-kubernetes-cluster">Deploy to Kubernetes cluster</h2>

<p>Setelah cluster kubernetes siap dan kita coba test network connection antar pod bisa juga, tahap selanjutnya adalah kita buat Kubernetes resourcesnya sepert Pod, dan Service yang masing-masing di kelompokan berdasarkan Namespace berdasarkan design architecture Kubernetes resources sebelumnya.</p>

<p>Secara sturuktur kita kelompokan seperti berikut:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">namespaces</span><span class="pi">:</span> 
  <span class="pi">-</span> <span class="na">default</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">nginx</span>
  <span class="pi">-</span> <span class="na">customer</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">customer-api</span>
      <span class="pi">-</span> <span class="s">mysql</span>
  <span class="pi">-</span> <span class="na">orders</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">orders-api</span>
      <span class="pi">-</span> <span class="s">postgresql</span>
</code></pre></div></div>

<p>Seperti berikut untuk kubernetes resources dengan namespace <code class="language-plaintext highlighter-rouge">customer-module</code></p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-ns-customer-api.yaml"> </script>

<p>Kemudian kita coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl apply <span class="nt">-f</span> kubernetes/ns-customer-api.yaml</code></pre></figure>

<p>Maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl apply <span class="nt">-f</span> kubernetes/ns-customer-api.yaml
namespace/customer-module created
configmap/mysql created
secret/mysql created
pod/mysql created
service/mysql created
pod/customer-api created
service/customer-api created

~ » kubectl get pod <span class="nt">-n</span> customer-module
NAME           READY   STATUS    RESTARTS   AGE
customer-api   1/1     Running   0          13s
mysql          1/1     Running   0          6m36s

~ » kubectl logs customer-api <span class="nt">-n</span> customer-module

  <span class="nb">.</span>   ____          _            __ _ _
 /<span class="se">\\</span> / ___<span class="s1">'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '</span>_ | <span class="s1">'_| | '</span>_ <span class="se">\/</span> _<span class="sb">`</span> | <span class="se">\ \ \ \</span>
 <span class="se">\\</span>/  ___<span class="o">)</span>| |_<span class="o">)</span>| | | | | <span class="o">||</span> <span class="o">(</span>_| |  <span class="o">)</span> <span class="o">)</span> <span class="o">)</span> <span class="o">)</span>
  <span class="s1">'  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.2)

2023-02-25T06:49:26.684Z  INFO 1 --- [           main] c.m.d.udemy.customer.MainApplication     : Starting MainApplication v0.0.1-SNAPSHOT using Java 19 with PID 1 (/spring-boot.jar started by root in /)
2023-02-25T06:49:31.550Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9090 (http)
2023-02-25T06:49:33.287Z  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-02-25T06:49:33.356Z  INFO 1 --- [           main] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:mysql://mysql:3306/customer_api (MySQL 8.0)
2023-02-25T06:49:33.728Z  INFO 1 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.090s)
2023-02-25T06:49:33.815Z  INFO 1 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table `customer_api`.`flyway_schema_history` ...
2023-02-25T06:49:34.140Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `customer_api`: &lt;&lt; Empty Schema &gt;&gt;
2023-02-25T06:49:34.184Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `customer_api` to version "20230211170102 - schema-customer"
2023-02-25T06:49:34.298Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `customer_api`, now at version v20230211170102 (execution time 00:00.190s)
2023-02-25T06:49:38.606Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9090 (http) with context path ''
2023-02-25T06:49:38.639Z  WARN 1 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-02-25T06:49:38.685Z  INFO 1 --- [           main] c.m.d.udemy.customer.MainApplication     : Started MainApplication in 15.321 seconds (process running for 17.433)

~ » kubectl exec mysql -n customer-module -it -- mysql -e '</span>show tables<span class="p">;</span><span class="s1">' --database customer_api -u customer_api -p
Enter password:
+------------------------+
| Tables_in_customer_api |
+------------------------+
| customer               |
| flyway_schema_history  |
+------------------------+

~ » kubectl exec customer-api -n customer-module -- curl --location --request GET '</span>localhost:9090/api/customer/v1/findById/cust01<span class="s1">' -v
Note: Unnecessary use of -X or --request, GET is already inferred.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9090 (#0)
&gt; GET /api/customer/v1/findById/cust01 HTTP/1.1
&gt; Host: localhost:9090
&gt; User-Agent: curl/7.61.1
&gt; Accept: */*
&gt;
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0&lt; HTTP/1.1 200
&lt; Content-Type: application/json
&lt; Transfer-Encoding: chunked
&lt; Date: Sat, 25 Feb 2023 07:14:25 GMT
&lt;
{ [100 bytes data]
100    94    0    94    0     0     30      0 --:--:--  
{"id":"cust01","userId":"dimasm93","fullname":"Dimas Maryanto","alamat":"Bandung, Jawa Barat"}
</span></code></pre></div></div>

<p>Selanjutnya kita deploy untuk namespace <code class="language-plaintext highlighter-rouge">orders</code> seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-ns-orders-api.yaml"> </script>

<p>Kemudian kita coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl apply <span class="nt">-f</span> kubernetes/ns-orders-api.yaml</code></pre></figure>

<p>Jika dijalankan maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl apply <span class="nt">-f</span> kubernetes/ns-orders-api.yaml
namespace/orders-module created
configmap/postgresql created
secret/postgresql created
pod/postgresql created
service/postgresql created
pod/orders-api created
service/orders-api created

~ » kubectl get pod <span class="nt">-n</span> orders-module
NAME         READY   STATUS    RESTARTS   AGE
orders-api   1/1     Running   0          15s
postgresql   1/1     Running   0          15s

~ » kubectl logs orders-api <span class="nt">-n</span> orders-module

  <span class="nb">.</span>   ____          _            __ _ _
 /<span class="se">\\</span> / ___<span class="s1">'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '</span>_ | <span class="s1">'_| | '</span>_ <span class="se">\/</span> _<span class="sb">`</span> | <span class="se">\ \ \ \</span>
 <span class="se">\\</span>/  ___<span class="o">)</span>| |_<span class="o">)</span>| | | | | <span class="o">||</span> <span class="o">(</span>_| |  <span class="o">)</span> <span class="o">)</span> <span class="o">)</span> <span class="o">)</span>
  <span class="s1">'  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.2)

2023-02-25T07:05:01.905Z  INFO 1 --- [           main] c.m.dimas.udemy.orders.MainApplication   : Starting MainApplication v0.0.1-SNAPSHOT using Java 19 with PID 1 (/spring-boot.jar started by root in /)
2023-02-25T07:05:06.506Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9091 (http)
2023-02-25T07:05:07.808Z  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-02-25T07:05:07.888Z  INFO 1 --- [           main] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:postgresql://postgresql:5432/order_api (PostgreSQL 15.1)
2023-02-25T07:05:07.985Z  INFO 1 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.041s)
2023-02-25T07:05:08.013Z  INFO 1 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "public"."flyway_schema_history" ...
2023-02-25T07:05:08.127Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "public": &lt;&lt; Empty Schema &gt;&gt;
2023-02-25T07:05:08.160Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "20230211171555 - create-order"
2023-02-25T07:05:08.225Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "public", now at version v20230211171555 (execution time 00:00.121s)
2023-02-25T07:05:24.876Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9091 (http) with context path ''
2023-02-25T07:05:25.288Z  INFO 1 --- [           main] c.m.dimas.udemy.orders.MainApplication   : Started MainApplication in 25.583 seconds (process running for 28.329)

~ » kubectl exec orders-api -n orders-module -- curl --location --request POST '</span>localhost:9091/api/order/v1/checkout<span class="s1">' \
--header '</span>Content-Type: application/json<span class="s1">' \
--data-raw '</span><span class="o">{</span>
    <span class="s2">"userId"</span>: <span class="s2">"cust01"</span>,
    <span class="s2">"item"</span>: <span class="s2">"Macbook Pro 13</span><span class="se">\"</span><span class="s2"> (A1723)"</span>,
    <span class="s2">"qty"</span>: <span class="s2">"2"</span>
<span class="o">}</span><span class="s1">' -v
Note: Unnecessary use of -X or --request, POST is already inferred.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9091 (#0)
&gt; POST /api/order/v1/checkout HTTP/1.1
&gt;
} [82 bytes data]
* upload completely sent off: 82 out of 82 bytes
&lt; HTTP/1.1 500
&lt; Content-Type: application/json

{"timestamp":"2023-02-25T08:05:26.037+00:00","status":500,"error":"Internal Server Error","path":"/api/order/v1100   204    0   122  100    82    163    109 --:--:-- --:--:-- --:--:--   273
* Closing connection 0
</span></code></pre></div></div>

<h2 id="connecting-other-service-from-the-another-namespace">Connecting other service from the another namespace</h2>

<p>Setelah kita deploy ke kubernetes cluster, jika temen-temen perhatikan kembali output yang dihasilkan dari service <code class="language-plaintext highlighter-rouge">orders-api</code> kita melakukan request ke endpoint <code class="language-plaintext highlighter-rouge">/api/order/v1/checkout</code> hasilnya <code class="language-plaintext highlighter-rouge">HTTP/Status 500, Internal Server Error</code> klo kita lihat dari log errornya pada service tersebut seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl logs orders-api <span class="nt">-n</span> orders-module
ith path <span class="o">[]</span> threw exception <span class="o">[</span>Request processing failed: org.springframework.web.client.ResourceAccessException: I/O error on GET request <span class="k">for</span> <span class="s2">"http://localhost:9090/api/customer/v1/findById/cust01"</span>: Connection refused] with root cause

java.net.ConnectException: Connection refused
	at java.base/sun.nio.ch.Net.pollConnect<span class="o">(</span>Native Method<span class="o">)</span> ~[na:na]
	at java.base/sun.nio.ch.Net.pollConnectNow<span class="o">(</span>Net.java:672<span class="o">)</span> ~[na:na]
	at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect<span class="o">(</span>NioSocketImpl.java:535<span class="o">)</span> ~[na:na]
	at java.base/sun.nio.ch.NioSocketImpl.connect<span class="o">(</span>NioSocketImpl.java:585<span class="o">)</span> ~[na:na]
	at java.base/java.net.Socket.connect<span class="o">(</span>Socket.java:666<span class="o">)</span> ~[na:na]
	at java.base/sun.net.NetworkClient.doConnect<span class="o">(</span>NetworkClient.java:178<span class="o">)</span> ~[na:na]
</code></pre></div></div>

<p>Nah jika temen-temen perhatikan pada log tersebut, terlihat ada error gak bisa connect ke <code class="language-plaintext highlighter-rouge">localhost:9090/api/xxx/xxx</code> dari <code class="language-plaintext highlighter-rouge">orders-api</code>, Sedangkan kita mau ngambil data dari service <code class="language-plaintext highlighter-rouge">customer-api</code>. Lantas gimana caranya?</p>

<p>Kita sebelumnya udah membuat service untuk masing-masing pod seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl get service <span class="nt">-n</span> orders-module
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT<span class="o">(</span>S<span class="o">)</span>          AGE
orders-api   NodePort   10.109.82.183   &lt;none&gt;        9091:31963/TCP   144m
postgresql   NodePort   10.100.81.138   &lt;none&gt;        5432:32759/TCP   144m

~ » kubectl get service <span class="nt">-n</span> customer-module
NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT<span class="o">(</span>S<span class="o">)</span>          AGE
customer-api   NodePort   10.99.232.190   &lt;none&gt;        9090:31920/TCP   122m
mysql          NodePort   10.96.9.233     &lt;none&gt;        3306:32554/TCP   172m
</code></pre></div></div>

<p>Nah jadi kalau dari kasus sebelumnya kita mau koneksi ke database maka kita bisa menggunakan hostname dari nama service tersebut misalnya <code class="language-plaintext highlighter-rouge">jdbc:postgresql://postgresql:5432/xxxx</code> nah serupa dengan hal tersebut dengan mengkases service <code class="language-plaintext highlighter-rouge">customer-api</code> dari <code class="language-plaintext highlighter-rouge">orders-api</code> tapi bagaimana dengan berbeda namespase.</p>

<p>Kita bisa menggunakan Kubernetes DNS queries untuk memangil service lain yang terletak pada namespace lain, seperti berikut:</p>

<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/resolv.conf
</span><span class="n">search</span> &lt;<span class="n">namespace</span>&gt;.<span class="n">svc</span>.<span class="n">cluster</span>.<span class="n">local</span> &lt;<span class="n">service</span>&gt;.&lt;<span class="n">namespace</span>&gt;.<span class="n">cluster</span>.<span class="n">local</span>
</code></pre></div></div>

<p>Kita coba panggil service <code class="language-plaintext highlighter-rouge">customer-api</code> dari pod <code class="language-plaintext highlighter-rouge">order-api</code> dengan simple <code class="language-plaintext highlighter-rouge">curl</code> seperti berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl <span class="nb">exec </span>orders-api <span class="nt">-n</span> orders-module <span class="nt">--</span> curl <span class="nt">--location</span> <span class="nt">--request</span> GET <span class="s1">'http://customer-api.customer-module:9090/api/customer/v1/findById/cust01'</span> <span class="nt">-v</span></code></pre></figure>

<p>Coba klo kita jalankan outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl <span class="nb">exec </span>orders-api <span class="nt">-n</span> orders-module <span class="nt">--</span> curl <span class="nt">--location</span> <span class="nt">--request</span> GET <span class="s1">'http://customer-api.customer-module:9090/api/customer/v1/findById/cust01'</span> <span class="nt">-v</span>
Note: Unnecessary use of <span class="nt">-X</span> or <span class="nt">--request</span>, GET is already inferred.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:--     0<span class="k">*</span>   Trying 10.99.232.190...
<span class="k">*</span> TCP_NODELAY <span class="nb">set</span>
<span class="k">*</span> Connected to customer-api.customer-module <span class="o">(</span>10.99.232.190<span class="o">)</span> port 9090 <span class="o">(</span><span class="c">#0)</span>
<span class="o">&gt;</span> GET /api/customer/v1/findById/cust01 HTTP/1.1
<span class="o">&gt;</span> Host: customer-api.customer-module:9090
<span class="o">&gt;</span> User-Agent: curl/7.61.1
<span class="o">&gt;</span> Accept: <span class="k">*</span>/<span class="k">*</span>
<span class="o">&gt;</span>
&lt; HTTP/1.1 200
&lt; Content-Type: application/json
&lt; Transfer-Encoding: chunked
100    94    0    94    0     0    209      0 <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:-- <span class="nt">--</span>:--:--   209
<span class="k">*</span> Connection <span class="c">#0 to host customer-api.customer-module left intact</span>
<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"cust01"</span>,<span class="s2">"userId"</span>:<span class="s2">"dimasm93"</span>,<span class="s2">"fullname"</span>:<span class="s2">"Dimas Maryanto"</span>,<span class="s2">"alamat"</span>:<span class="s2">"Bandung, Jawa Barat"</span><span class="o">}</span>
</code></pre></div></div>

<p>Nah sekarang sudah okay bisa mendapatkan response, kita coba update specifikasi podnya dengan menambahkan variable <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_HOST</code>, <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_PORT</code>, <code class="language-plaintext highlighter-rouge">SERVICE_CUSTOMER_PROTO</code> dengan membuat configmap dan tambahkan ke spec pod <code class="language-plaintext highlighter-rouge">orders-api</code> seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-cm-orders-api-integrasi.yaml"> </script>

<p>Sekarang kita coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl delete pod/orders-api <span class="nt">-n</span> orders-module
kubectl apply <span class="nt">-f</span> kubernetes/ns-orders-api.yaml</code></pre></figure>

<p>Jika dijalankan outputnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl delete pod/orders-api <span class="nt">-n</span> orders-module
pod <span class="s2">"orders-api"</span> deleted

~ » kubectl apply <span class="nt">-f</span> kubernetes/ns-orders-api.yaml
configmap/orders-api created
pod/orders-api created

~ » kubectl get pod <span class="nt">-n</span> orders-module
NAME         READY   STATUS    RESTARTS   AGE
orders-api   1/1     Running   0          40s
postgresql   1/1     Running   0          166m

~ » kubectl logs orders-api <span class="nt">-n</span> orders-module

  <span class="nb">.</span>   ____          _            __ _ _
 /<span class="se">\\</span> / ___<span class="s1">'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '</span>_ | <span class="s1">'_| | '</span>_ <span class="se">\/</span> _<span class="sb">`</span> | <span class="se">\ \ \ \</span>
 <span class="se">\\</span>/  ___<span class="o">)</span>| |_<span class="o">)</span>| | | | | <span class="o">||</span> <span class="o">(</span>_| |  <span class="o">)</span> <span class="o">)</span> <span class="o">)</span> <span class="o">)</span>
  <span class="s1">'  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.2)

2023-02-25T09:51:19.825Z  INFO 1 --- [           main] c.m.dimas.udemy.orders.MainApplication   : Started MainApplication in 42.845 seconds (process running for 46.726)

~ » kubectl exec orders-api -n orders-module -- curl --location --request POST '</span>localhost:9091/api/order/v1/checkout<span class="s1">' \
--header '</span>Content-Type: application/json<span class="s1">' \
--data-raw '</span><span class="o">{</span>
    <span class="s2">"userId"</span>: <span class="s2">"cust01"</span>,
    <span class="s2">"item"</span>: <span class="s2">"Macbook Pro 13</span><span class="se">\"</span><span class="s2"> (A1723)"</span>,
    <span class="s2">"qty"</span>: <span class="s2">"2"</span>
<span class="o">}</span><span class="s1">' -v

* TCP_NODELAY set
* Connected to localhost (::1) port 9091 (#0)
&gt; POST /api/order/v1/checkout HTTP/1.1
&gt; Host: localhost:9091
&gt; User-Agent: curl/7.61.1
&gt; Accept: */*
&gt; Content-Type: application/json
&gt; Content-Length: 82
&gt;
} [82 bytes data]
* upload completely sent off: 82 out of 82 bytes
100    82    0     0  100    82      0     19  0:00:04  0:00:04 --:--:--    19

{"id":"bb9f7d1e-92ef-4307-b412-ce112fbc01f6","createdDate":"2023-02-25T09:52:58.443768159","customer":{"id":"cust01","userId":"dimasm93","fullname":"Dimas Maryanto","alamat":"Bandung, Jawa Barat"},"item":"Macbook Pro 13\" (A1723)","qty":2}

&lt; HTTP/1.1 200
</span></code></pre></div></div>

<p>Okay sampai sini kita sudah berhasil membuat microservice berjalan dengan baik di kubernetes, selanjutnya adalah kita buat feature kubernetes lebih advance lagi.</p>

<h2 id="specify-container-probes">Specify container probes</h2>

<p>Okay, sebelumnya kita khan sudah deploy container springboot untuk service <code class="language-plaintext highlighter-rouge">customer-api</code> dan <code class="language-plaintext highlighter-rouge">orders-api</code> ke Kubernetes cluster, hanya masih belum optimal contohnya startup service masih lama, kemudian jika database connection mati belum ada feature auto recover. Nah jadi untuk menambahkan feature tersebut ada yang perlu kita tambahkan pada framework springboot tersebut yaitu menggunakan lib <code class="language-plaintext highlighter-rouge">spring-boot-starter-actuator</code> yang kita tambahkan ke file <code class="language-plaintext highlighter-rouge">pom.xml</code> seperti berikut:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;project</span> <span class="na">xmlns=</span><span class="s">"http://maven.apache.org/POM/4.0.0"</span>
         <span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
         <span class="na">xsi:schemaLocation=</span><span class="s">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span><span class="nt">&gt;</span>

<span class="c">&lt;!-- project settings --&gt;</span>

<span class="nt">&lt;dependencies&gt;</span>
  <span class="c">&lt;!-- other dependency --&gt;</span>
  <span class="nt">&lt;dependency&gt;</span>
    <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
    <span class="nt">&lt;artifactId&gt;</span>spring-boot-starter-actuator<span class="nt">&lt;/artifactId&gt;</span>
  <span class="nt">&lt;/dependency&gt;</span>
<span class="nt">&lt;/dependencies&gt;</span>

<span class="nt">&lt;/project&gt;</span></code></pre></figure>

<p>Dan edit/tambahkan property <code class="language-plaintext highlighter-rouge">management.health</code> pada file <code class="language-plaintext highlighter-rouge">src/main/resources/application.yaml</code> seperti berikut:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="c1">## other properties</span>
<span class="na">management</span><span class="pi">:</span>
  <span class="na">endpoint</span><span class="pi">:</span>
    <span class="na">health</span><span class="pi">:</span>
      <span class="na">enabled</span><span class="pi">:</span> <span class="kc">true</span>
      <span class="na">probes</span><span class="pi">:</span>
        <span class="na">enabled</span><span class="pi">:</span> <span class="kc">true</span>
      <span class="na">group</span><span class="pi">:</span>
        <span class="na">liveness</span><span class="pi">:</span>
          <span class="na">include</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="s">db</span>
      <span class="na">show-components</span><span class="pi">:</span> <span class="s">always</span>
<span class="na">logging</span><span class="pi">:</span>
  <span class="na">level</span><span class="pi">:</span>
    <span class="na">org.springframework</span><span class="pi">:</span> <span class="s">fatal</span>
    <span class="na">org.flywaydb.core.internal.license</span><span class="pi">:</span> <span class="s">fatal</span>
    <span class="na">org.hibernate</span><span class="pi">:</span> <span class="s">fatal</span></code></pre></figure>

<p>Jika sudah coba jalankan dengan menggunakan perintah berikut</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn clean <span class="nt">-pl</span> customer spring-boot:run</code></pre></figure>

<p>Jika sudah coba akses endpoint <a href="http://localhost:9090/actuator/health">localhost:9090/actuator/health</a> hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » curl localhost:9090/actuator/health
<span class="o">{</span><span class="s2">"status"</span>:<span class="s2">"UP"</span>,<span class="s2">"components"</span>:<span class="o">{</span><span class="s2">"db"</span>:<span class="o">{</span><span class="s2">"status"</span>:<span class="s2">"UP"</span><span class="o">}</span>,<span class="s2">"diskSpace"</span>:<span class="o">{</span><span class="s2">"status"</span>:<span class="s2">"UP"</span><span class="o">}</span>,<span class="s2">"livenessState"</span>:<span class="o">{</span><span class="s2">"status"</span>:<span class="s2">"UP"</span><span class="o">}</span>,<span class="s2">"ping"</span>:<span class="o">{</span><span class="s2">"status"</span>:<span class="s2">"UP"</span><span class="o">}</span>,<span class="s2">"readinessState"</span>:<span class="o">{</span><span class="s2">"status"</span>:<span class="s2">"UP"</span><span class="o">}}</span>,<span class="s2">"groups"</span>:[<span class="s2">"liveness"</span>,<span class="s2">"readiness"</span><span class="o">]}</span>%
</code></pre></div></div>

<p>Jika sudah seperti itu outputnya, lakukan hal yang sama dengan service <code class="language-plaintext highlighter-rouge">orders-api</code> dan kemudian coba re-build container image kemudian push menggunakan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">docker compose build <span class="o">&amp;&amp;</span> <span class="se">\</span>
docker compose push</code></pre></figure>

<p>Setelah kita push container image dari kedua service tersebut, sekarang kita bisa tambahkan feature container probe di kubernetes resource object pod seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-pod-container-probe.yaml"> </script>

<p>Sekarang coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl delete pod customer-api <span class="nt">-n</span> customer-module <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl delete pod orders-api <span class="nt">-n</span> orders-module

kubectl apply <span class="nt">-f</span> kubernetes/pod-container-probes.yaml</code></pre></figure>

<p>Maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl delete <span class="nt">-f</span> kubernetes/pod-container-probes.yaml
pod <span class="s2">"orders-api"</span> deleted
pod <span class="s2">"customer-api"</span> deleted

~ » kubectl apply <span class="nt">-f</span> kubernetes/pod-container-probes.yaml
pod/orders-api created
pod/customer-api created

~ » kubectl get pod <span class="nt">-A</span>
NAMESPACE         NAME             READY   STATUS              RESTARTS   AGE
customer-module   customer-api     0/1     ContainerCreating   0          6s
customer-module   mysql            1/1     Running             0          9m29s
orders-module     orders-api       0/1     Running             0          6s
orders-module     postgresql       1/1     Running             0          9m12s

~ » kubectl describe pod customer-api <span class="nt">-n</span> customer-module
Name:             customer-api
Namespace:        customer-module
Priority:         0
Service Account:  default
Node:             springboot-microservice-m03/192.168.64.25
Start Time:       Sat, 25 Feb 2023 23:53:15 +0700
Labels:           <span class="nv">app</span><span class="o">=</span>customer-api
                  <span class="nv">project</span><span class="o">=</span>customer
                  <span class="nv">tier</span><span class="o">=</span>backend
Status:           Running
IP:               10.244.2.9
IPs:
  IP:  10.244.2.9

Events:
  Type    Reason     Age   From               Message
  <span class="nt">----</span>    <span class="nt">------</span>     <span class="nt">----</span>  <span class="nt">----</span>               <span class="nt">-------</span>
  Normal  Scheduled  20s   default-scheduler  Successfully assigned customer-module/customer-api to springboot-microservice-m03
  Normal  Pulled     18s   kubelet            Container image <span class="s2">"192.168.88.50:8086/dimmaryanto93/example/customer-api:v2"</span> already present on machine
  Normal  Created    17s   kubelet            Created container customer-api
  Normal  Started    17s   kubelet            Started container customer-api

~ » kubectl get pod <span class="nt">-n</span> customer-module
NAME           READY   STATUS    RESTARTS   AGE
customer-api   1/1     Running   0          57s
mysql          1/1     Running   0          19m

~ » kubectl get pod <span class="nt">-n</span> orders-module
NAME         READY   STATUS    RESTARTS   AGE
orders-api   0/1     Running   0          14s
postgresql   1/1     Running   0          20m

~ » kubectl describe pod orders-api <span class="nt">-n</span> orders-module
Name:             orders-api
Namespace:        orders-module
Priority:         0
Service Account:  default
Node:             springboot-microservice-m03/192.168.64.25
Start Time:       Sun, 26 Feb 2023 00:03:58 +0700
Labels:           <span class="nv">app</span><span class="o">=</span>orders-api
                  <span class="nv">project</span><span class="o">=</span>orders-api
                  <span class="nv">tier</span><span class="o">=</span>backend
Annotations:      &lt;none&gt;
Status:           Running
IP:               10.244.2.14
IPs:
  IP:  10.244.2.14

Events:
  Type    Reason     Age   From               Message
  <span class="nt">----</span>    <span class="nt">------</span>     <span class="nt">----</span>  <span class="nt">----</span>               <span class="nt">-------</span>
  Normal  Scheduled  26s   default-scheduler  Successfully assigned orders-module/orders-api to springboot-microservice-m03
  Normal  Pulled     25s   kubelet            Container image <span class="s2">"192.168.88.50:8086/dimmaryanto93/example/order-api:v2"</span> already present on machine
  Normal  Created    25s   kubelet            Created container orders-api
  Normal  Started    25s   kubelet            Started container orders-api

~ » kubectl get pod <span class="nt">-n</span> orders-module
NAME         READY   STATUS    RESTARTS   AGE
orders-api   1/1     Running   0          70s
postgresql   1/1     Running   0          20m
</code></pre></div></div>

<h2 id="specify-resource-request-and-limit">Specify resource request and limit</h2>

<p>Tahap selanjutnya untuk mengoptimalkan penggunaan resource node/worker kita harus specifikasi resource request dan limit. Resource request dan limit ini sangat membantu untuk menambahkan alert pada system kubernetes agar pod tidak menggunakan resource yang berlebih atau masih bisa mencukupi resource yang ada (resource availablity).</p>

<p>Untuk menentukan resource request dan limit ini kita harus mengetahui dulu titik minimum dari workload aplikasi kita dan titik optimal (rata-rata operational) dengan cara melihat activity process, metrics untuk penggunaan cpus dan memory. Sebagai contoh disini saya menggunakan Activity Monitor untuk melihat penggunaan system memory dan cpus.</p>

<p>Berikut adalah cpu yang terpakai dari workload <code class="language-plaintext highlighter-rouge">customer-api</code>:</p>

<p><img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/04-cpus-usage.png" alt="cpu-usage" /></p>

<p>Berikut adalah memory yang terpakai:</p>

<p><img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/04-memory-usage.png" alt="memory-usage" /></p>

<p>Atau selain itu juga kita bisa expose dari service tersebut dengan menambahkan beberapa property <code class="language-plaintext highlighter-rouge">metrics</code> pada <code class="language-plaintext highlighter-rouge">src/main/resources/application.yaml</code> seperti berikut:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="c1">## other properties</span>
<span class="na">management</span><span class="pi">:</span>
  <span class="na">endpoints</span><span class="pi">:</span>
    <span class="na">web</span><span class="pi">:</span>
      <span class="na">exposure</span><span class="pi">:</span>
        <span class="na">include</span><span class="pi">:</span> <span class="s">health,metrics</span></code></pre></figure>

<p>Kemudian coba jalankan dengan perintah:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn clean <span class="nt">-pl</span> customer spring-boot:run</code></pre></figure>

<p>Jika dijalankan hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » curl localhost:9090/actuator/metrics
<span class="o">{</span>
  <span class="s2">"names"</span>: <span class="o">[</span>
    <span class="s2">"application.ready.time"</span>,
    <span class="s2">"application.started.time"</span>,
    <span class="s2">"disk.free"</span>,
    <span class="s2">"disk.total"</span>,
    <span class="s2">"hikaricp.connections"</span>,
    <span class="s2">"hikaricp.connections.acquire"</span>,
    <span class="s2">"hikaricp.connections.active"</span>,
    <span class="s2">"hikaricp.connections.creation"</span>,
    <span class="s2">"hikaricp.connections.idle"</span>,
    <span class="s2">"hikaricp.connections.max"</span>,
    <span class="s2">"hikaricp.connections.min"</span>,
    <span class="s2">"hikaricp.connections.pending"</span>,
    <span class="s2">"hikaricp.connections.timeout"</span>,
    <span class="s2">"hikaricp.connections.usage"</span>,
    <span class="s2">"http.server.requests.active"</span>,
    <span class="s2">"jdbc.connections.active"</span>,
    <span class="s2">"jdbc.connections.idle"</span>,
    <span class="s2">"jdbc.connections.max"</span>,
    <span class="s2">"jdbc.connections.min"</span>,
    <span class="s2">"jvm.buffer.count"</span>,
    <span class="s2">"jvm.buffer.memory.used"</span>,
    <span class="s2">"jvm.buffer.total.capacity"</span>,
    <span class="s2">"jvm.classes.loaded"</span>,
    <span class="s2">"jvm.classes.unloaded"</span>,
    <span class="s2">"jvm.compilation.time"</span>,
    <span class="s2">"jvm.gc.live.data.size"</span>,
    <span class="s2">"jvm.gc.max.data.size"</span>,
    <span class="s2">"jvm.gc.memory.allocated"</span>,
    <span class="s2">"jvm.gc.memory.promoted"</span>,
    <span class="s2">"jvm.gc.overhead"</span>,
    <span class="s2">"jvm.info"</span>,
    <span class="s2">"jvm.memory.committed"</span>,
    <span class="s2">"jvm.memory.max"</span>,
    <span class="s2">"jvm.memory.usage.after.gc"</span>,
    <span class="s2">"jvm.memory.used"</span>,
    <span class="s2">"jvm.threads.daemon"</span>,
    <span class="s2">"jvm.threads.live"</span>,
    <span class="s2">"jvm.threads.peak"</span>,
    <span class="s2">"jvm.threads.states"</span>,
    <span class="s2">"logback.events"</span>,
    <span class="s2">"process.cpu.usage"</span>,
    <span class="s2">"process.files.max"</span>,
    <span class="s2">"process.files.open"</span>,
    <span class="s2">"process.start.time"</span>,
    <span class="s2">"process.uptime"</span>,
    <span class="s2">"system.cpu.count"</span>,
    <span class="s2">"system.cpu.usage"</span>,
    <span class="s2">"system.load.average.1m"</span>,
    <span class="s2">"tomcat.sessions.active.current"</span>,
    <span class="s2">"tomcat.sessions.active.max"</span>,
    <span class="s2">"tomcat.sessions.alive.max"</span>,
    <span class="s2">"tomcat.sessions.created"</span>,
    <span class="s2">"tomcat.sessions.expired"</span>,
    <span class="s2">"tomcat.sessions.rejected"</span>
  <span class="o">]</span>
<span class="o">}</span>%

~ » curl localhost:9090/actuator/metrics/jvm.info
<span class="o">{</span>
  <span class="s2">"name"</span>: <span class="s2">"jvm.info"</span>,
  <span class="s2">"description"</span>: <span class="s2">"JVM version info"</span>,
  <span class="s2">"measurements"</span>: <span class="o">[</span>
    <span class="o">{</span>
      <span class="s2">"statistic"</span>: <span class="s2">"VALUE"</span>,
      <span class="s2">"value"</span>: 1
    <span class="o">}</span>
  <span class="o">]</span>,
  <span class="s2">"availableTags"</span>: <span class="o">[</span>
    <span class="o">{</span>
      <span class="s2">"tag"</span>: <span class="s2">"vendor"</span>,
      <span class="s2">"values"</span>: <span class="o">[</span>
        <span class="s2">"Oracle Corporation"</span>
      <span class="o">]</span>
    <span class="o">}</span>,
    <span class="o">{</span>
      <span class="s2">"tag"</span>: <span class="s2">"runtime"</span>,
      <span class="s2">"values"</span>: <span class="o">[</span>
        <span class="s2">"Java(TM) SE Runtime Environment"</span>
      <span class="o">]</span>
    <span class="o">}</span>,
    <span class="o">{</span>
      <span class="s2">"tag"</span>: <span class="s2">"version"</span>,
      <span class="s2">"values"</span>: <span class="o">[</span>
        <span class="s2">"19.0.1+10-21"</span>
      <span class="o">]</span>
    <span class="o">}</span>
  <span class="o">]</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Temen-temen bisa check menggunakan beberapa property seperti <code class="language-plaintext highlighter-rouge">jvm.memory.used</code>, <code class="language-plaintext highlighter-rouge">system.cpu.usage</code>, <code class="language-plaintext highlighter-rouge">process.cpu.usage</code> dan lain-lain. Okay selanjutnya kita build ulang container imagenya supaya metrics tersebut terexpose dengan perintah</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn clean <span class="nt">-DskipTests</span> package

docker compose build customerAPI <span class="o">&amp;&amp;</span> <span class="se">\</span>
docker compose push customerAPI</code></pre></figure>

<p>Okay jadi disini saya simpulkan bahwa batas minimum atau resource request yaitu <code class="language-plaintext highlighter-rouge">cpu = 100m</code> dan <code class="language-plaintext highlighter-rouge">memory = 250Mi</code> sedangkan untuk maximum limit yaitu <code class="language-plaintext highlighter-rouge">cpu = 1500m</code> dan <code class="language-plaintext highlighter-rouge">memory = 2000Mi</code>. Sekarang kita coba update file pod.yaml menjadi seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-pod-resource-request-limit.yaml"> </script>

<p>Sekarang kita coba jalankan file tersebut dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl delete pod customer-api <span class="nt">-n</span> customer-module <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl delete pod orders-api <span class="nt">-n</span> orders-module

kubectl apply <span class="nt">-f</span> kubernetes/pod-resource-request-limit.yaml</code></pre></figure>

<p>Maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl delete pod customer-api <span class="nt">-n</span> customer-module <span class="o">&amp;&amp;</span> <span class="se">\</span>
kubectl delete pod orders-api <span class="nt">-n</span> orders-module
pod <span class="s2">"customer-api"</span> deleted
pod <span class="s2">"orders-api"</span> deleted

~ » kubectl top node
NAME                          CPU<span class="o">(</span>cores<span class="o">)</span>   CPU%   MEMORY<span class="o">(</span>bytes<span class="o">)</span>   MEMORY%
springboot-microservice       497m         24%    1360Mi          34%
springboot-microservice-m02   266m         13%    1571Mi          40%
springboot-microservice-m03   491m         24%    919Mi           23%

~ » kubectl apply <span class="nt">-f</span> kubernetes/pod-resource-request-limit.yaml
pod/customer-api created
pod/orders-api created

~ » kubectl get pod <span class="nt">-n</span> customer-module
NAME           READY   STATUS    RESTARTS   AGE
customer-api   1/1     Running   0          55s
mysql          1/1     Running   0          6m53s

~ » kubectl top pod customer-api <span class="nt">-n</span> customer-module
NAME           CPU<span class="o">(</span>cores<span class="o">)</span>   MEMORY<span class="o">(</span>bytes<span class="o">)</span>
customer-api   536m         260Mi

~ » kubectl get pod <span class="nt">-n</span> orders-module
NAME         READY   STATUS    RESTARTS   AGE
orders-api   1/1     Running   0          91s
postgresql   1/1     Running   0          7m6s

~ » kubectl top pod orders-api <span class="nt">-n</span> orders-module
NAME         CPU<span class="o">(</span>cores<span class="o">)</span>   MEMORY<span class="o">(</span>bytes<span class="o">)</span>
orders-api   9m           273Mi

~ » kubectl top node
NAME                          CPU<span class="o">(</span>cores<span class="o">)</span>   CPU%   MEMORY<span class="o">(</span>bytes<span class="o">)</span>   MEMORY%
springboot-microservice       151m         7%     1349Mi          34%
springboot-microservice-m02   62m          3%     1861Mi          47%
springboot-microservice-m03   45m          2%     1184Mi          30%
</code></pre></div></div>

<h2 id="implement-api-gateway-using-nginx-reverse-proxy">Implement API Gateway using nginx reverse proxy</h2>

<p>Okay sebelumnya kita sudah deploy workload ke kubernetes cluster, kemudian juga sudah lakukan tuning workloadnya supaya bisa berjalan dengan baik di kubernetes dengan menambahkan container probe dan resource request &amp; limit. Ini adalah ujung dari studikasus ini yaitu kita akan memasang API Gateway. okay temen-temen ada yang tau apa itu API Gateway? mengapa harus menggunakan API Gateway?</p>

<p>An API gateway is an API management tool that sits between a client and a collection of backend services. An API gateway acts as a reverse proxy to accept all application programming interface (API) calls, aggregate the various services required to fulfill them, and return the appropriate result.</p>

<p>Nah karena kita punya banyak services (microservices) jadi pada implementasinya exposing service tersebut tidak satu-per-satu atau setiap service memiliki port sendiri tetapi biasanya menggunakan methode DMZ (Demilitarized Zone) atau satu gerbang untuk beberapa service jika kita ilustrasikan seperti berikut:</p>

<p><img src="/resources/posts/kubernetes/04b-study-cases-microservice-apps/05-dmz-system.png" alt="dmz-services" /></p>

<p>Untuk implementasi API Gateway ini ada lumayan banyak salah satunya adalah <a href="https://apisix.apache.org/">apisix</a>, <a href="https://www.nginx.com/">nginx</a>, <a href="https://www.krakend.io/">KrakenD</a> dan lain-lain. Untuk kasus kali ini kita akan menggunakan yang simple dulu ya yaitu Nginx reverse proxy dengan configurasi seperti berikut:</p>

<script src="https://gist.github.com/dimMaryanto93/c8e8b75d52f1266a6bd7c8f5939c91f4.js?file=04b-api-gateway.yaml"> </script>

<p>Sekarang coba jalankan dengan perintah berikut:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">kubectl apply <span class="nt">-f</span> kubernetes/api-gateway.yaml</code></pre></figure>

<p>Maka hasilnya seperti berikut:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ » kubectl apply <span class="nt">-f</span> kubernetes/api-gateway 
configmap/api-gateway unchanged
pod/api-gateway created
service/api-gateway configured

~ » kubectl get pod,service
NAME              READY   STATUS    RESTARTS   AGE
pod/api-gateway   1/1     Running   0          54s

NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT<span class="o">(</span>S<span class="o">)</span>        AGE
service/api-gateway   NodePort    10.107.243.20    &lt;none&gt;        80:30001/TCP   167m
service/kubernetes    ClusterIP   10.96.0.1        &lt;none&gt;        443/TCP        27h

~ » kubectl cluster-info
Kubernetes control plane is running at https://192.168.64.23:8443
CoreDNS is running at https://192.168.64.23:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use <span class="s1">'kubectl cluster-info dump'</span><span class="nb">.</span>

~ » curl http://192.168.64.23:30001/customers/api/customer/v1/findById/cust01 <span class="nt">-v</span>
<span class="k">*</span>   Trying 192.168.64.23:30001...
<span class="k">*</span> Connected to 192.168.64.23 <span class="o">(</span>192.168.64.23<span class="o">)</span> port 30001 <span class="o">(</span><span class="c">#0)</span>
<span class="o">&gt;</span> GET /customer/api/customer/v1/findById/cust01 HTTP/1.1
<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"cust01"</span>,<span class="s2">"userId"</span>:<span class="s2">"dimasm93"</span>,<span class="s2">"fullname"</span>:<span class="s2">"Dimas Maryanto"</span>,<span class="s2">"alamat"</span>:<span class="s2">"Bandung, Jawa Barat"</span><span class="o">}</span>

~ » curl <span class="nt">--location</span> <span class="nt">--request</span> POST <span class="s1">'http://192.168.64.23:30001/orders/api/order/v1/checkout'</span> <span class="se">\</span>
<span class="nt">--header</span> <span class="s1">'Content-Type: application/json'</span> <span class="se">\</span>
<span class="nt">--data-raw</span> <span class="s1">'{
    "userId": "cust01",
    "item": "Macbook Pro 13\" (A1723)",
    "qty": "2"
}'</span> <span class="nt">-v</span>
Note: Unnecessary use of <span class="nt">-X</span> or <span class="nt">--request</span>, POST is already inferred.
<span class="k">*</span>   Trying 192.168.64.23:30001...
<span class="k">*</span> Connected to 192.168.64.23 <span class="o">(</span>192.168.64.23<span class="o">)</span> port 30001 <span class="o">(</span><span class="c">#0)</span>
<span class="o">&gt;</span> POST /order/api/order/v1/checkout HTTP/1.1
<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"2c25434d-00ec-46e6-b37f-c080291019b2"</span>,<span class="s2">"createdDate"</span>:<span class="s2">"2023-02-26T09:15:03.570489716"</span>,<span class="s2">"customer"</span>:<span class="o">{</span><span class="s2">"id"</span>:<span class="s2">"cust01"</span>,<span class="s2">"userId"</span>:<span class="s2">"dimasm93"</span>,<span class="s2">"fullname"</span>:<span class="s2">"Dimas Maryanto"</span>,<span class="s2">"alamat"</span>:<span class="s2">"Bandung, Jawa Barat"</span><span class="o">}</span>,<span class="s2">"item"</span>:<span class="s2">"Macbook Pro 13</span><span class="se">\"</span><span class="s2"> (A1723)"</span>,<span class="s2">"qty"</span>:2<span class="o">}</span>%
</code></pre></div></div>

<p>Nah jadi disini kesimpulannya yang kita expose adalah ip <code class="language-plaintext highlighter-rouge">192.168.64.23</code> dengan port <code class="language-plaintext highlighter-rouge">30001</code> saja ke router/loadbalancer yang selanjutnya kita bisa lakukan untuk port forwarding ke ip public.</p>]]></content><author><name>Dimas Maryanto</name></author><category term="DevOps" /><category term="Orchestration" /><category term="Kubernetes" /><category term="Pods" /><summary type="html"><![CDATA[Hai semuanya, di materi study cases untuk Pod and Container specification kali ini adalah lanjutan dari sebelumnya yang lebih advanced lagi yaitu Create and build microservices dengan framework Springboot Rest API dengan architecture seperti berikut: Okay nah terlihat sedikit berbeda dengan application monolith sebelumnya, disini setiap service akan saling berkomunikasi dengan menggunakan protocol yang lightweight (ringan) seperti Rest API, grpc, messaging bus, database shared dan lain-lain. Pada study kasus kali ini terlihat pada diagram tersebut masih menggunakan physical / virtual-machine deployement kita akan migrasikan menggunakan orchestration container system dengan Kubernetes. Adapun tahap-tahap yang perlu kita lakukan yaitu Develop aplikasi How code works (Code Review) The new architecture for orchestration container system Containerize apps Deploy to Kubernetes Running as a Pod with namespace Connecting other service from the another namespace Specify container probes (health check) Specify resource request and limit Implement API Gateway using nginx reverse proxy Ok tanpa berlama-lama yuk langsung aja kita bahas materi yang pertama:]]></summary></entry><entry xml:lang="nutanix-ahv"><title type="html">Welcome to the Nutanix HCF (Hybrid Cloud Fundamental)</title><link href="/posts/cloud-computing/nutanix/ahv/01-welcome-nutanix-class" rel="alternate" type="text/html" title="Welcome to the Nutanix HCF (Hybrid Cloud Fundamental)" /><published>2023-02-05T12:00:40+07:00</published><updated>2023-02-05T12:00:40+07:00</updated><id>/posts/cloud-computing/nutanix/ahv/01-welcome-nutanix-class</id><content type="html" xml:base="/posts/cloud-computing/nutanix/ahv/01-welcome-nutanix-class"><![CDATA[<p>Hai semuanya, selamat datang di kelas ‘SRE - Nutanix AHV untuk Pemula sampai Mahir’ di section pertama kali ini kita akan membahas technology yang biasanya digunakan oleh team Infra/Operation yaitu Hyperconverged Infrastructure.</p>

<p>Nah dengan kecanggihan teknology jaman sekarang, technologies dapat membantu mendorong kemajuan suatu perusahan dalam meningkatan performa dalam menentukan goals. Selain itu juga dengan technology perusahaan dapat menentukan flexibility, choice, agility, and cost efficiency supaya memastikan bahwa perusahaan tersebut bisa competitive in the marketplace and innovate, bringing new services and products to their customers faster than ever.</p>

<p>Okay untuk memenuhi semua tantangan tersebut, jadi kita akan membahas dari yang funamental yaitu The Nutanix Cloud Fundamental cource, it designed for familiarize the features, components and capabilities of Nutanix cluster as if this was your first week on the job with a freshly installed Nutanix cluster. Sebelum kita mulai practice lab dengan Nutanix cluster kita akan bahas dulu</p>

<ol>
  <li>What is Nutanix?</li>
  <li>What we can do with Nutanix?</li>
  <li>Why Nutanix?</li>
</ol>

<p>Okay tanpa berlama-lama yuk langsung aja kita bahas materi yang pertama:</p>

<!--more-->

<h2 id="what-is-nutanix">What is Nutanix?</h2>

<blockquote>
  <p>Nutanix, Inc. is an American cloud computing company that sells software, cloud services (such as desktops as a service, disaster recovery as a service, and cloud monitoring), and software-defined storage. Nutanix was founded on September 23, 2009 by Dheeraj Pandey, Mohit Aron and Ajeet Singh.</p>
</blockquote>

<p><br />
<img src="/resources/posts/nutanix-ahv/01-welcome-nutanix/nutanix-logo.png" alt="nutanix-logo" width="500px" /></p>

<p>Jadi Nutanix adalah suatu perusahaan dengan main operation bisnis software yang meng-combine storage, computing, and virtualization menjadi satu kesatuan yang disebut Hyperconverged Infrastructure. Produk utama dari Nutanix yaitu Acropolis, Prism, Era, Frame, and Files. Serta pada tahun 2015 nutanix membuat Linux KVM based hypervisor yang disebut AHV (Acropolis HyperVisor) untuk memanage computer infrastructure lebih mudah.</p>

<p>Pada awal Nutanix berdiri fokus utama bisnis perusahaan adalah berjualan Hardware appliances sama seperti IBM, Lenovo, Dell dan lain-lain tetapi pada 2021 beralih fokus menjadi subscription software. Dimana saat ini Nutanix menjadi partner beberapa vendor hardware tersebut, dengan menjadikan software Nutanix bisa dijalankan diatas hardware vendor seperti IBM, Lenovo.</p>

<h2 id="what-we-can-do-with-nutanix">What we can do with Nutanix?</h2>

<p>The Nutanix Cloud Platform comprises hybrid cloud infrastructure, multicloud management along with unified storage, database services, and desktop services, to support any application and workload, in any location.</p>

<p><img src="/resources/posts/nutanix-ahv/01-welcome-nutanix/nutanix-cloud-platform.png" alt="nutanix-cloud-platform" /></p>

<p>Nutanix menawarkan beberapa solusi untuk workload seperti Cloud, Nutanix Database Service, Unified storage dan Applications.</p>

<ol>
  <li><strong>Cloud</strong>: AHV Virtualization, Nutanix Kubernetes Engine (NKE), Nutanix Discover Recovery dan lain-lain</li>
  <li><strong>Database</strong>: Database as a Services, Database operations dan lain-lain</li>
  <li><strong>Unified storage</strong>: Files storage, Object storage, dan lain-lain</li>
  <li><strong>Application</strong>: AI/ML, Big Data &amp; Analitics dan lain-lain</li>
  <li><strong>End User Computing</strong>: VDI, VMware, Citrix dan lain-lain</li>
</ol>

<h2 id="why-nutanix">Why Nutanix?</h2>

<p>Mungkin dari temen-temen bertanya Nutanix ini software Virtualisasi mengapa tidak menggunakan VMWare atau sejenisnya? the answer is yes but not simple as that.</p>

<p>We solve the toughest cloud challenges, Nutanix unifies public cloud simplicity and agility with private cloud performance and security. Whether on-premises or hybrid, you’ll ensure business continuity through centralized management, one-click operations, and AI-driven automation. It’s your choice.</p>

<p><img src="/resources/posts/nutanix-ahv/01-welcome-nutanix/nutanix-solution.png" alt="nutanix-solution" /></p>

<ol>
  <li><strong>Your apps</strong>: IDC says there will be 500 million new apps by 2023. Nutanix makes it easy to deploy, manage and provision them.</li>
  <li><strong>Your infrastructure</strong>: Compute, storage, virtualization, and networking are hyperconverged and driven by software on the Nutanix Cloud Platform.</li>
  <li><strong>Your cloud</strong>: Whether hybrid, multicloud, public or private, you can move apps effortlessly anywhere you want with zero data loss.</li>
</ol>

<p>Jika kita lihat, Nutanix ada 4 prinsip yaitu</p>

<ol>
  <li><strong>The power of simplicity</strong>: We empower a single team to manage applications, data and security across your multicloud environments.</li>
  <li><strong>We’re data centric</strong>: Deploy, manage and scale a single software-driven storage platform that spans multiple clouds and datacenters.</li>
  <li><strong>Unmatched flexibility</strong>: Our software is server, hypervisor and cloud agnostic so you can build an infrastructure that matches your needs.</li>
  <li><strong>Substantial value</strong>: In five years, we can reduce operating costs by <code class="language-plaintext highlighter-rouge">62%</code> and deliver <code class="language-plaintext highlighter-rouge">477%</code> ROI. We’re obsessed with your long-term success.</li>
</ol>]]></content><author><name>Dimas Maryanto</name></author><category term="Cloud-Computing" /><category term="Nutanix" /><category term="AHV" /><summary type="html"><![CDATA[Hai semuanya, selamat datang di kelas ‘SRE - Nutanix AHV untuk Pemula sampai Mahir’ di section pertama kali ini kita akan membahas technology yang biasanya digunakan oleh team Infra/Operation yaitu Hyperconverged Infrastructure. Nah dengan kecanggihan teknology jaman sekarang, technologies dapat membantu mendorong kemajuan suatu perusahan dalam meningkatan performa dalam menentukan goals. Selain itu juga dengan technology perusahaan dapat menentukan flexibility, choice, agility, and cost efficiency supaya memastikan bahwa perusahaan tersebut bisa competitive in the marketplace and innovate, bringing new services and products to their customers faster than ever. Okay untuk memenuhi semua tantangan tersebut, jadi kita akan membahas dari yang funamental yaitu The Nutanix Cloud Fundamental cource, it designed for familiarize the features, components and capabilities of Nutanix cluster as if this was your first week on the job with a freshly installed Nutanix cluster. Sebelum kita mulai practice lab dengan Nutanix cluster kita akan bahas dulu What is Nutanix? What we can do with Nutanix? Why Nutanix? Okay tanpa berlama-lama yuk langsung aja kita bahas materi yang pertama:]]></summary></entry><entry xml:lang="nutanix-ahv"><title type="html">Silabus SRE - Nutanix AHV: Pemula sampai Mahir</title><link href="/posts/cloud-computing/nutanix/ahv/00-silabus-nutanix-ahv" rel="alternate" type="text/html" title="Silabus SRE - Nutanix AHV: Pemula sampai Mahir" /><published>2023-02-04T20:23:05+07:00</published><updated>2023-02-04T20:23:05+07:00</updated><id>/posts/cloud-computing/nutanix/ahv/00-silabus-nutanix-ahv</id><content type="html" xml:base="/posts/cloud-computing/nutanix/ahv/00-silabus-nutanix-ahv"><![CDATA[<p>Hai semuanya, di cource ini kita akan membahas salah satu Profesi IT yaitu <strong>Site Reliability Engineering</strong> atau yang biasa kita kenal dengan <strong>SRE Engineer</strong> terkait dengan <strong>Nutanix HCI (Hyper-Converged Infrastructure)</strong>.</p>

<p>Mungkin dari temen-temen masih asing atau mungkin sudah pernah mendengar istilah SRE Engineer tetapi gak teralu mengerti seperti apa profesi tersebut, Di instrustri IT khususnya tech company banyak sekali loh profesi-profesi selain programmer yang relate dengan IT salah satunya adalah Site Reliability Engineering. Nah terus apasih Site Reliability Engineering?</p>

<blockquote>
  <p>Site Reliability Engineering atau singkatan dari SRE adalah salah satu pekerjaan di bidang IT yang specialis menangani reliabilitas suatu aplikasi atau software agar bisa berjalan dengan baik pada suatu infrastruktur yang sesuai.</p>
</blockquote>

<!--more-->

<p>Mungkin dari temen-temen masih belum tergambar magsudnya seperti apa? Okay nah jika temen-temen banyangkan dalam suatu development lifecycle biasanya terdiri beberapa team yaitu developer/programmer, bisnis analis, project/product manager, dan operation. Berikut adalah tugas masing-masing team:</p>

<ol>
  <li>Bisnis analis: bertugas merumuskan design berdasarkan user requirement yang di translate ke diagram agar mudah di terjemahkan oleh developer</li>
  <li>Developer: bertugas menterjemahkan hasil design yang dibuat oleh bisnis analis menjadi software atau kode program</li>
  <li>Operation: bertugas untuk mendeliver software atau kode program yang telah dibuat oleh programmer ke environment atau yang biasa disebut infrastructure.</li>
  <li>Project/Product manager: bertugas untuk menjaga timeline, distribute task ke masing-masing team dan memastikan feature yang dibuat sesuai dengan user requirement.</li>
</ol>

<p>Nah salah satu problem yang biasa ditemui di perusahaan besar adalah orang Developer/Programer gak ngerti infra sedangkan orang Operation gak ngerti Programming jadi begitu mau deliver software dari Developer/Programmer ke team Operation apakah langsung bisa jalan??? tentu saja tidak nah maka dari itu disini ada yang namanya SRE atau Site Reliability Engineering. Jadi secara umum tanggung jawab Site Reliability Engineering adalah untuk membantu atau sebagai penengah antara team Developer/Programmer dan team Operation.</p>

<p>Nah kira-kira udah ada gambaran sedikit khan tanggung jawab SRE seperti apa, nah jadi dikelas ini kita bahas dengan studi kasus menggunakan Nutanix HCI platform. Untuk memenuhi semua itu temen-temen perlu memahami dulu platform yang akan digunakan contohnya menggunakan Nutanix Hyper-Converged Infrastructure dan juga beberapa prinsip Developer/Programmer.</p>

<p>Materi yang akan dibahas di kelas ini adalah gabungan dari 3 bidang yaitu Infrastructur, Operation, Development dan DevOps knowledge seperti berikut:</p>

<h3 id="infrastructur-knowledge">Infrastructur knowledge</h3>

<ol>
  <li>What is Nutanix HCI</li>
  <li>Overview Hardware, Servers, dan Networking</li>
  <li>Introduction to Nutanix AHV</li>
  <li>Nutanix Prism Element</li>
  <li>Nutanix Prism Central</li>
  <li>Virtual Machine (VM)</li>
  <li>Monitoring cluster</li>
  <li>Lifecycle management</li>
</ol>

<h3 id="operation-knowledge">Operation knowledge</h3>

<ol>
  <li>System operation</li>
  <li>OS Server</li>
  <li>Management files</li>
  <li>Linux bash/shell script</li>
  <li>Networking tools</li>
</ol>

<h3 id="development-knowlage">Development knowlage</h3>

<ol>
  <li>What is Programming language?</li>
  <li>Types of programming language?</li>
  <li>What is tools they used to develop application/software?</li>
  <li>How to work with programmer?</li>
</ol>

<h3 id="devops-knowlage">DevOps knowlage</h3>

<ol>
  <li>What is DevOps?</li>
  <li>What is tools they used to automate deployment of application/software that developer created?</li>
  <li>What the different between DevOps and SRE?</li>
</ol>

<p>Okay mungkin sekian dulu yang bisa saya bahas terkait silabus yang akan kita pelajari di kelas ‘SRE - Nutanix AHV: Pemula sampai Mahir’, semoga temen-temen tertarik mengikuti kelas ini sampai akhir sampai jumpa dikelas!!!</p>]]></content><author><name>Dimas Maryanto</name></author><category term="Cloud-Computing" /><category term="Nutanix" /><category term="AHV" /><summary type="html"><![CDATA[Hai semuanya, di cource ini kita akan membahas salah satu Profesi IT yaitu Site Reliability Engineering atau yang biasa kita kenal dengan SRE Engineer terkait dengan Nutanix HCI (Hyper-Converged Infrastructure). Mungkin dari temen-temen masih asing atau mungkin sudah pernah mendengar istilah SRE Engineer tetapi gak teralu mengerti seperti apa profesi tersebut, Di instrustri IT khususnya tech company banyak sekali loh profesi-profesi selain programmer yang relate dengan IT salah satunya adalah Site Reliability Engineering. Nah terus apasih Site Reliability Engineering? Site Reliability Engineering atau singkatan dari SRE adalah salah satu pekerjaan di bidang IT yang specialis menangani reliabilitas suatu aplikasi atau software agar bisa berjalan dengan baik pada suatu infrastruktur yang sesuai.]]></summary></entry></feed>