--- title: 'Cara Set Up Continuos Deployment Pipeline dengan menggunakan Docker dan Gitlab CI/CD' disqus: hackmd --- Cara *Set Up Continuos Deployment Pipeline* dengan menggunakan Docker dan Gitlab CI/CD === Pada kesempatan ini, kami akan melakukan simulasi tentang cara *Set Up a Continuous Deployment Pipeline* dengan menggunakan Docker dan GitLab CI/CD. Disini kami akan membuat terlebih dahulu Docker Image yang berisikan sebuah tools Mininet, setelah itu kami merancang sebuah kode untuk menjalankan Docker Image tersebut menjadi sebuah Container di Virtual Machine Ubuntu 18.04. Simak selengkapnya dalam tutorial ini. ## Daftar Isi [TOC] ## Pendahuluan Docker images adalah sebuah template yang bersifat read only. Template ini sebenarnya adalah sebuah OS atau OS yang telah diinstall berbagai aplikasi. Docker images berfungsi untuk membuat docker container, dengan hanya 1 docker images kita dapat membuat banyak docker container. Docker images dapat dibangun melalui 2 cara, menggunakan Dockerfile yaitu suatu file dengan format penulisan yaml yang dipergunakan oleh docker engine untuk menciptakan suatu image berdasarkan baris perintah dan konfigurasi yang terdapat pada file dan melalui docker-commit selayaknya melakukan commit pada Git versioning system. Docker Container menjadi wadah bagi instance Docker image. Membuat dan menjalankan Image menghasilkan Docker container. Image menyediakan template yang digunakan dalam pembuatan container. Di dalam image, terdapat informasi yang dibutuhkan untuk membuat container. Image bisa disimpan di komputer atau secara remote. GitLab adalah platform berbasis open-source yang menyediakan fitur-fitur canggih selain menghosting repositori kode. Dengan menggunakan Gitlab kita dapat mengatur ***continuous integration (CI) & continuous deployment (CD)***, dan banyak lagi. Dalam tutorial ini kita akan membuat pipeline penerapan berkelanjutan dengan GitLab. Kita akan mengonfigurasi pipeline untuk membuat image Docker, mendorongnya ke registry container GitLab, dan menerapkannya ke server Anda menggunakan SSH. Pipeline akan berjalan untuk setiap komit yang didorong ke repositori. *Prerequisites* --- Untuk dapat menjalankan tutorial ini, kita membutuhkan: - Satu server Ubuntu versi 18.04. - Docker yang terpasang pada server Ubuntu Tersebut - *User account di GitLab*, *free plan* sudah cukup untuk menjalankan tutorial ini. You can also host your own GitLab instance by following the How To Install and Configure GitLab on Ubuntu 18.04 guide. Pembuatan *GitLab Repository dan Dockerfile* --- Log in pada GitLab instance dan klik **New project**. ![](https://i.imgur.com/elGAjlK.png) Kemudian kita harus mengisi nama projek dan deskripsi projek (optional), setelah itu klik **Create Project**. ![](https://i.imgur.com/3pFAZrZ.png) Kita akan membuat sebuah *Dockerfile* yang nantinya akan menjadi Docker Image, untuk membuat *Dockerfile* kita cukup mengklik **New File**. ![](https://i.imgur.com/Bv9kAxO.png) Buat *Dockerfile* yang berisikan code berikut. ![](https://i.imgur.com/B72DoRb.png) FROM debian:stretch-slim ENV DEBIAN_FRONTEND=noninteractive # Install packages RUN apt-get update && \ apt-get install \ --no-install-recommends \ --no-install-suggests \ -y \ apt-utils ca-certificates cgroup-bin cgroup-tools cpp cpp-6 curl fontconfig-config fonts-dejavu-core git git-man iperf iproute2 iputils-ping kmod libapt-inst2.0 libatomic1 libbsd0 libcap2 libcgroup1 libcurl3 libcurl3-gnutls libelf1 liberror-perl libexpat1 libffi6 libfontconfig1 libfreetype6 libgdbm3 libgmp10 libgnutls30 libgpm2 libgssapi-krb5-2 libhogweed4 libice6 libidn11 libidn2-0 libisl15 libk5crypto3 libkeyutils1 libkmod2 libkrb5-3 libkrb5support0 libldap-2.4-2 libldap-common libmnl0 libmpc3 libmpfr4 libncurses5 libnettle6 libnghttp2-14 libp11-kit0 libpcap0.8 libperl5.24 libpng16-16 libprocps6 libpsl5 libpython-stdlib libpython2.7-minimal libpython2.7-stdlib libreadline7 librtmp1 libsasl2-2 libsasl2-modules-db libsm6 libsqlite3-0 libssh2-1 libssl1.0.2 libssl1.1 libtasn1-6 libunistring0 libutempter0 libwrap0 libx11-6 libx11-data libxau6 libxaw7 libxcb1 libxcursor1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxmu6 libxmuu1 libxpm4 libxrandr2 libxrender1 libxt6 libxxf86vm1 mime-support net-tools netbase openssl openvswitch-common openvswitch-switch patch perl perl-modules-5.24 procps python python-minimal python-pkg-resources python-six python2.7 python2.7-minimal readline-common socat sudo tcpdump telnet ucf uuid-runtime wireshark x11-common x11-xserver-utils xbitmaps xterm xxd # Prepare Mininet Install RUN rm -rf /home/openflow/ && \ mkdir /usr/share/man/man1 # Install Mininet from git RUN git clone https://github.com/mininet /mininet.git /home/mininet/ WORKDIR /home/mininet/ RUN git checkout 2.2.2 COPY mod_install.sh /home/mininet/util/install.sh RUN chmod +x /home/mininet/util/install.sh && \ /home/mininet/util/install.sh -fnv # Prepare Start EXPOSE 6633 6653 6640 COPY entrypoint.sh /home/entrypoint.sh RUN chmod +x /home/entrypoint.sh ENTRYPOINT [ "/home/entrypoint.sh" ] > Read more about mermaid here: http://mermaid-js.github.io/mermaid/ *Registering Gitlab Runner di Virtual Machine* --- Untuk menjalankan *Gitlab Runner*, sebelumnya kita harus menambahkan terlebih dahulu repository Official dari Gitlab. **Unduh dan inspect instalasi script.** curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh > script.deb.sh less script.deb.sh Jalankan ***installer*** sudo bash script.deb.sh Install ***gitlab-runner*** sudo apt install gitlab-runner Untuk *register* *gitlab runner* kita perlu mendapatkan ***project token*** dan ***Gitlab URL*** 1. Masuk pada laman ***Settings > CI/CD > Runners.*** 2. Pilih ***Set up a specific Runner manually***, disini kita akan mendapatkan ***project token*** dan ***Gitlab URL*** ![](https://i.imgur.com/0ANNuo1.png) Kembali ke terminal Ubuntu, register runner tersebut dengan command sudo gitlab-runner register -n --url https://your_gitlab.com --registration-token project_token --executor docker --description "Deployment Runner" --docker-image "docker:stable" --tag-list deployment --docker-privileged Fungsi dari ***command*** tersebut adalah -n menjalankan perintah register secara non-interaktif (kami menetapkan semua parameter yang ada sebagai opsi perintah). --url merupakan URL GitLab yang dapat disalin dari website runner di GitLab. --registration-token merupakan token yang disalin dari website runner di GitLab. --executor merupakan tipe eksekutor. Docker mengeksekusi setiap tugas CI/CD dalam Docker Container (lihat dokumentasi GitLab tentang eksekutor). --description merupakan deskripsi runner, yang nantinya akan ditampilkan di GitLab. --docker-image merupakan image Docker default yang digunakan dalam tugas CI/CD, fika tidak ditentukan secara spesifik. --tag-list merupakan daftar dari sebuah tag yang ditetapkan ke dalam runner. Tag dapat digunakan dalam konfigurasi pipeline untuk memilih runner tertentu untuk pekerjaan CI/CD. Penerapan tag memungkinkan kita merujuk ke runner khusus untuk menjalankan proses penerapan. --docker-privileged mengeksekusi Docker Container yang dibuat untuk setiap pekerjaan CI/CD ketika dalam mode privileged. Container dengan mode privileged memiliki akses ke semua perangkat dalam host dan memiliki akses yang hampir sama ke host seperti proses yang berjalan di luar container (lihat dokumentasi Docker tentang mode privileged dan fungsi Linux). Tujuan menjalankan mode privileged adalah agar dapat menggunakan Docker-in0Docker (dind) untuk membuat image Docker di pipeline CI/CD. Ini merupakan praktek yang bagus guna memberikan Container spesifikasi minimun yang dibutuhkan. Mode privileged merupakan sebuah kebutuhan agar dapat menggunakan Docker-in-Docker. Berhati hatilah ketika sudah meregistrasi runner spesifik hanya untuk projek ini saja, tempat untuk mengontrol perintah yang dijalankan dengan mode privileged. Verifikasi apakah runner telah berhasil berjalan atau tidak ![](https://i.imgur.com/FR0OJCk.png) Konfigurasi SSH --- Langkah pertama tambahkan pengguna untuk dapat mengakses ssh pada server adduser deployer su deployer Selanjutnya, generate sebuah 4096-bit SSH key ssh-keygen -b 4096 Tampilkan SSH Private key cat ~/.ssh/id_rsa Selanjutnya kita akan menambahkan private key tersebut pada ***Settings > CI / CD > Variables*** di GitLab project kita dan klik ***Add Variable.*** Isi form tersebut sebagai berikut: Key: ID_RSA Value: Paste SSH private key dari ~/.ssh/id_rsa Type: File Environment Scope: All (default) Protect variable: Checked Mask variable: Unchecked Tambahkan variable dengan alamat server IP. Klik Add Variable dan isi form sebagai berikut: Key: SERVER_IP Value: IP_server Type: Variable Environment scope: All (default) Protect variable: Checked Mask variable: Checked Terakhir, buat variable dengan login user *deployer*. Klik Add Variable dan isi form sebagai berikut: Key: SERVER_USER Value: deployer Type: Variable Environment scope: All (default) Protect variable: Checked Mask variable: Checked Konfigurasi file *-gitlab-ci.yml* --- Kita akan mengonfigurasi pipeline GitLab CI / CD. Pipeline akan membuat image Docker dan push docker image tersebut ke registry container. Langkah terakhir dalam pipeline adalah docker image akan masuk ke server ubuntu, remove docker container yang lama, dan mulai dengan container yang baru. Langkah pertama kita harus mendefinisikan *stage*. *Stage* akan dijalankan sesuai urutan yang ditentukan. Di sini, tahap ***publish*** akan dilakukan pertama dan tahap ***deploy*** dijalankan kedua. Tahapan yang berurutan hanya dimulai ketika tahap sebelumnya berhasil diselesaikan (yaitu, semua pekerjaan telah berlalu). stages: - publish - deploy Bagian variabel menentukan *environment* yang akan tersedia dalam konteks bagian **job’s script section**. Variabel ini akan tersedia sebagai variabel Linux environment variables; artinya, kita dapat mereferensikannya dalam skrip dengan mengawali dengan tanda dolar seperti ***$TAGLATEST***. GitLab membuat beberapa variabel yang telah ditentukan untuk setiap pekerjaan yang menyediakan informasi spesifik konteks, seperti nama cabang atau hash komit yang sedang dikerjakan runner . Di sini Anda membuat dua variabel dari variabel yang telah ditentukan. Mereka mewakili: CI_REGISTRY_IMAGE: Merepresentasikan URL dari registry container yang terkait dengan proyek tertentu. URL ini bergantung pada instance di GitLab. Misalnya, URL registry untuk proyek gitlab.com mengikuti pola : registry.gitlab.com/your_user/your_project. Namun karena GitLab akan menyediakan variabel ini, maka kita tidak perlu mengetahui secara persis URL tersebut. CI_COMMIT_REF_NAME: Merupakan nama cabang atau tag untuk proyek yang akan dibuat. CI_COMMIT_SHORT_SHA: Merupakan delapan karakter pertama dari revisi komit untuk proyek yang sedang dibangun. Variabel yang ditambahkan akan menjadi sebagai berikut: variables: TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA Selanjutnya kita akan menambahkan *stage publish* dengan memasukan code sebagai berikut: publish: image: docker:latest stage: publish services: - docker:dind script: - docker build -t $TAG_COMMIT -t $TAG_LATEST . - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY - docker push $TAG_COMMIT - docker push $TAG_LATEST Keterangan pada script tersebut adalah sebagai berikut: image adalah Docker image yang akan digunakan untuk tugas ini. Runner GitLab akan membuat Docker container untuk setiap pekerjaan dan menjalankan script dalam container ini. docker:latest image memastikan bahwa perintah Docker akan selalu tersedia. stage menugaskan pekerjaan ke tahap publikasi. services menentukan Docker-in-Docker dind service. Ini adalah alasan mengapa kita harus mendaftarkan runner GitLab dalam mode privileged. Script section pada publish job specifies the shell commands untuk melakukan job tersebut. Working directory akan di set ke repository root ketika command dibawah diekskusi: docker build ...: Membangun Docker image berdasarkan Dockerfile dan menandainya dengan tag commit terbaru yang ditentukan di bagian variabel. docker login ...: Memasukkan Docker ke dalam container registry projek. Menggunakan variabel standard $CI_BUILD_TOKEN sebagai token otentikasi. GitLab akan menghasilkan token dan tetap valid selama masa pengerjaan berlangsung. docker push ...: Mendorong kedua image tag ke container registry. Selanjutnya untuk ***stage deploy*** tambahkan kode yang tertera di bawah ini: deploy: image: alpine:latest stage: deploy tags: - deployment script: - chmod og= $ID_RSA - apk update && apk add openssh-client - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f tugas-uts || true" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run --privileged --name tugas-uts $TAG_COMMIT mn --test pingall" Alpine adalah distribusi Linux yang ringan dan cukup sebagai image Docker di sini. Anda menetapkan pekerjaan ke tahap penerapan. Tag penerapan memastikan bahwa pekerjaan akan dijalankan pada pelari yang diberi tag publish, seperti runner yang Anda konfigurasikan pada Langkah 2. Script section pada *deploy job* dimulai dengan dua configurative commands: chmod og= $ID_RSA: Mencabut semua izin untuk group dan lainnya dari private key, sehingga hanya pemilik yang dapat menggunakannya. Ini adalah sebuah persyaratan, jika tidak dilakukan maka SSH akan menolak untuk menggunakan private key. apk update && apk add openssh-client: Memperbaharui manajer paket Alpine (apk) dan menginstall openssh-client, yang menyediakan perintah ssh. Untuk melakukan command ssh didefinisikan dengan command berikut: ssh connect pattern for all deployment commands ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "command" Options tersebut merupakan: -i Merupakan singkatan dari file identitas dan $ID_RSA adalah variabel GitLab yang berisi jalur ke file private key. -o StrictHostKeyChecking=no Memastikan untuk melewati pertanyaan, apakah kita mempercayai host jarak jauh atau tidak. Pertanyaan ini tidak dapat dijawab dalam konteks non-interaktif seperti pipeline. $SERVER_USER and $SERVER_IP Merupakan variabel GitLab yang dibuat pada langkah ke 5. Menentukan host jarak jauh dan pengguna login untuk koneksi SSH. command akan dijalankan pada host jarak jauh. Beberapa command yang dieksekusi adalah sebagai berikut: docker login ...: Memasukkan Docker ke dalam container registry. docker pull ...: Menarik image terbaru dari container registry. docker container rm ...: Menghapus container yang ada jika tersedia. || true memastikan bahwa kode yang dikeluarkan selalu berhasil, meskipun tidak ada penampung yang dijalankan dengan nama tugas-uts. Ini menjamin penghapusan tanpa merusak pipeline ketika container tidak tersedia (misalnya, untuk penerapan perdana). docker run ...: Memilai container baru menggunakan image yang terbaru dari registry. Container akan dinamai tugas-uts. mn --test pingall percobaan tes ping pada semua host. Terakhir kita akan menambahkan ***GitLab environments*** Saat tugas pipeline menentukan bagian environment, GitLab akan membuat penerapan untuk environment tertentu setiap kali job berhasil diselesaikan. Ini memungkinkan kita melacak semua penerapan yang dibuat oleh GitLab CI / CD. Untuk setiap penerapan. . . . deploy: . . . environment: name: production url: http://your_server_IP only: - master Maka untuk percobaan kali ini, isi kode dari ***.gitlab-ci.yml*** adalah sebagai berikut: stages: - publish - deploy variables: TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA publish: image: docker:latest stage: publish services: - docker:dind script: - docker build -t $TAG_COMMIT -t $TAG_LATEST . - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY - docker push $TAG_COMMIT - docker push $TAG_LATEST deploy: image: alpine:latest stage: deploy tags: - deployment script: - chmod og= $ID_RSA - apk update && apk add openssh-client - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f tugas-uts || true" - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run --privileged --name tugas-uts $TAG_COMMIT mn --test pingall" environment: name: production url: http://ip_server only: - master Validasi *Deployment* --- Buka ***CI / CD> Pipelines*** di project GitLab untuk melihat status pipeline. Jika job masih berjalan / tertunda, tunggu sampai selesai. Kita akan melihat pipeline Lulus dengan dua tanda centang hijau, yang menunjukkan bahwa pekerjaan ***publish*** dan ***deploy*** berjalan dengan sukses. ![](https://i.imgur.com/09ZC6FY.png) Proses ***publish*** ![](https://i.imgur.com/GTQIDY3.png) Proses ***deploy*** ![](https://i.imgur.com/hkdBbIq.png) ## Kesimpulan Dalam tutorial ini, Kita telah mengonfigurasi pipeline penerapan berkelanjutan dengan ***Docker dan GitLab CI / CD***. Kita membuat docker image mininet pada Dockerfile, kemudian kita mengonfigurasi konfigurasi pipeline .gitlab-ci.yml dengan tujuan: 1. Build the Docker image. 2. Push the Docker image ke container registry. 3. Log in ke server, pull image mininet terbaru, stop current container, dan start container baru. --- Cara Menghubungkan 2 *Virtual Machine Mininet* dengan *GRE Tunnel* dan mengontrol *Network* menggunakan *Controller ONOS* === Pada kesempatan kali ini, kami akan melakukan simulasi tentang cara menghubungkan 2 *Virtual Machine Mininet* dengan *GRE Tunnel* dan mengontrol *Network* menggunakan *controller ONOS*. Disini kami akan membuat terlebih dahulu 3 *Virtual Machine*, 2 *Virtual Machine Mininet* akan dihubungkan satu sama lain dengan menggunakan *GRE Tunnel*, dan 1 *Virtual Machine* akan digunakan sebagai *controller*. Dalam percobaan kali ini, kami menggunakan *controller ONOS*. Simak selengkapnya dalam tutorial ini. *Prerequisites* --- Untuk dapat menjalankan tutorial ini, berikut adalah spesifikasi *Virtual Machine* yang akan digunakan: 1. Mininet-2.3.0b2-210131-ubuntu-18.04.5-server-amd64-ovf sebagai *Virtual Machine* 1 2. Mininet-2.3.0rc2-210209-ubuntu-18.04.5-server-amd64-ovf sebagai *Virtual Machine* 2 3. Mininet-2.3.0-210211-ubuntu-18.04.5-server-amd64-ovf sebagai *Virtual Machine* 3 (Controller ONOS) Menghubungkan 2 *Virtual Machine* menggunakan *GRE Tunnel* === * Langkah pertama yang harus kita lakukan adalah mempersiapkan ketiga *Virtual Machine* yang akan digunakan dan menjalankannya. * Selanjutnya kita akan melakukan SSH ke *Virtual Machine Mininet* menggunakan software *PuTTY*. Dalam percobaan ini *IP Address* yang dimiliki *Virtual Machine* pertama adalah `192.168.74.128`, sedangkan *IP Address* yang dimiliki *Virtual Machine* kedua adalah `192.168.74.131`. ![](https://i.imgur.com/dqKz4hM.png) * Selanjutnya kita akan menjalankan *ONOS* yang terdapat pada *Virtual Machine* ketiga dengan perintah sebagai berikut : `sudo systemct1 start onos` `sudo systemct1 status onos` Berikut ini adalah contoh screenshot yang menunjukkan bahwa *ONOS* sudah berjalan. ![](https://i.imgur.com/XdGvZwR.png) * Selanjutnya kita akan mengakses *GUI ONOS* melalui *browser* dengan memasukkan user `onos` dan kata sandi `rocks`. ![](https://i.imgur.com/mau2d04.png) * Selanjutnya pada *Virtual Machine* pertama dengan *IP Address* `192.168.74.128` kita akan membuat skrip *Python* dengan menuliskan perintah `nano test.py`, kemudian tuliskan skrip *Python Mininet* guna membuat topologi menggunakan *GRE Tunnel* sebagai berikut : ``` from mininet.topo import Topo class MyTopo( Topo ): "Simple topology example." def __init__( self ): "Create custom topo." # Initialize topology Topo.__init__( self ) # Add hosts and switches h1 =self.addHost('h1',ip='10.0.0.101') s1 = self.addSwitch( 's1' ) # Add links self.addLink( h1, s1 ) topos = { 'mytopo':( lambda: MyTopo() ) } ![](https://i.imgur.com/1Wqpmwy.png) * Selanjutnya pada *Virtual Machine* pertama dengan *IP Address* `192.168.74.131` kita akan membuat skrip *Python* dengan menuliskan perintah `nano test.py`, kemudian tuliskan skrip *Python Mininet* guna membuat topologi menggunakan *GRE Tunnel* sebagai berikut : ``` from mininet.topo import Topo class MyTopo( Topo ): "Simple topology example." def __init__( self ): "Create custom topo." # Initialize topology Topo.__init__( self ) # Add hosts and switches leftHost = self.addHost( 'h2',ip='10.0.0.102') leftSwitch = self.addSwitch( 's2' ) # Add links self.addLink( leftHost, leftSwitch ) topos = { 'mytopo': (lambda:MyTopo()) } ![](https://i.imgur.com/RXOBuIQ.png) * Selanjutnya tuliskanlah perintah sebagai berikut pada kedua *Virtual Machine Mininet* : ``` mn --custom ./test.py --topo mytopo --switch ovsk --controller remote,ip=192.168.74.133 ![](https://i.imgur.com/3gXftXe.png) * Selanjutnya jalankan perintah berikut guna mengaktifkan *GRE Tunnel* antara S1 dan S2. *Virtual Machine* 1 : ![](https://i.imgur.com/8K984hR.png) *Virtual Machine* 2 : ![](https://i.imgur.com/yNgVNHK.png) * Selanjutnya kita harus mengaktifkan fitur *Reactive Forwarding* yang tersedia pada *GUI ONOS* yang telah kita buka pada *browser*. ![](https://i.imgur.com/BHh7jcp.png) * Langkah terakhir yaitu melakukan tes *ping* antar *Virtual Machine 1 dan Virtual Machine 2*, apabila berhasil maka proses *ping* akan berjalan dengan sukses seperti gambar di bawah ini. ![](https://i.imgur.com/DjpJrNY.png)