Pada artikel sebelumnya, penulis telah menjelaskan bagaimana cara melakukan deployment docker ke heroku, akan tetapi cara tersebut bisa dibilang sangat melelahkan ketika kita harus memanage banyak service. Untuk dapat melakukan otomatisasi keseluruhan service maka kita akan menggunakan bantuan CI/CD yang ditawarkan oleh gitlab. Untuk penjelasan mengenai CI/CD, anda dapat membaca artikel Belajar Melakukan Integrasi Jenkins Dan Gitlab Pada Docker. Pada artikel ini, kita akan mencoba membuat CI/CD untuk kebutuhan deployment service yang terdapat pada artikel Belajar Deployment Docker Pada Heroku.

Arsitektur Deployment Dengan Gitlab CI/CD

Berikut adalah arsitektur yang akan kita gunakan untuk CI/CD pada gitlab.

Arsitektur Gitlab CI_CD.png

Berikut adalah penjelasan dari gambar diatas.

  1. Developer akan melakukan pull code terlebih dahulu yang berasal dari gitlab
  2. Jika telah selesai mengubah atau menambahkan code, maka developer melakukan push code ke gitlab
  3. Jika terdapat perubahan, gitlab akan melakukan build source code lalu melakukan testing, biasanya trigger perubahan ini dapat dilakukan pada branch tertentu.
  4. Jika proses build source code dan testing berhasil maka gitlab akan melakukan build docker image, lalu docker image ini akan di push ke docker hub.
  5. Setelah selesai melakukan push ke docker hub, gitlab akan melakukan deployment ke heroku. Pada saat proses deployment, gitlab akan melakukan pull image terlebih dahulu dari docker hub, lalu image terebut nantinya akan di push ke registry heroku.
  6. Jika proses push docker image ke registry heroku berhasil, maka heroku akan menjalankan image tersebut.

Import Project Dari Github Ke Gitlab

Salah satu alasan menggunakan gitlab adalah gitlab memberikan banyak fitur terutama untuk penggunaan devops. Untuk melakukan import project dari github ke gitlab, silahkan lakukan langkah - langkah berikut.

  1. Silahkan login pada website gitlab. Lalu silahkan buat sebuah project, lalu pilih tab import project seperti gambar berikut.

Screen Shot 2018-03-03 at 7.20.05 PM

  1. Lalu pilih import dari github, maka akan muncul output seperti berikut.

Screen Shot 2018-03-03 at 7.29.22 PM.png

Lalu klik authorize sehingga gitlab dapat mengakses repo anda yang ada di github.

  1. Lalu pilih repo seperti berikut.

Screen Shot 2018-03-03 at 7.31.37 PM.png

  1. Setelah selesai, silahkan clone kembali repo Heroku-Container yang berasal dari gitlab seperti berikut
git clone git@gitlab.com:RizkiMufrizal/Heroku-Container.git

Membuat Unit Test Pada Spring Boot

Silahkan buka class HerokuContainerApplicationTests yang terdapat di dalam package org.rizki.mufrizal.heroku.container. Kemudian silahkan ubah source code nya menjadi seperti berikut untuk kebutuhan testing.

package org.rizki.mufrizal.heroku.container

import com.fasterxml.jackson.databind.ObjectMapper
import org.hamcrest.Matchers
import org.junit.Test
import org.junit.runner.RunWith
import org.rizki.mufrizal.heroku.container.domain.Barang
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.MediaType
import org.springframework.test.context.TestPropertySource
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultHandlers
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
import java.math.BigDecimal

@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = [HerokuContainerApplication::class])
@AutoConfigureMockMvc
@TestPropertySource(locations = ["classpath:application.properties"])
class HerokuContainerApplicationTests {

    @Autowired
    lateinit var mockMvc: MockMvc

    @Test
    @Throws(Exception::class)
    fun getBarangsTest() {
        mockMvc
                .perform(MockMvcRequestBuilders.get("/api/barang").contentType(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isOk)
                .andExpect(MockMvcResultMatchers.jsonPath("$._embedded.barang", Matchers.hasSize<Int>(0)))
    }

    @Test
    @Throws(Exception::class)
    fun saveBarangTest() {
        val barang = Barang(namaBarang = "rinso", hargabarang = BigDecimal.valueOf(5000), jumlahBarang = 100)
        mockMvc
                .perform(MockMvcRequestBuilders.post("/api/barang").contentType(MediaType.APPLICATION_JSON).content(ObjectMapper().writeValueAsString(barang)).accept(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isCreated)
    }

}

Lalu buat sebuah file application.properties di dalam folder resources, lalu tambahkan konfigurasinya seperti berikut.

spring.profiles=heroku

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=postgres://postgresqldb:postgresqldb@postgres:5432/heroku_container_test
spring.datasource.poolName=SpringBootHikariCP
spring.datasource.maximumPoolSize=3
spring.datasource.minimumIdle=5
spring.datasource.maxLifetime=2000000
spring.datasource.connectionTimeout=30000
spring.datasource.idleTimeout=30000

spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect

spring.hateoas.use-hal-as-default-json-media-type=true

endpoints.cors.allowed-methods = POST, GET, OPTIONS, DELETE, PUT
endpoints.cors.allowed-origins = '*'
endpoints.cors.exposed-headers = accept, authorization, x-requested-with, content-type
endpoints.cors.max-age = 3600

spring.jackson.serialization.indent-output=true

spring.data.rest.base-path=/api

Maka struktur project akan berubah menjadi seperti berikut.

Screen Shot 2018-03-03 at 8.00.33 PM.png

Setup CI/CD Gitlab

Pada tahapan ini, kita akan mencoba setup CI/CD pada gitlab. Untuk membuat CI/CD pada gitlab sangatlah mudah yaitu dengan membuat sebuah file di dalam root project dengan nama .gitlab-ci.yml, lalu tambahkan source code berikut

image: docker:latest

stages:
 - build
 - publish-image
 - deploy-heroku-container

build:
 stage: build
 image: gradle:alpine
 variables:
  POSTGRES_DB: heroku_container_test
  POSTGRES_USER: postgresqldb
  POSTGRES_PASSWORD: postgresqldb
 services:
   - postgres:alpine
 script:
  - gradle clean test build
 artifacts:
  paths:
    - build/libs/*.jar

publish-image:
 stage: publish-image
 variables:
  POSTGRES_DB: heroku_container_test
  POSTGRES_USER: postgresqldb
  POSTGRES_PASSWORD: postgresqldb
  DOCKER_DRIVER: overlay2
 services:
  - docker:dind
  - postgres:alpine
 before_script:
  - docker info
 script:
 - echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin
 - apk add --no-cache openjdk8
 - java -version
 - ./gradlew clean test build docker dockerPush

deploy-heroku-container:
 stage: deploy-heroku-container
 image: rizkimufrizal/docker-node
 variables:
  DOCKER_DRIVER: overlay2
 services:
  - docker:dind
 before_script:
  - docker info
 script:
   - npm install -g heroku-cli
   - cd heroku-docker
   - echo $HEROKU_API_KEY | docker login --username=$HEROKU_USERNAME --password-stdin registry.heroku.com
   - heroku container:push web --app heroku-docker

Pada konfigurasi diatas terdapat 3 proses yang akan dijalankan oleh gitlab yaitu

  1. build yaitu proses test dan build project menjadi file jar, nantinya kita dapat mendownload file jar yang telah dibuild oleh gitlab.
  2. publish-image yaitu proses test build dan juga sekaligus proses push docker image ke docker hub.
  3. deploy-heroku-container yaitu proses deployment docker image ke heroku.

Setelah selesai, tahap selanjutnya adalah kita perlu melakukan konfigurasi Variables yang dibutuhkan. Berikut adalah variabel yang dibutuhkan untuk konfigurasi gitlab diatas.

  • DOCKER_USERNAME yaitu username docker hub
  • DOCKER_PASSWORD yaitu password docker hub
  • HEROKU_USERNAME yaitu username heroku biasanya menggunakan email
  • HEROKU_API_KEY yaity api key sebagai pengganti password heroku

Untuk melakukan konfigurasi variabel diatas, silahkan akses project di gitlab anda. Lalu pilih menu setting dan pilih menu CI / CD. Lalu expand Secret variables dan isikan konfigurasi nya seperti berikut.

Screen Shot 2018-03-03 at 8.15.20 PM.png

Untuk melihat API Key nya heroku, silahkan buka dashboard heroku, klik profile lalu pilih menu account settings, lalu scroll kebawah sehingga akan muncul menu API Key seperti berikut.

Screen Shot 2018-03-03 at 8.17.01 PM.png

Silahkan pilih menu reveal untuk melihat API Key tersebut.

Mengecek Hasil Deployment

Setelah konfigurasi diatas selesai, silahkan commit lalu push source code anda, jika berhasil maka muncul proses pipeline yang sedang berjalan pada project gitlab anda seperti berikut.

Screen Shot 2018-03-03 at 8.21.11 PM.png

Lalu silahkan pilih menu CI / CD di menu project anda, nantinya akan muncul pipeline yang sedang berjalan seperti berikut.

Screen Shot 2018-03-03 at 8.22.29 PM.png

Jika ingin lebih detail, silahkan klik menu jobs, maka akan muncul seperti berikut.

Screen Shot 2018-03-03 at 8.23.09 PM.png

Pada gambar diatas dapat dilihat bahwa jobs yang pertama yaitu build telah berhasil dikerjakan dan anda dapat melakukan download artifact jar melalui menu berikut.

Screen Shot 2018-03-03 at 8.24.29 PM.png

Berikut adalah gambar jika pipeline nya berhasil dijalankan

Screen Shot 2018-03-03 at 8.28.10 PM.png

Dan berikut adalah gambar jika semua jobs berhasil dijalankan

Screen Shot 2018-03-03 at 8.28.19 PM.png

Bagi anda yang ingin melihat source code codingan, silahkan lihat di Heroku-Container. Sekian artikel mengenai Belajar Gitlab Continuous Integration Dan Continuous Deployment dan terima kasih :).

Apache Cassandra adalah salah satu database yang banyak digunakan, terutama jika anda adalah developer API Gateway. Beberapa product API Gateway seperti axway dan kong menggunakan database Apache Cassandra untuk menyimpan seluruh konfigurasi API Gateway. Agar data lebih aman ketika terjadi sesuatu yang tidak diinginkan pada database Apache Cassandra maka dibutuhkan suatu proses replication pada database tersebut. Secara default, Apache Cassandra mendukung replication dimana replication yang ditawarkan dari Apache Cassandra adalah master - master, sehingga kita tidak perlu membuat 2 konfigurasi seperti konfigurasi master - slave pada MySQL atau mariadb. Pada artikel ini, penulis akan membahas mengenai bagaimana cara membuat replication di dalam 1 cluster apache cassandra dengan menggunakan docker swarm.

Arsitektur Cluster Apache Cassandra

Arsitektur cluster Apache Cassandra yang akan kita gunakan adalah sebagai berikut

Cassandra.png

Pada gambar diatas terdapat :

  • 6 Node Apache Cassandra, node disini adalah satu instalasi Apache Cassandra, dimana 1 node hanya dipasang pada 1 server, maka seharusnya kita menggunakan 6 server.
  • 3 Rack, rack disini untuk menentukan replication akan dilakukan secarah horizontal
  • 2 Data Center (data center dan data recovery), di dalam cassandra biasanya penulis menentukan 2 data center sehingga data center pertama adalah sebagai data center pada umumnya dan data ceter kedua sebagai data recovery.
  • 1 Cluster

Apa Itu Docker Swarm

Sebelum membahas tentang arsitektur nya, kita akan membahas terlebih dahulu mengenai docker swarm.

Docker Swarm adalah Salah satu product nya docker untuk dapat mendeploy container pada multihost.

Multihost disini adalah di banyak server. Misalnya kita mempunyai 2 server, misalnya server A dan server B. Masing - masing server akan dilakukan instalasi docker, dan masing - masing docker mempunyai 1 container yang sedang berjalan. Bagaimana caranya agar container yang terdapat pada server A dan melakukan komunikasi dengan container yang ada pada server B, sedangkan jaringan yang terdapat pada server berbeda dengan jaringan yang terdapat di dalam masing - masing container. Jawaban nya adalah dengan menggunakan docker swarm, dengan menggunakan docker swarm maka docker yang yang terdapat di dalam beberapa host dapat kita lakukan cluster sehingga seakan - akan docker tersebut terdapat pada 1 host. Dengan menggunakan docker swarm, kita bebas menetukan container tersebut ingin di deploy ke host yang diinginkan.

Arsitektur Cluster Apache Cassandra Pada Docker Swarm

Berikut adalah arsitektur yang akan digunakan.

Docker Swarm.png

Pada gambar diatas terdapat

  • 2 server yaitu dengan IP 192.168.50.2 dan 192.168.50.3
  • 3 container di masing - masing server, di dalam 1 container terdapat 1 node cassandra

Dari gambar diatas dapat kita lihat bahwa antar server, terdapat jaringan fisik misalnya LAN dan sebagainya, sedangkan di dalam docker container terdapat jaringan tersendiri, sehingga untuk menyambungkan container antar server/host maka digunakan jaringan overlay.

Jaringan Overlay adalah jaringan komputer virtual yang dibangun di atas jaringan lain.

Jaringan overlay ini nantinya akan dibuatkan oleh docker swarm sehingga kita tidak perlu melakukan konfigurasi secara manual, sehingga setiap container yang berbeda host dapat berkomunikasi pada 1 jaringan overlay.

Setup Centos 7 Dengan Vagrant

Pada artikel ini, penulis akan menggunakan vagrant untuk virtualisasi 2 server, bagi yang belum paham vagrant, silahkan simak artikel Belajar Vagrant. Silahkan buat sebuah file Vagrantfile lalu masukkan code berikut.

Vagrant.configure("2") do |config|

  config.vm.provider "virtualbox" do |v|
    v.memory = 3072
  end

  config.vm.define "master" do |master|
    master.vm.box = "centos/7"
    master.vm.hostname = 'master'
    master.vm.network "private_network", ip: "192.168.50.2"
  end

  config.vm.define "worker" do |worker|
    worker.vm.box = "centos/7"
    worker.vm.hostname = 'worker'
    worker.vm.network "private_network", ip: "192.168.50.3"
  end
end

Dari konfigurasi diatas, kita membuat 2 server dengan masing - masing ip yaitu 192.168.50.2 dan 192.168.50.3. Sistem operasi yang kita gunakan adalah centos 7. Setelah selesai, silahkan jalankan perintah berikut untuk menjalankan kedua server tersebut.

vagrant up

Setelah selesai, silahkan akses kedua vagrant tersebut dengan perintah

vagrant ssh master
vagrant ssh worker

Lakukan perintah berikut pada kedua server diatas. Silahkan login dengan user dengan perintah.

sudo -s

Kemudian jalankan perintah berikut untuk menghapus docker versi lama

yum remove docker docker-common docker-selinux docker-engine

Jalankan perintah berikut untuk instalasi config manager yum

yum install -y yum-utils device-mapper-persistent-data lvm2

Lalu tambahkan repo docker pada centos dengan perintah berikut.

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

Lalu lakukan update dengan perintah

yum update -y

Setelah selesai, lakukan instalasi docker dengan perintah

yum install -y docker-ce

Setelah selesai, silahkan jalankan docker dengan perintah

systemctl start docker

Setup Docker Swarm

Silahkan akses server master, lalu jalankan perintah berikut untuk inisialisasi docker swarm

docker swarm init --advertise-addr 192.168.50.2

IP diatas adalah IP dari server master, jika berhasil maka akan muncul output seperti berikut.

[root@master vagrant]# docker swarm init --advertise-addr 192.168.50.2
Swarm initialized: current node (hw3kzewnluvm9gmf6cz8sfunb) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-2il6rouemqho08tl2dmipd77prj293gqqn8elzgzeiu5qhmwrb-efy6r4nj9wnrvci6x7aen3ikz 192.168.50.2:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Lalu silahkan akses server worker lalu jalankan perintah join seperti berikut

docker swarm join --token SWMTKN-1-2il6rouemqho08tl2dmipd77prj293gqqn8elzgzeiu5qhmwrb-efy6r4nj9wnrvci6x7aen3ikz 192.168.50.2:2377

Perintah join tersebut berfungsi untuk mendaftarkan server/host pada docker swarm master. Setelah selesai, silahkan akses server master kembali lalu jalankan perintah berikut untuk melihat node / host / server apa saja yang telah terdaftar.

docker node ls

Dan berikut adalah outputnya.

[root@master vagrant]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
hw3kzewnluvm9gmf6cz8sfunb *   master              Ready               Active              Leader
wknzip11beucg2u4e6u46noy4     worker              Ready               Active

Setelah selesai, langkah berikut nya yaitu kita akan memberikan penamaan kepada setiap node / host / server agar nantinya kita dapat menentukan sebuah container dapat di deploy pada node / host / server yang mana. Silahkan jalankan perintah berikut untuk melakukan penamaan label pada node / host / server master dan worker.

docker node update --label-add server=master hw3kzewnluvm9gmf6cz8sfunb
docker node update --label-add server=worker wknzip11beucg2u4e6u46noy4

ID diatas dapat dilihat dengan perintah menampilkan semua node yang telah kita lakukan sebelumnya.

Membuat Compose Cassandra Untuk Docker Swarm

Langkah selanjutnya, kita akan membuat sebuah file yaitu docker-compose.yml, isinya sama seperti konfigurasi docker compose hanya saja terdapat penambahan untuk kebutuhan docker swarm, silahkan buat file docker-compose.yml di dalam server master, lalu tambahkan code berikut.

version: '3'
services:
  cassandra_dc_1:
    image: cassandra:latest
    command: bash -c 'if [ -z "$$(ls -A /var/lib/cassandra/)" ] ; then sleep 0; fi && /docker-entrypoint.sh cassandra -f'
    deploy:
      placement:
        constraints:
          - node.labels.server == master
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s
    environment:
      CASSANDRA_CLUSTER_NAME: "CassandraCluster"
      CASSANDRA_BROADCAST_ADDRESS: cassandra_dc_1
      CASSANDRA_SEEDS: cassandra_dc_1,cassandra_dr_1
      CASSANDRA_DC: DC
      CASSANDRA_RACK: RACK1
      CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
      MAX_HEAP_SIZE: 300m
      HEAP_NEWSIZE: 200m
    ports:
    - "7000"
    networks:
      default:

  cassandra_dc_2:
    image: cassandra:latest
    command: bash -c 'if [ -z "$$(ls -A /var/lib/cassandra/)" ] ; then sleep 120; fi && /docker-entrypoint.sh cassandra -f'
    deploy:
      placement:
        constraints:
          - node.labels.server == master
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s
    environment:
      CASSANDRA_CLUSTER_NAME: "CassandraCluster"
      CASSANDRA_BROADCAST_ADDRESS: cassandra_dc_2
      CASSANDRA_SEEDS: cassandra_dc_1,cassandra_dr_1
      CASSANDRA_DC: DC
      CASSANDRA_RACK: RACK2
      CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
      MAX_HEAP_SIZE: 300m
      HEAP_NEWSIZE: 200m
    depends_on:
      - cassandra_dc_1
    ports:
    - "7000"
    networks:
      default:

  cassandra_dc_3:
    image: cassandra:latest
    command: bash -c 'if [ -z "$$(ls -A /var/lib/cassandra/)" ] ; then sleep 240; fi && /docker-entrypoint.sh cassandra -f'
    deploy:
      placement:
        constraints:
          - node.labels.server == master
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s
    environment:
      CASSANDRA_CLUSTER_NAME: "CassandraCluster"
      CASSANDRA_BROADCAST_ADDRESS: cassandra_dc_3
      CASSANDRA_SEEDS: cassandra_dc_1,cassandra_dr_1
      CASSANDRA_DC: DC
      CASSANDRA_RACK: RACK3
      CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
      MAX_HEAP_SIZE: 300m
      HEAP_NEWSIZE: 200m
    depends_on:
      - cassandra_dc_2
    ports:
    - "7000"
    networks:
      default:

  cassandra_dr_1:
    image: cassandra:latest
    command: bash -c 'if [ -z "$$(ls -A /var/lib/cassandra/)" ] ; then sleep 60; fi && /docker-entrypoint.sh cassandra -f'
    deploy:
      placement:
        constraints:
          - node.labels.server == worker
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s
    environment:
      CASSANDRA_CLUSTER_NAME: "CassandraCluster"
      CASSANDRA_BROADCAST_ADDRESS: cassandra_dr_1
      CASSANDRA_SEEDS: cassandra_dr_1,cassandra_dc_1
      CASSANDRA_DC: DR
      CASSANDRA_RACK: RACK1
      CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
      MAX_HEAP_SIZE: 300m
      HEAP_NEWSIZE: 200m
    depends_on:
      - cassandra_dc_1
    ports:
    - "7000"
    networks:
      default:

  cassandra_dr_2:
    image: cassandra:latest
    command: bash -c 'if [ -z "$$(ls -A /var/lib/cassandra/)" ] ; then sleep 180; fi && /docker-entrypoint.sh cassandra -f'
    deploy:
      placement:
        constraints:
          - node.labels.server == worker
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s
    environment:
      CASSANDRA_CLUSTER_NAME: "CassandraCluster"
      CASSANDRA_BROADCAST_ADDRESS: cassandra_dr_2
      CASSANDRA_SEEDS: cassandra_dr_1,cassandra_dc_1
      CASSANDRA_DC: DR
      CASSANDRA_RACK: RACK2
      CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
      MAX_HEAP_SIZE: 300m
      HEAP_NEWSIZE: 200m
    depends_on:
      - cassandra_dr_1
    ports:
    - "7000"
    networks:
      default:

  cassandra_dr_3:
    image: cassandra:latest
    command: bash -c 'if [ -z "$$(ls -A /var/lib/cassandra/)" ] ; then sleep 300; fi && /docker-entrypoint.sh cassandra -f'
    deploy:
      placement:
        constraints:
          - node.labels.server == worker
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s
    environment:
      CASSANDRA_CLUSTER_NAME: "CassandraCluster"
      CASSANDRA_BROADCAST_ADDRESS: cassandra_dr_3
      CASSANDRA_SEEDS: cassandra_dr_1,cassandra_dc_1
      CASSANDRA_DC: DR
      CASSANDRA_RACK: RACK3
      CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
      MAX_HEAP_SIZE: 300m
      HEAP_NEWSIZE: 200m
    depends_on:
      - cassandra_dr_2
    ports:
    - "7000"
    networks:
      default:

networks:
  default:

Setelah selesai, silahkan jalankan perintah berikut untuk melakukan pull image cassandra terlebih dahulu.

docker pull cassandra

Setelah selesai, silahkan jalankan semua cassandra dengan perintah berikut

docker stack deploy --compose-file docker-compose.yml cassandra

Jika berhasil, silahkan cek service nya dengan perintah

docker service ls

Maka akan muncul output seperti berikut

ID                  NAME                       MODE                REPLICAS            IMAGE               PORTS
hx95sgod38ip        cassandra_cassandra_dc_1   replicated          1/1                 cassandra:latest    *:30020->7000/tcp
n3dbljgnptsj        cassandra_cassandra_dc_2   replicated          1/1                 cassandra:latest    *:30021->7000/tcp
tdqtwh7eaib3        cassandra_cassandra_dc_3   replicated          1/1                 cassandra:latest    *:30016->7000/tcp
l69lcdacvnnw        cassandra_cassandra_dr_1   replicated          1/1                 cassandra:latest    *:30017->7000/tcp
tgyypjfaeenf        cassandra_cassandra_dr_2   replicated          1/1                 cassandra:latest    *:30018->7000/tcp
7ao6ubi2j7e4        cassandra_cassandra_dr_3   replicated          1/1                 cassandra:latest    *:30019->7000/tcp

Silahkan cek container yang sudah jalan dengan perintah

docker ps

Maka akan muncul output seperti berikut

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES
305e963a4989        cassandra:latest    "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        7000-7001/tcp, 7199/tcp, 9042/tcp, 9160/tcp   cassandra_cassandra_dc_2.1.53t1s2c5obqwwfzgenbnj3a3f
03501ebc8870        cassandra:latest    "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        7000-7001/tcp, 7199/tcp, 9042/tcp, 9160/tcp   cassandra_cassandra_dc_1.1.qj4nikx2x9qweqrjp5h2i644a
16b1d316c721        cassandra:latest    "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        7000-7001/tcp, 7199/tcp, 9042/tcp, 9160/tcp   cassandra_cassandra_dc_3.1.f3fesq271jnpky0zw1la4vdhy

Cari NAMES yang memiliki nama cassandra_cassandra_dc_1, misalnya jika dilihat dari atas, kita menemukan nya di cassandra_cassandra_dc_1.1.qj4nikx2x9qweqrjp5h2i644a. Lalu silahkan akses container tersebut dengan perintah.

docker exec -it 03501ebc8870 /bin/bash

Lalu jalankan perintah berikut untuk mengecek cluster cassandra

nodetool status

Jika berhasil maka akan muncul output seperti berikut.

Datacenter: DC
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.0.0.67  92.35 KiB  256          31.5%             a5c66734-eb77-4c2c-9555-7b6de6d61529  RACK1
UN  10.0.0.69  75.05 KiB  256          34.2%             4a1db9a3-8a29-4da7-9fce-809ef056a35c  RACK2
UN  10.0.0.59  74.99 KiB  256          35.2%             0e12bb91-91db-4344-b532-1ca01a0e36df  RACK3
Datacenter: DR
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.0.0.61  69.93 KiB  256          33.1%             d07abb28-c4ce-4b49-b322-0aed46324adc  RACK1
UN  10.0.0.63  69.93 KiB  256          34.9%             697e25ba-0e1f-4e8b-ba65-d7fa0c8c98b1  RACK2
UN  10.0.0.65  74.98 KiB  256          31.2%             3c28cce9-7514-4a54-97ca-97a063ecdd06  RACK3

Sekian artikel mengenai Belajar Membuat Cluster Apache Cassandra Dengan Docker Swarm dan terima kasih :).

Setelah sekian lama tidak aktif untuk menulis artikel, akhirnya hari ini penulis menyempatkan waktu untuk menulis artikel baru :D. Pada artikel ini, penulis akan membahas mengenai bagaimana teknik deployment docker pada heroku. Secara default, heroku sebenarnya mendukung deploment untuk docker akan tetapi hanya sedikit artikel dan tutorial mengenai deployment pada heroku.

Mungkin ada yang bertanya, mengapa kita menggunakan heroku untuk melakukan deployment docker ? sebenarnya untuk melakukan deployment docker dapat menggunakan provider lain misalnya google cloud, akan tetapi google cloud mewajibkan kita menggunakan kartu kredit untuk menggunakan versi free :(, untuk mengatasi hal tersebut, kita dapat menggunakan heroku :D. Proses deployment ini juga penulis gunakan untuk deployment aplikasi - aplikasi microservice yang penulis bangun untuk kebutuhan tesis :), jadi dapat dipastikan bahwa deployment docker pada heroku merupakan alternative yang tepat bagi developer yang ingin mencoba teknologi docker.

Setup Project Spring Boot

Pada artikel ini, penulis akan membuat sebuah project spring boot dengan bahasa pemrograman kotlin yang nantinya akan di deploy ke container. Silahkan akses start.spring.io, lalu isi seperti berikut.

Screen Shot 2018-02-11 at 9.56.34 PM.png

Silahkan download lalu extract project tersebut dan import ke dalam IDE Intellij IDEA. Lalu silahkan buka file build.gradle dan ubah menjadi seperti berikut.

buildscript {
    ext {
        kotlinVersion = '1.2.21'
        springBootVersion = '1.5.10.RELEASE'
        gradleDockerPlugin = '0.13.0'
    }
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
        classpath("gradle.plugin.com.palantir.gradle.docker:gradle-docker:${gradleDockerPlugin}")
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'com.palantir.docker'

group = 'org.rizki.mufrizal.heroku.container'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

jar {
    baseName = 'heroku-container'
    version = '0.0.1'
}

docker {
    name "rizkimufrizal/${jar.baseName}"
    tags 'latest'
    files jar.archivePath
    buildArgs(['JAR_FILE': "${jar.archiveName}"])
}

compileKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}
compileTestKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-data-rest')
    compile('org.springframework.boot:spring-boot-starter-hateoas')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    compile('com.zaxxer:HikariCP')
    runtime('org.postgresql:postgresql')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Dapat dilihat pada bagian berikut.

jar {
    baseName = 'heroku-container'
    version = '0.0.1'
}

docker {
    name "rizkimufrizal/${jar.baseName}"
    tags 'latest'
    files jar.archivePath
    buildArgs(['JAR_FILE': "${jar.archiveName}"])
}

merupakan konfigurasi plugin docker pada gradle yang nantinya kita gunakan untuk melakukan proses pembuatan image. rizkimufrizal adalah nama dari account docker hub. Langkah selanjutnya silahkan buka file application.properties di dalam folder src/main/resources lalu ubah konfigurasinya menjadi seperti berikut.

spring.profiles=heroku

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=${DATABASE_URL}
spring.datasource.poolName=SpringBootHikariCP
spring.datasource.maximumPoolSize=3
spring.datasource.minimumIdle=5
spring.datasource.maxLifetime=2000000
spring.datasource.connectionTimeout=30000
spring.datasource.idleTimeout=30000

spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect

spring.hateoas.use-hal-as-default-json-media-type=true

endpoints.cors.allowed-methods = POST, GET, OPTIONS, DELETE, PUT
endpoints.cors.allowed-origins = '*'
endpoints.cors.exposed-headers = accept, authorization, x-requested-with, content-type
endpoints.cors.max-age = 3600

spring.jackson.serialization.indent-output=true

spring.data.rest.base-path=/api

${DATABASE_URL} merupakan variabel yang ada pada heroku, variabel ini nantinya kita gunakan untuk mengambil url database. Lalu silahkan buat sebuah package configuration di dalam package org.rizki.mufrizal.heroku.container lalu buatlah sebuah class kotlin DataSourceConfiguration untuk keperluan konfigurasi datasource, dan ubah codingan nya seperti berikut.

package org.rizki.mufrizal.heroku.container.configuration

import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import java.net.URI
import javax.sql.DataSource

/**
 *
 * @Author Rizki Mufrizal <mufrizalrizki@gmail.com>
 * @Web <https://RizkiMufrizal.github.io>
 * @Since 11 February 2018
 * @Time 10:31 PM
 * @Project Heroku-Container
 * @Package org.rizki.mufrizal.heroku.container.configuration
 * @File DataSourceConfiguration
 *
 */

@Configuration
class DataSourceConfiguration @Autowired constructor(val environment: Environment) {

    @Bean(destroyMethod = "close")
    fun dataSource(): DataSource {
        val databaseUrl = URI(environment.getRequiredProperty("spring.datasource.url"))
        val dataSourceConfig = HikariConfig()
        dataSourceConfig.driverClassName = environment.getRequiredProperty("spring.datasource.driver-class-name")
        dataSourceConfig.jdbcUrl = "jdbc:postgresql://${databaseUrl.host}:${databaseUrl.port}${databaseUrl.path}"
        dataSourceConfig.username = databaseUrl.userInfo.split(":")[0]
        dataSourceConfig.password = databaseUrl.userInfo.split(":")[1]
        dataSourceConfig.maximumPoolSize = environment.getRequiredProperty("spring.datasource.maximumPoolSize").toInt()
        dataSourceConfig.minimumIdle = environment.getRequiredProperty("spring.datasource.minimumIdle").toInt()
        dataSourceConfig.connectionTimeout = environment.getRequiredProperty("spring.datasource.connectionTimeout").toLong()
        dataSourceConfig.idleTimeout = environment.getRequiredProperty("spring.datasource.idleTimeout").toLong()
        dataSourceConfig.addDataSourceProperty("poolName", environment.getRequiredProperty("spring.datasource.poolName"))
        dataSourceConfig.addDataSourceProperty("cachePrepStmts", true)
        dataSourceConfig.addDataSourceProperty("prepStmtCacheSize", 250)
        dataSourceConfig.addDataSourceProperty("prepStmtCacheSqlLimit", 2048)
        return HikariDataSource(dataSourceConfig)
    }
}

Langkah selanjutnya silahkan buat package domain pada package org.rizki.mufrizal.heroku.container lalu buat sebuah class kotlin dengan nama Barang lalu masukkan codingan seperti berikut.

package org.rizki.mufrizal.heroku.container.domain

import org.hibernate.annotations.GenericGenerator
import java.math.BigDecimal
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.Table

/**
 *
 * @Author Rizki Mufrizal <mufrizalrizki@gmail.com>
 * @Web <https://RizkiMufrizal.github.io>
 * @Since 11 February 2018
 * @Time 10:34 PM
 * @Project Heroku-Container
 * @Package org.rizki.mufrizal.heroku.container.domain
 * @File Barang
 *
 */

@Entity
@Table(name = "tb_barang")
data class Barang(
        @Id
        @GeneratedValue(generator = "uuid2")
        @GenericGenerator(name = "uuid2", strategy = "uuid2")
        @Column(name = "id_barang", length = 36)
        val idBarang: String? = null,

        @Column(name = "nama_barang", length = 50)
        val namaBarang: String? = null,

        @Column(name = "jumlah_barang")
        val jumlahBarang: Int? = null,

        @Column(name = "harga_barang")
        val hargabarang: BigDecimal? = null
)

Setelah selesai silahkan buat package repository di dalam package org.rizki.mufrizal.heroku.container lalu buat sebuah class kotlin dengan nama BarangRepostory lalu ubah codingan menjadi seperti berikut.

package org.rizki.mufrizal.heroku.container.repository

import org.rizki.mufrizal.heroku.container.domain.Barang
import org.springframework.data.repository.PagingAndSortingRepository
import org.springframework.data.rest.core.annotation.Description
import org.springframework.data.rest.core.annotation.RepositoryRestResource

/**
 *
 * @Author Rizki Mufrizal <mufrizalrizki@gmail.com>
 * @Web <https://RizkiMufrizal.github.io>
 * @Since 11 February 2018
 * @Time 10:38 PM
 * @Project Heroku-Container
 * @Package org.rizki.mufrizal.heroku.container.repository
 * @File BarangRepostory
 *
 */

@RepositoryRestResource(collectionResourceRel = "barang", path = "barang", collectionResourceDescription = Description("API Barang"))
interface BarangRepostory : PagingAndSortingRepository<Barang, String>

Lalu ubah main class HerokuContainerApplication menjadi seperti berikut.

package org.rizki.mufrizal.heroku.container

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.hateoas.config.EnableHypermediaSupport

/**
 *
 * @Author Rizki Mufrizal <mufrizalrizki@gmail.com>
 * @Web <https://RizkiMufrizal.github.io>
 * @Since 11 February 2018
 * @Time 10:31 PM
 * @Project Heroku-Container
 * @Package org.rizki.mufrizal.heroku.container
 * @File HerokuContainerApplication
 *
 */

@SpringBootApplication
@EnableHypermediaSupport(type = [EnableHypermediaSupport.HypermediaType.HAL])
class HerokuContainerApplication

fun main(args: Array<String>) {
    SpringApplication.run(HerokuContainerApplication::class.java, *args)
}

Langkah selanjutnya silahkan buat file Dockerfile pada root project lalu tambahkan codingan berikut.

FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
RUN sh -c 'touch /app.jar'

Setelah selesai, selanjutnya kita akan membuat image berdasarkan project tersebut, silahkan jalankan command berikut untuk login ke docker hub.

docker login

Setelah selesai login, lalu jalankan perintah gradle berikut.

gradle clean build docker dockerPush -x test

Jika telah selesai, maka anda dapat melihat image anda telah tersedia di docker hub seperti berikut.

Screen Shot 2018-02-11 at 11.00.13 PM.png

Deploy Docker Container Ke Heroku

Silahkan buat sebuah folder di dalam root project dengan nama heroku-docker lalu buat sebuah file Dockerfile di dalamnya dan tambahkan konfigurasi docker seperti berikut.

FROM rizkimufrizal/heroku-container
CMD java -Xmx300m -Xss512k -Dspring.profiles.active=heroku -jar /app.jar --server.port=$PORT

Container yang ada pada heroku wajib menggunakan perintah CMD untuk menjalankan service nya, dikarenakan ini adalah project java maka penulis menggunakan command java untuk menjalankan aplikasi web tersebut. -Xmx300m -Xss512k merupakan perintah untuk membatasi penggunaan memory dikarenakan memory untuk heroku versi gratis dibatasi hanya sampai 512 MB.

Silahkan login pada web heroku di https://dashboard.heroku.com, lalu buat sebuah aplikasi dengan nama heroku-docker, untuk nama silahkan gunakan nama yang anda inginkan. Setelah selesai, silahkan masuk ke dalam detail aplikasi tersebut lalu pilih menu resources, lalu pada bagian add-ons silahkan ketika postgres maka akan muncul seperti berikut.

Screen Shot 2018-02-11 at 11.09.14 PM.png

Nantinya akan muncul seperti gambar berikut dan pilih provision

Screen Shot 2018-02-11 at 11.09.23 PM.png

Nantinya akan muncul seperti berikut.

Screen Shot 2018-02-11 at 11.09.29 PM.png

Lalu silahkan akses folder heroku-docker melalui terminal lalu jalankan perintah berikut untuk melakukan login ke heroku.

heroku login

silahkan isikan email dan password anda, lalu login ke registry docker heroku dengan perintah

heroku container:login

Kemudian untuk melakukan deploy ke heroku, silakan jalankan perintah berikut. Perintah berikut menggunakan heroku-cli, silahkan lihat cara instalasi heroku-cli di heroku-cli.

heroku container:push web --app heroku-docker

heroku-docker silahkan gunakan nama aplikasi yang anda buat di heroku. Jika berhasil maka akan muncul output seperti berikut pada terminal anda.

Screen Shot 2018-02-11 at 11.22.15 PM.png

Test REST API Spring Boot

Untuk melakukan test terhadap REST API yang telah kita bangun, silahkan jalankan command berikut untuk melakukan proses save data.

curl -X POST -H "Content-type: application/json" -d '{
  "namaBarang": "rinso",
  "jumlahBarang": 100,
  "hargabarang": 5000
}' 'https://heroku-docker.herokuapp.com/api/barang'

Lalu silahkan akses data dengan command berikut

curl -X GET https://heroku-docker.herokuapp.com/api/barang

Untuk mematikan container pada heroku, anda dapat melakukan scale down menjadi 0 dengan perintah

heroku ps:scale web=0 --app heroku-docker

Bagi anda yang ingin melihat source code codingan, silahkan lihat di Heroku-Container. Sekian artikel mengenai Belajar Deployment Docker Pada Heroku dan terima kasih :).

Pada artikel sebelumnya, penulis telah membahas mengenai bagaimana cara setup project angular 4. Pada artikel ini, penulis akan membahas mengenai bagaimana cara membuat routing pada angular 4.

Apa Itu Routing ?

Routing adalah salah satu fitur angular dimana routing ini biasanya digunakan untuk navigasi sebuah web.

Dalam melakukan development sebuah web, biasanya arsitektur yang digunakan adalah membuat sebuah web dengan full fitur angular, sehingga untuk urusan routing dan navigasi juga akan dihandle oleh angular. Untuk mengakses data ke bagian server, angular dapat menggunakan fungsi http bawaan. Pada artikel ini, kita akan mencoba membuat 2 routing, akan tetapi sebelum membuat routing, kita akan melakukan konfigurasi bootstrap terlebih dahulu.

Setup Bootstrap

Untuk menambah dependency library bootstrap silahkan jalankan perintah berikut.

npm install --save @ng-bootstrap/ng-bootstrap bootstrap@4.0.0-beta

pada artikel ini,kita akan menggunakan library ng-bootstrap. Setelah selesai melakukan instalasi dependency, selanjutnya kita akan mendaftarkan library bootstrap pada file .angular-cli.json yang berada pada root project. Silahkan buka file .angular-cli.json lalu ubah seperti berikut.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "belajar-angular4"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles.css",
        "../node_modules/bootstrap/dist/css/bootstrap.min.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "lint": [
    {
      "project": "src/tsconfig.app.json"
    },
    {
      "project": "src/tsconfig.spec.json"
    },
    {
      "project": "e2e/tsconfig.e2e.json"
    }
  ],
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "component": {}
  }
}

Setelah selesai, silahkan buka app.module.ts di dalam folder src/app, lalu tambahkan main module dari angular bootstrap seperti berikut.

import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

Lalu kita memerlukan import pada bagian annotation @NgModule, maka hasilnya akan seperti berikut.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    NgbModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Langkah selanjutnya kita akan coba membuat 2 component, dimana nanti 2 component ini yang akan kita gunakan untuk kebutuhan routing. Disini penulis akan mencoba membuat 2 component yaitu not-found dan dashboard. Untuk membuat component silahkan jalankan perintah berikut.

ng g component dashboard
ng g component not-found

Untuk melakukan setting routing, silahkan buat sebuah file di dalam folder src/app dengan nama app.routing.module.ts. Lalu silahkan masukkan codingan seperti berikut.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { NotFoundComponent } from './not-found/not-found.component';

const routes: Routes = [
    { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
    { path: 'dashboard', component: DashboardComponent },
    { path: '**', component: NotFoundComponent }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

export const RoutedComponents = [
    DashboardComponent,
    NotFoundComponent
];

Nah kemudian silahkan buka file app.module.ts, silahkan ubah codingan menjadi seperti berikut.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import { AppComponent } from './app.component';
import { AppRoutingModule, RoutedComponents } from './app.routing.module';

@NgModule({
  declarations: [
    AppComponent,
    RoutedComponents
  ],
  imports: [
    BrowserModule,
    FormsModule,
    NgbModule.forRoot(),
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Nah dapat dilihat pada source code diatas, bahwa component yang tadi nya telah diregister telah dipindahkan ke file app.routing.module.ts. Langkah selanjutnya kita harus mendeklarasikan routing nya pada file app.component.html, silahkan ubah codingan nya menjadi seperti berikut.

<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
  <a class="navbar-brand" routerLink="/dashboard">Belajar Angular 4</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarCollapse">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" routerLink="/dashboard">Home <span class="sr-only">(current)</span></a>
      </li>
    </ul>
  </div>
</nav>

<div class="container">
  <router-outlet></router-outlet>
</div>

Agar halaman nya tampil maka dibutuhkan css tambahan,silahkan buka file index.html di dalam folder src lalu silahkan ubah seperti berikut.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>BelajarAngular4</title>
  <style>
    body {
      min-height: 75rem;
      padding-top: 4.5rem;
    }
  </style>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

Jika berhasil maka outputnya akan seperti berikut.

Screen Shot 2017-08-13 at 11.24.36 AM.png

Silahkan akses dengan url http://localhost:4200/dashboard1 maka akan muncul halaman not-found seperti berikut.

Screen Shot 2017-08-13 at 11.24.42 AM.png

Sekian artikel mengenai Membuat Routing Pada Angular 4, jika ada pertanyaan atau saran silahkan isi di kolom komentar dan Terima kasih :).

Setelah melewati proses development aplikasi, maka tahap berikutnya adalah melakukan deployment aplikasi ke server yang dituju. Sebelum melakukan deployment, maka aplikasi wajib dilakukan testing terlebih dahulu. Proses seperti testing, building dan deployment sebenarnya dapat dijalankan secara otomatis dengan menggunakan tool automated deployment misalnya seperti :

Untuk melakukan integrasi dari satu proses dengan proses lain misalnya seperti testing kemudian menjalankan building lalu mendeploy, dalam hal ini sering disebut dengan Continuous Integration. Di dalam proses Continuous Integration, terdapat 2 jenis yaitu :

  1. Continuous Deployment adalah proses deployment yang dijalankan secara otomatis mulai dari testing, building hingga deployment ke server production
  2. Continuous Delivery adalah proses deployment yang dijalankan secara otomatis mulai dari testing, building, akan tetapi untuk proses deployment akan dilakukan secara manual. Biasanya yang melakukan deployment ke server production adalah manager IT yang tertinggi untuk memastikan aplikasi berjalan lancar.

Pada artikel ini, penulis akan membahas bagaimana cara melakukan integrasi gitlab (git server) dengan jenkins. Source code yang telah di push ke gitlab nantinya akan diclone di jenkins server lalu dilakukan testing, jika sukses maka source code akan di deploy ke server production, dalam artikel ini penulis akan mencoba melakukan deployment otomatis ke heroku. Berikut adalah arsitektur yang akan penulis gunakan untuk membuat Continuous Deployment dengan menggunakan docker, gitlab dan jenkins.

Flow Gitlab Jenkins.svg

Setup Docker Compose

Bagi anda yang belum mengerti bagaimana cara menggunakan docker, silahkan baca di artikel Belajar Docker dan Belajar Load Balancing Dengan HAProxy, Docker Dan Spring Boot. Silahkan buat sebuah file docker-compose.yml lalu isikan source code seperti berikut.

version: '2'

services:
  gitlab:
    container_name: docker-gitlab
    image: gitlab/gitlab-ce
    ports:
      - 80:80
    networks:
      main:
        aliases:
          - gitlab

  jenkins:
    container_name: docker-jenkins
    image: jenkins/jenkins
    ports:
      - 8080:8080
    networks:
      main:
        aliases:
          - jenkins

networks:
  main:

Konfigurasi docker compose yang kita gunakan adalah versi 2. Disini penulis membuat 2 container yaitu docker-gitlab dengan base image gitlab/gitlab-ce dan docker-jenkins dengan base image jenkins/jenkins. Masing - masing container akan melakukan expose port sehingga kita dapat melakukan akses dari luar container. Pada konfigurasi diatas kita menggunakan fungsi networks, fungsi networks ini memungkinkan kita untuk mengakses 2 way dependency antar container, secara default sebenarnya kita dapat menggunakan fungsi links, akan tetapi jika menggunakan 2 way dependency link maka akan muncul error, untuk mengatasi hal diatas maka kita gunakan networks untuk menghubungkan 2 container dengan kebutuhan 2 way dependency. Dengan menggunakan network maka container jenkins dapat mengakses http://gitlab dan container gitlab dapat mengakses http://jenkins. Jika telah selesai, kita akan melakukan menjalankan 2 container diatas dengan perintah.

docker-compose up

Jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-30 at 4.56.25 PM.png

Setup Jenkins

Ketika jenkins startup, jangan lupa untuk mencatat key security, biasanya terdapat pada baris berikut.

docker-jenkins | Jul 30, 2017 10:03:54 AM jenkins.install.SetupWizard init
docker-jenkins | INFO:
docker-jenkins |
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************
docker-jenkins |
docker-jenkins | Jenkins initial setup is required. An admin user has been created and a password generated.
docker-jenkins | Please use the following password to proceed to installation:
docker-jenkins |
docker-jenkins | a541f4e0f9f94dff807afb3273c260a1
docker-jenkins |
docker-jenkins | This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
docker-jenkins |
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************

Dapat dilihat, bahwa key security yang akan kita gunakan nantinya adalah a541f4e0f9f94dff807afb3273c260a1. Jika anda melihat output seperti berikut.

docker-jenkins | --> setting agent port for jnlp
docker-jenkins | --> setting agent port for jnlp... done
docker-jenkins | Jul 30, 2017 10:04:02 AM hudson.model.UpdateSite updateData
docker-jenkins | INFO: Obtained the latest update center data file for UpdateSource default
docker-jenkins | Jul 30, 2017 10:04:04 AM hudson.model.DownloadService$Downloadable load
docker-jenkins | INFO: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller
docker-jenkins | Jul 30, 2017 10:04:08 AM hudson.model.DownloadService$Downloadable load
docker-jenkins | INFO: Obtained the updated data file for hudson.tools.JDKInstaller
docker-jenkins | Jul 30, 2017 10:04:08 AM hudson.model.AsyncPeriodicWork$1 run
docker-jenkins | INFO: Finished Download metadata. 19,060 ms
docker-jenkins | Jul 30, 2017 10:04:11 AM hudson.model.UpdateSite updateData
docker-jenkins | INFO: Obtained the latest update center data file for UpdateSource default
docker-jenkins | Jul 30, 2017 10:04:11 AM hudson.WebAppMain$3 run
docker-jenkins | INFO: Jenkins is fully up and running

Ini menandakan bahwa jenkins adalah telah berjalan dan siap digunakan. Untuk gitlab, nantinya kita akan lakukan konfigurasi jika gitlab telah berjalan dengan sempurna, gitlab membutuhkan waktu yang lebih lama dikarenakan melakukan beberapa setup database dan lain sebagainya. Oke silahkan buka http://127.0.0.1:8080 di browser anda. Jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-30 at 5.07.19 PM.png

Lalu silahkan isikan security key yang telah anda simpan. Jika berhasil maka akan muncul halaman Customize Jenkins untuk melakukan instalasi plugin, silahkan pilih install suggested plugins, nantinya anda akan dibawa ke halaman proses instalasi plugin seperti berikut.

Screen Shot 2017-07-30 at 5.12.20 PM.png

Jika instalasi plugin telah selesai, nantinya anda akan diarahkan ke halaman pengisian data administrator, silahkan isi sesuai dengan kebutuhan anda. Berikut adalah halaman awal ketika anda memasuki dashboard jenkins.

Screen Shot 2017-07-30 at 5.19.29 PM.png

Instalasi Plugin Gitlab

Langkah selanjutnya, karena kita menggunakan gitlab, maka kita harus melakukan instalasi plugin gitlab terlebih dahulu. Berikut adalah langkah - langkahnya.

  1. Silahkan pilih menu manage jenkins yang ada disebelah kanan anda.
  2. Lalu pilih menu manage plugins.
  3. Lalu pilih tab available
  4. Kemudian silahkan cari plugin GitLab Plugin, cek list lalu pilih install without restart
  5. Kemudian akan diarahkan ke halaman proses instalasi, silahkan cek list Restart Jenkins when installation is complete and no jobs are running agar jenkins melakukan restart setelah melakukan instalasi plugin tersebut.

Setup Gradle Dan JDK

Project yang akan penulis deploy adalah project berbasis gradle, maka kita perlu melakukan setup gradle dan juga jdk nya. Berikut adalah langkah - langkahnya.

  1. Silahkan pilih menu manage jenkins yang ada disebelah kanan anda.
  2. Lalu pilih menu Global Tool Configuration
  3. Pada menu JDK, silahkan pilih Add JDK
  4. Bagian name isikan dengan JDK 8, cek list pada agreement dan jangan lupa login dengan menggunakan oracle account.
  5. Pada menu gradle, silahkan pilih Add Gradle
  6. Bagian name isikan dengan Gradle 4.0.2.
  7. Jika telah selesai silahkan klik save.

Setup Gitlab

Langkah selanjutnya kita akan melakukan setup gitlab, silahkan akses http://127.0.0.1, secara default gitlab menggunakan port 80. Ketika anda mengakses pertama kali, anda akan diminta untuk mengisi password baru, silahkan isi dengan kebutuhan anda. Jika telah selesai, anda akan dipindahkan ke halaman login seperti berikut.

Screen Shot 2017-07-30 at 5.34.08 PM.png

Silahkan login dengan menggunakan user root dan password yang telah anda register kan pada halaman sebelumnya. Jika berhasil maka akan muncul halaman seperti berikut.

Screen Shot 2017-07-30 at 5.36.17 PM.png

Setup User Jenkins Pada Gitlab

Repository yang ada di dalam gitlab biasanya akan disetting menjadi private repository, sehingga hanya user tertentu yang dapat melakukan akses terhadap repository tersebut. Agar jenkins dapat melakukan akses repository tersebut maka kita harus melakukan register untuk user jenkins. Silahkan logout terlebih dahulu, lalu lakukan registrasi melalui halaman register gitlab. Setelah selesai, silahkan logout kembali lalu login kembali menggunakan user root. Silahkan buat sebuah group dengan nama jenkins-group lalu buat sebuah project di dalam jenkins-group dengan nama Belajar-Jenkins seperti gambar berikut.

Screen Shot 2017-07-30 at 5.47.02 PM.png

Setelah selesai, silahkan pilih menu admin area (gambar kunci) seperti berikut

Screen Shot 2017-07-30 at 5.48.40 PM

Maka akan muncul halaman baru, silahkan pilih group jenkins-group dibagian kanan bawah. Nantinya anda akan masuk ke halaman management user di dalam group tersebut, silahkan pilih user jenkins dan berikan hak akses sebagai owner seperti gambar berikut.

Screen Shot 2017-07-30 at 5.50.41 PM.png

Setup Credentials Pada Jenkins

Setelah membuat user pada gitlab, sekarang kita akan mencoba membuat credentials pada jenkins, sehingga nantinya jenkins dapat melakukan clone dan deployment otomatis ke heroku. Silahkan pilih menu credentials pada menu jenkins yang berada di bawah enu My views, maka akan muncul menu system yang telah di expand, silahkan pilih menu system tersebut. Lalu pilih domain Global credentials (unrestricted), dan kemudian pilih menu Add Credentials. Untuk user jenkins silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 6.18.11 PM.png

Untuk user heroku juga silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 6.20.17 PM.png

Yang terakhir, kita harus mendaftarkan api token gitlab pada jenkins, untuk membuat api token gitlab, silahkan login kembali ke gitlab dengan menggunakan user root, lalu pilih menu setting dan pilih tab access token. Lalu isikan seperti berikut.

Screen Shot 2017-07-30 at 6.22.56 PM.png

Jika sudah, nantinya akan muncul api token gitlab, kemudian silahkan isikan seperti berikut di menu jenkins.

Screen Shot 2017-07-30 at 6.24.02 PM.png

Berikut adalah list credentials yang didaftarkan.

Screen Shot 2017-07-30 at 6.25.56 PM.png

Setup Connection Jenkins Ke Gitlab

Agar jenkins dapat mengakses source code pada gitlab maka kita harus melakukan konfigurasi connection terlebih dahulu pada jenkins. Berikut adalah tahapan nya.

  1. Pilih menu manage jenkins.
  2. Lalu pilih configure system.
  3. Lalu isikan konfigurasi berikut pada menu gitlab

Screen Shot 2017-07-30 at 6.38.07 PM.png

Pada gitlab host URL, penulis menggunakan http://gitlab, ini disebabkan kita menggunakan network dari docker, sehingga untuk memanggil connection gitlab, kita dapat menggunakan url http://gitlab. Kemudian silahkan lakukan test connection, jika error silahkan periksa konfigurasinya kembali.

Setup Project Pada Heroku

Silahkan login pada dashboard heroku, lalu silahkan buat sebuah app, bebas dengan nama apa saja, misalnya disini saya membuat projectnya dengan nama belajar-jenkins. Maka nantinya url git yang digunakan akan menjadi git@heroku.com:belajar-jenkins.git

Membuat Project Pada Jenkins

Silahkan akses kembali dashboard jenkins, silahkan pilih menu create new jobs atau new item, lalu pilih menu Freestyle Project, nama project diisikan dengan Belajar-Jenkins lalu pilih oke. Untuk bagian general silahkan pilih gitlab connection seperti berikut.

Screen Shot 2017-07-30 at 6.41.02 PM.png

Pada source code management silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 9.19.29 PM.png

Screen Shot 2017-07-30 at 9.19.34 PM.png

Pada bagian rspec silahkan isikan sintak berikut untuk origin.

+refs/heads/*:refs/remotes/origin/* +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*

dan sintak berikut untuk heroku.

+refs/heads/*:refs/remotes/heroku/* +refs/merge-requests/*/head:refs/remotes/heroku/merge-requests/*

Pada bagian build triggers silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 6.45.18 PM.png

Pada bagian build environment silahkan pilih Delete workspace before build starts. Pada bagian build silahkan pilih add build step lalu pilih invoke gradle script. Pada bagian tasks silahkan isikan dengan perintah.

clean test

berikut adalah konfigurasi untuk invoke gradle

Screen Shot 2017-07-30 at 9.24.06 PM.png

Pada bagian Post-build Actions, silahkan pilih menu add post-build action, lalu pilih publish build status to gitlab commit, kemudian pilih menu git publisher, lalu silahkan ubah konfigurasinya menjadi seperti berikut.

Screen Shot 2017-07-30 at 6.51.31 PM.png

Screen Shot 2017-07-30 at 6.51.39 PM.png

Setup WebHook Pada Gitlab

Setiap 1 project yang ada di jenkins akan mewakili 1 project atau bahkan akan mewakili 1 branch yang ada di gitlab. Silahkan login kembali pada gitlab dengan user root, lalu pilih project yang akan didaftarkan webhook nya. Pilih menu setting pada projectnya, lalu pilih menu integrations kemudian isikan konfigurasinya seperti berikut.

Screen Shot 2017-07-30 at 7.07.08 PM.png

Kemudian lakukan test webhook nya, jika berhasil maka akan muncul output seperti berikut.

Hook execution failed. Ensure the project has commits.

Pesan diatas dikarenakan repository masih kosong dan belum ada source code yang dicommit.

Setup Project Yang Akan Di Deploy

Project yang akan kita deploy ke heroku adalah project spring boot dengan menggunakan kotlin, silahkan download terlebih dahulu projectnya di Belajar-Jenkins. Lalu silahkan extract project nya. Silahkan inisialisasi git pada project tersebut dengan perintah.

git init

Lalu inisialisasi remote git nya dengan perintah

git remote add origin http://127.0.0.1/jenkins-group/Belajar-Jenkins.git

lalu lakukan add semua project dengan perintah berikut.

git add .

lalu commit seperti berikut.

git commit -m "deploy jenkins"

Melakukan Deploy

Untuk melakukan deploy, silahkan lakukan push dengan perintah.

git push origin master

Ketika dijalankan teryata menyebabkan error, ini disebabkan karena ssh key yang ada di docker belum kita daftarkan pada heroku. Sebelumnya, kita akan melakukan instalasi heroku cli terlebih dahulu pada docker, untuk dapat mengakses ssh docker, kita membutuhkan id container yang sedang aktif. Silahkan jalan perintah berikut untuk mengetahui id nya.

docker ps

maka hasilnya akan seperti berikut.

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                 PORTS                                 NAMES
a794b66cca69        jenkins/jenkins     "/bin/tini -- /usr..."   3 hours ago         Up 3 hours             0.0.0.0:8080->8080/tcp, 50000/tcp     docker-jenkins
2cb159c58b5e        gitlab/gitlab-ce    "/assets/wrapper"        3 hours ago         Up 3 hours (healthy)   22/tcp, 443/tcp, 0.0.0.0:80->80/tcp   docker-gitlab

Untuk mengakses root container silahkan jalankan perintah berikut.

docker exec -u 0 -it a794b66cca69 bash

Kemudian silahkan jalankan perintah dibawah ini berdasarkan baris nya.

wget https://cli-assets.heroku.com/heroku-cli/channels/stable/heroku-cli-linux-x64.tar.gz -O heroku.tar.gz
$ tar -xvzf heroku.tar.gz
$ mkdir -p /usr/local/lib /usr/local/bin
$ mv heroku-cli-v6.x.x-darwin-64 /usr/local/lib/heroku
$ ln -s /usr/local/lib/heroku/bin/heroku /usr/local/bin/heroku

Setelah selesai, silahkan keluar dari ssh, kemudian login lagi ke ssh dengan perintah berikut.

docker exec -i -t a794b66cca69 /bin/bas

Kemudian lakukan login heroku dengan perintah.

heroku login

silahkan lakukan login dengan username dan password anda. Tahap selanjutnya, silahkan generate ssh anda dengan perintah.

ssh-keygen -t rsa -C "mufrizalrizki@gmail.com"

Lalu setting git nya dengan perintah

git config --global user.name "RizkiMufrizal"
git config --global user.email "mufrizalrizki@gmail.com"
git config --global color.ui true

Setelah selesai, silahkan jalankan perintah berikut untuk memunculkan public key.

cat ~/.ssh/id_rsa.pub

Kemudian hasilnya public key nya silahkan didaftarkan di heroku. Setelah selesai, coba lakukan clone repository dari heroku agar mendapatkan hak akses ssh nya dengan perintah.

git clone git@heroku.com:belajar-jenkins.git

Maka akan muncul info seperti berikut.

Cloning into 'belajar-jenkins'...
The authenticity of host 'heroku.com (50.19.85.132)' can't be established.
RSA key fingerprint is SHA256:8tF0wX2WquK45aGKs/Bh1dKmBXH08vxUe0VCJJWOA/o.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'heroku.com,50.19.85.132' (RSA) to the list of known hosts.

Silahkan ketik yes, maka project akan di clone dari heroku. Nah jika telah selesai, silahkan balik lagi ke dashboard project jenkins, silahkan pilih menu build now, sehingga jenkins akan menjalankan ulang proses test build dan deploy ke heroku.

Jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-30 at 9.25.52 PM.png

Jika ingin melihat status pipeline yang ada di gitlab, silahkan login kembali dengan user root lalu akses project, pilih menu pipelines dan berikut adalah hasilnya.

Screen Shot 2017-07-30 at 9.29.58 PM.png

Untuk mengecek apakah sudah berhasil di deploy atau belum, silahkan cek di https://{nama-aplikasi-heroku}.herokuapp.com/api/barangs, karena saya menggunakan belajar-jenkins, maka saya mengakses nya di https://belajar-jenkins.herokuapp.com/api/barangs dan berikut adalah hasilnya.

Screen Shot 2017-07-30 at 9.28.27 PM.png

Jika sewaktu - waktu terjadi error pada saat testing, maka jenkins akan mengeluarkan pesan error dan deployment ke production tidak akan dilakukan, berikut output jika testing error.

Screen Shot 2017-07-30 at 9.42.22 PM.png

Dan berikut jika output yang akan ditampilkan pada gitlab.

Screen Shot 2017-07-30 at 9.42.25 PM.png

Sekian artikel mengenai Belajar Melakukan Integrasi Jenkins Dan Gitlab Pada Docker, jika ada pertanyaan atau saran silahkan isi di kolom komentar dan Terima kasih :).