---
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**.

Kemudian kita harus mengisi nama projek dan deskripsi projek (optional), setelah itu klik **Create Project**.

Kita akan membuat sebuah *Dockerfile* yang nantinya akan menjadi Docker Image, untuk membuat *Dockerfile* kita cukup mengklik **New File**.

Buat *Dockerfile* yang berisikan code berikut.

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***

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

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.

Proses ***publish***

Proses ***deploy***

## 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`.

* 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.

* Selanjutnya kita akan mengakses *GUI ONOS* melalui *browser* dengan memasukkan user `onos` dan kata sandi `rocks`.

* 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() ) }

* 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()) }

* 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

* Selanjutnya jalankan perintah berikut guna mengaktifkan *GRE Tunnel* antara S1 dan S2.
*Virtual Machine* 1 :

*Virtual Machine* 2 :

* Selanjutnya kita harus mengaktifkan fitur *Reactive Forwarding* yang tersedia pada *GUI ONOS* yang telah kita buka pada *browser*.

* 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.
