Grafana – Monitor các thiết bị

Ở các bài trước ta đã setup được cơ bản server cho web hosting, gatekeeper. Vậy post này ta setup Grafana trên `gatekeeper` để monitor các server(s).

Đầu tiên là install Grafana . Cái này quite simple chỉ cần follow up guide trên website của hãng là okay.

Sau đó install Prometheus

Setup Group & User

groupadd prometheus
useradd -s /sbin/nologin --system -g prometheus prometheus

Setup các directories cần thiết

mkdir /var/lib/prometheus
for i in rules rules.d files_sd; do sudo mkdir -p /etc/prometheus/${i}; done

Directory “““/var/lib/prometheus sẽ dùng chứa data do đó suggest store trên HDD thay vì SSD chính để bảo toàn tuổi thọ cho SSD, cũng như không làm ảnh hưởng performance của SSD cho các việc khác liên quan tới OS.

Download Prometheus

mkdir -p /tmp/prometheus
cd /tmp/prometheus
curl -s https://api.github.com/repos/prometheus/prometheus/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4 | wget -qi -
tar xvf prometheus*.tar.gz

Tiếp theo là cd vào directory vừa unzip ra và move binaries về “`/usr/local/bin

sudo mv prometheus promtool /usr/local/bin/

Sau đó tạo file config ( ở directory song song với data )

sudo mv prometheus.yml /etc/prometheus/prometheus.yml

Tạo service

[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target

[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/prometheus \
    --config.file=/etc/prometheus/prometheus.yml \
    --storage.tsdb.path=/var/lib/prometheus/ \
    --web.console.templates=/etc/prometheus/consoles \
    --web.console.libraries=/etc/prometheus/console_libraries \
    --web.listen-address=0.0.0.0:9090 \
    --web.enable-lifecycle \
    --log.level=info

[Install]
WantedBy=multi-user.target

https://prometheus.io/docs/prometheus/latest/command-line/prometheus

Chú ý thay đổi path phù hợp

Enable service khi boot và start

sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter
sudo systemctl status node_exporter

Như vậy là xong. Prometheus sẽ chạy ở port 9090

Thực tế https://prometheus.jooservices.com

Ở các bài tiếp theo sẽ setup tiếp các exporters / loki

Gatekeep server with Syslog-NG

Em gatekeep được hiểu như gác cổng của toàn bộ thiết bị sau đó, do đó nó cũng phải monitoring mọi thứ. Syslog-NG là một trong những services cần thiết

  • Router sẽ bắn syslog về
  • Core Switch cũng sẽ bắn syslog về
  • Cuối cùng là các AP cũng vậy
  • …. và bất kì thiết bị nào khác cũng sẽ tương tự

Sự khác biệt giữa syslog / syslog-ng & rsyslog

https://serverfault.com/questions/692309/what-is-the-difference-between-syslog-rsyslog-and-syslog-ng

Đầu tiên là phải enable UDP port 514 để nhận syslog từ ngoài vào. Mấy món này sẽ easily hơn với Webmin UI.

Vậy là SyslogNG đã ready. Tuy nhiên cần lưu ý kiểm port 514 UDP đã được enable ( most of case thì Webmin sẽ install luôn firewall và tất nhiên port này không được enabled )

Tuy nhiên log là thứ … write liên tục. Do đó giảm thiểu cái nào được ra khỏi SSD thì tốt bấy nhiêu.

  • Log sources : Các nguồn cung cấp logs . Ở đây mình đã thêm s_net
  • Log destination : Store logs vào đâu
  • Log filter : Lọc các logs
  • Và cuối cùng là kết hợp mọi thứ để tạo log : Log từ source nào – Filter thế nào & Save vào đâu

HAProxy server

Ở bài trước mình đã có 1 con server selfhosted dành cho web server. Tuy nhiên homelab này mình sẽ có nhiều server do đó sẽ cần 1 em đóng vai trò gateway ( cũng như monitoring )

  • i5-8700
  • 32GB RAM – 2666Mhz
  • SSD NVme Gen3 x4 : 256GB
  • HDD Sata : 1TB

Sau khi setup xong Ubuntu server như ở bài trước ( không cần Virtualmin ) thì ở server này sẽ cần HAProxy

HAProxy is a free, very fast and reliable reverse-proxy offering high availabilityload balancing, and proxying for TCP and HTTP-based applications.

Mục đích sử dụng HAProxy để forward request về các servers / services cần thiết. Ví dụ

  • https://selfhosted.jooservices.com/ sẽ được forward về Virtualmin ( port 10000 ) ở server selfhosted ta vừa installed trước.
  • https://jooservices.com sẽ forward về port 443 ( SSL ) của Virtualmin và load website

Cấu hình HAProxy

# HAProxy Stats
listen  stats
        bind *:1936
        log global

        maxconn 10

        stats enable
        stats show-node

        http-request use-service prometheus-exporter if { path /metrics }
        stats uri  /stats

Bật HAProxy stats để quản lý

Tạm gác qua Sentry & Grafana ta sẽ nói sau. Thì ta có FE SSL cho các services

  • cnmatrix.jooservices.com : Trỏ về Core switch port 443
  • gatekeeper.jooservices.com : Trỏ về con server này với Webmin ( không phải Virtualmin ) trên port 10000
  • jooservices.com && xcrawler.net cùng nằm trên selfhosted server với port 443

Và sau đó là config BE để forward về server / port tương tứng với từng FE

global
	log /dev/log	local0
	log /dev/log	local1 notice
	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin
	stats timeout 30s
	user haproxy
	group haproxy
	daemon

	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
	log	global
	mode	http
	option	httplog
	option	dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
	errorfile 400 /etc/haproxy/errors/400.http
	errorfile 403 /etc/haproxy/errors/403.http
	errorfile 408 /etc/haproxy/errors/408.http
	errorfile 500 /etc/haproxy/errors/500.http
	errorfile 502 /etc/haproxy/errors/502.http
	errorfile 503 /etc/haproxy/errors/503.http
	errorfile 504 /etc/haproxy/errors/504.http

    # Newly added timeouts
    timeout http-request 10s
    timeout http-keep-alive 2s
    timeout queue 5s
    timeout tunnel 2m
    timeout client-fin 1s
    timeout server-fin 1s

# Caching
cache hosting
    total-max-size 4095   # MB
    max-object-size 10000 # bytes
    max-age 3600            # seconds

cache general
    total-max-size 4095   # MB
    max-object-size 10000 # bytes
    max-age 3600            # seconds

# HAProxy Stats
listen  stats
        bind *:1936
        log global

        maxconn 10

        stats enable
        stats show-node

        http-request use-service prometheus-exporter if { path /metrics }
        stats uri  /stats

userlist basic_auth_logins
        user <username> insecure-password <password>


# Frontend HTTP
frontend http
    bind :80
    mode http
    compression algo gzip

    acl acl_grafana hdr(host) -i grafana.jooservices.com
    acl acl_sentry hdr(host) -i sentry.jooservices.com

    use_backend be_grafana if acl_grafana
    #default_backend be_http

backend be_grafana
        mode http
        balance roundrobin
        server gatekeeper 192.168.1.5:3000 check

backend be_sentry
        mode http
        balance roundrobin
        server gitlab 192.168.1.5:9000 check

## Frontend SSL
frontend ssl
        bind :443
        mode tcp
        option tcplog

        # Wait for a client hello for at most 5 seconds
        tcp-request inspect-delay 5s
        tcp-request content accept if { req_ssl_hello_type 1 }

        ## 192.168.1.2
        use_backend be_ssl_cnmatrix if { req_ssl_sni -i cnmatrix.jooservices.com }

        ## 192.168.1.3
        # use_backend be_ssl_unifi if { req_ssl_sni -i unifi.jooservices.com }

	## 192.168.1.5
	use_backend be_ssl_webmin_gatekeeper if { req_ssl_sni -m end gatekeeper.jooservices.com }

        ## 192.168.1.6
        use_backend be_ssl_selfhosted if { req_ssl_sni -i jooservices.com }
	use_backend be_ssl_virtualmin_selfhosted if { req_ssl_sni -m end selfhosted.jooservices.com }
	#### XCrawler
        use_backend be_ssl_selfhosted if { req_ssl_sni -i xcrawler.net }
        use_backend be_ssl_selfhosted if { req_ssl_sni -m end .xcrawler.net }

        ## 192.168.1.8
        use_backend be_ssl_nas if { req_ssl_sni -i nas.jooservices.com }

        ## 192.168.1.10
        #use_backend be_ssl_esxi if { req_ssl_sni -i esxi.jooservices.com }

        ## 192.168.1.24
        #use_backend be_ssl_gitlab if { req_ssl_sni -i gitlab.jooservices.com }

        ## Virtualmin / Webmin
        #use_backend be_ssl_hosting_virtualmin if { req_ssl_sni -i virtualmin.jooservices.com }
        #use_backend be_ssl_gatekeeper_webmin if { req_ssl_sni -i gatekeeper.jooservices.com }
        #use_backend be_ssl_smb_webmin if { req_ssl_sni -i smb.jooservices.com }

        ## Hosting
        ## 192.168.1.20
        #use_backend be_ssl_hosting if { req_ssl_sni -i jooservices.com }       

        ## XCrawler
        ## 192.168.1.30
        #use_backend be_ssl_xcrawler if { req_ssl_sni -i xcrawler.net }
        #use_backend be_ssl_xcrawler if { req_ssl_sni -m end .xcrawler.net }

        #default_backend be_ssl_hosting

## Backend SSL
### CnMatrix
backend be_ssl_cnmatrix
        mode tcp
        balance roundrobin
        server cnmatrix 192.168.1.2:443 check

### Gatekeeper
backend be_ssl_webmin_gatekeeper
        mode tcp
        balance roundrobin
        server selfhosted 192.168.1.5:10000 check

### NAS
backend be_ssl_nas
        mode tcp
        balance roundrobin
        server nas 192.168.1.8:443 check

## Selfhosted
backend be_ssl_selfhosted
        mode tcp
        balance roundrobin
        server selfhosted 192.168.1.6:443 check
backend be_ssl_virtualmin_selfhosted
        mode tcp
        balance roundrobin
        server selfhosted 192.168.1.6:10000 check

[Part 1] Ubuntu server for web hosting

Bài đầu tiên trong series là Setup 1 con Ubuntu server.

Mình có 1 con HP EliteDesk 800 G2 với

  • i5-6400
  • 32GB RAM – 2666Mhz
  • SSD NVme Gen3 x4 : 256GB
  • SSD Sata : 120GB

OS

Read more: [Part 1] Ubuntu server for web hosting

Oki sau khi installed OS xong. Ta có 1 vài thứ cơ bản

Update /etc/sudoers và thêm vào cuối file

$USER ALL=(ALL) NOPASSWD:ALL
  • Update LVM 100% Storage
  • Update NTP & Timezone
curl -L https://raw.githubusercontent.com/jooservices/bash/main/services/vm | bash

Oki để hosting ta sẽ dùng Virtualmin.

Virtualmin is the leading and most sophisticated web hosting control panel designed for Linux systems.

Virtualmin

By default Virtualmin không có đủ hết các PHP versions do đó ta sẽ install thêm

curl -L https://raw.githubusercontent.com/jooservices/bash/main/services/multi-php.sh | bash

Cơ bản 1 con web hosting như vậy là đủ. Một số packages bổ sung tùy chọn

By default Webmin / Virtualmin sẽ enable firewall. Do đó nếu cần access từ ngoài vào với các 3rd party services / ports thì cần update rules

Live site : https://selfhosted.jooservices.com

Để setup domain / Cloudflare trỏ về Virtualmin ta sẽ dùng HAProxy ở bài sau

My HAProxy configuration

global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
    log global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000

    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

    # Newly added timeouts
    timeout http-request 10s
    timeout http-keep-alive 2s
    timeout queue 5s
    timeout tunnel 2m
    timeout client-fin 1s
    timeout server-fin 1s

# Caching
cache hosting
    total-max-size 4095   # MB
    max-object-size 10000 # bytes
    max-age 3600            # seconds

cache general
    total-max-size 4095   # MB
    max-object-size 10000 # bytes
    max-age 3600            # seconds

# HAProxy Stats
listen  stats
        bind *:1936
        log global

        maxconn 10

        stats enable
        stats show-node

        http-request use-service prometheus-exporter if { path /metrics }
        stats uri  /stats

userlist basic_auth_logins
        user <your_username_here> insecure-password <your_password_here>

# Frontend HTTP
frontend http
    bind :80
    mode http
    compression algo gzip

    acl acl_sentry hdr(host) -i sentry.jooservices.com
    acl acl_grafana hdr(host) -i grafana.jooservices.com
    
    use_backend be_sentry if acl_sentry
    use_backend be_grafana if acl_grafana
    #default_backend be_http

backend be_sentry
        mode http
        balance roundrobin
        server gitlab 192.168.1.12:9000 check

backend be_grafana
        mode http
        balance roundrobin
        server gitlab 192.168.1.12:3000 check


## Frontend SSL
frontend ssl
        bind :443
        mode tcp
        option tcplog

        # Wait for a client hello for at most 5 seconds
        tcp-request inspect-delay 5s
        tcp-request content accept if { req_ssl_hello_type 1 }

        ## 192.168.1.2
        use_backend be_ssl_cnmatrix if { req_ssl_sni -i cnmatrix.jooservices.com }

        ## 192.168.1.3
        # use_backend be_ssl_unifi if { req_ssl_sni -i unifi.jooservices.com }

        ## 192.168.1.8
        use_backend be_ssl_nas if { req_ssl_sni -i nas.jooservices.com }

        ## 192.168.1.10
        use_backend be_ssl_esxi if { req_ssl_sni -i esxi.jooservices.com }

        ## 192.168.1.24
        use_backend be_ssl_gitlab if { req_ssl_sni -i gitlab.jooservices.com }
        
        ## Virtualmin / Webmin
        use_backend be_ssl_hosting_virtualmin if { req_ssl_sni -i virtualmin.jooservices.com }
        use_backend be_ssl_gatekeeper_webmin if { req_ssl_sni -i gatekeeper.jooservices.com }
        use_backend be_ssl_smb_webmin if { req_ssl_sni -i smb.jooservices.com }
        
        ## Hosting
        ## 192.168.1.20
        use_backend be_ssl_hosting if { req_ssl_sni -i jooservices.com } 
        use_backend be_ssl_hosting if { req_ssl_sni -m end tpbeauty.art baristaschool.vn .baristaschool.vn phongcachxanh.vn }
        #use_backend be_ssl_develop if { req_ssl_sni -m end coffeeschool.vn .coffeeschool.vn }

        ## XCrawler
        ## 192.168.1.30
        use_backend be_ssl_xcrawler if { req_ssl_sni -i xcrawler.net }
        use_backend be_ssl_xcrawler if { req_ssl_sni -m end .xcrawler.net }

        default_backend be_ssl_hosting


### CnMatrix
backend be_ssl_cnmatrix
        mode tcp
        balance roundrobin
        server cnmatrix 192.168.1.2:443 check

### Unifi
#backend be_ssl_unifi
#        mode tcp
#        balance roundrobin
#        server gatekeeper 192.168.1.3:443 check

# BEGIN Monitor
# END Monitor

# NAS
backend be_ssl_nas
        mode tcp
        balance roundrobin
        server smb 192.168.1.8:443 check

### BEGIN ESXi
        #### Gatekeeper
        backend be_ssl_gatekeeper_webmin
                mode tcp
                balance roundrobin
                server gatekeeper 192.168.1.9:10000 check

        #### ESXi
        backend be_ssl_esxi
                mode tcp
                balance roundrobin
                server esxi 192.168.1.10:443 check

        #### BEGIN Hosting
        backend be_ssl_hosting_virtualmin
                mode tcp
                balance roundrobin
                server hosting 192.168.1.20:10000 check

        backend be_ssl_hosting
                mode tcp
                balance roundrobin
                server hosting 192.168.1.20:443 check

        #backend be_ssl_develop
        #        mode tcp
        #        balance roundrobin
        #        server develop 192.168.1.12:443 check

        backend be_ssl_smb_webmin
                mode tcp
                balance roundrobin
                server smb 192.168.1.14:10000 check

        backend be_ssl_gitlab
                mode tcp
                balance roundrobin
                server hosting 192.168.1.24:443 check
          
# END Hosting


# BEGIN XCrawler
backend be_ssl_xcrawler
        mode tcp
        balance roundrobin
        server xcrawler 192.168.1.13:443 check
# END XCrawler

Bash script setup basically VM

No password required with sudo

joos ALL=(ALL) NOPASSWD:ALL

Extend LVM

sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv

Setup timezone

sudo timedatectl set-timezone Asia/Ho_Chi_Minh
sudo timedatectl set-ntp on

Docker

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker

Setup PHP

#!/bin/bash

echo 'Install requirements'

sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update && sudo apt upgrade -y

phpVersions=('8.3')
phpExtensions=('dev' 'cli' 'mbstring' 'curl' 'intl' 'mbstring' 'xml' 'xmlrpc' 'xsl' 'yaml' 'zip' 'imagick' 'gd' 'opcache' 'memcache' 'memcached' 'mysql' 'sqlite3' 'ldap' 'bcmath' 'fpm')
phpPecls=('mongodb' 'redis' 'pcov' 'apcu')

for phpVersion in "${phpVersions[@]}"
do
  echo "Install PHP ${phpVersion} extensions"
  extensions=$(printf "php${phpVersion}-%s " "${phpExtensions[@]}")
  sudo apt install -y $extensions

  echo "Install PHP ${phpVersion} pecl extensions"
  for phpPecl in "${phpPecls[@]}"
  do
    sudo pecl -d php_suffix="${phpVersion}" install "${phpPecl}"
    sudo pecl uninstall -r "${phpPecl}"    
    sudo bash -c 'echo "extension='${phpPecl}'.so" >> /etc/php/'${phpVersion}'/cli/php.ini'
    sudo bash -c 'echo "extension='${phpPecl}'.so" >> /etc/php/'${phpVersion}'/fpm/php.ini'
  done
done

Github action – Reusable

# https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions
name: XCrawler - Build & Tests

# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
on:
  # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
  pull_request:
    branches: [ develop ]
    types: [ opened, synchronize ]

jobs:

  sonar_cloud:
    name: SonarCloud
    uses: ./.github/workflows/sonar_cloud.yml
    secrets: inherit

  security_check:
    name: Security check
    uses: ./.github/workflows/security_check.yml
    secrets: inherit

  code_standards:
    name: Code standards check
    needs: [ sonar_cloud, security_check ]
    strategy:
      matrix:
        lint: [ phpstan, phpmd, phpcs ]
    uses: ./.github/workflows/code_standards.yml
    with:
      lint: ${{ matrix.lint }}
    secrets: inherit

  tests:
    name: Execute UnitTest
    needs: [ code_standards ]
    strategy:
      matrix:
        test: [ Client, JAV, Flickr, Core ]
    uses: ./.github/workflows/unittest.yml
    with:
      test: ${{ matrix.test }}
    secrets: inherit

  finalizing_build:
    name: "All Parallel Tests passed"
    needs: [ tests ]
    uses: ./.github/workflows/codecov.yml
    secrets: inherit
Continue reading Github action – Reusable

Laravel – Code structure with UnitTest

Giả sử ta có một code structure như sau

Controller

  • Gọi Services để thực thi và respond

Services

  • Gọi Repository khi cần tương tác database
  • Trigger Event
  • Gọi các Services khác hoặc các code logic khác.

Vậy UnitTest sẽ cần những gì. Trong quan điểm mình là đi từ thấp nhất lên cao nhất

  • Repositories : Đảm bảo database được thực thi, assert các data như mong đợi.
    • Assert events đã dispatched.
    • Events : Dispatch events và assert data như mong đợi
  • Services
    • Nếu services có các events ẢNH HƯỞNG TRỰC TIẾP đến kết quả thì mình sẽ không fake event mà để event thực thi và assert kết quả
    • Nếu các events đó dùng cho 3rd thì mình assert để make sure events dispatched như mong đợi

Tất nhiên nếu service đó thuần túy gọi tới 3rd party thì mình chỉ việc mock và test respond từ 3rd party thôi.

Và sau cùng là assert controller trả về data như mong đợi