บันทึกการเดินทาง ญาจาง (Nha Trang, Vietnam) 2024

Nha Trang, Vietnam 2024
Nha Trang, Vietnam 2024

พอดีมีโอกาส ได้ไปเที่ยวญาจาง ด้วยความที่เห็นรีวิว กันเยอะมากจาก YouTuber .. ว่าเป็นเมืองที่สวยงาม Seafood ราคาถูก ค่าที่พักถูก ค่าครองชีพถูก

จากการที่ไปเอง เมืองเค้าเป็นระเบียบ สวยงามดีมากครับ .. เหมาะสำหรับคนมาพักผ่อน และทำกิจกรรมต่างๆ คนที่ชอบทะเล .. ที่นิยมกัน ก็จะไปสวนสนุก ที่เกาะ VinPearl แล้วก็มีที่เที่ยวที่น่าสนใจ ทางศาสนาและวัฒนธรรมโบราณ อื่นๆ

ตอนเย็น weekend จะมีนักท่องเที่ยว ทั้งชาวเวียดนามเอง เกาหลี รัสเซีย ฝรั่งอื่นๆ เยอะมากครับ (เด็กๆ เยอะมาก)มาเล่นน้ำกัน สนุกสนานดี คนเยอะมาก ในแต่ละจุด ผมว่ามีกว่า 10000 คนได้ หาดเค้าจะยาวมาก .. อีกฝั่งถนนก็จะเป็นที่พัก โรงแรม ร้านรวงต่างๆ ..

ชายหาดจะมีแม่ค้าหาบของปิ้งย่างขาย แต่ตอนผมไป ไม่เจอล็อบสเตอร์ แบบที่เค้ารีวิวกันนะ จะมีขายแต่ในร้านอาหาร ราคาก็ไม่ได้ถูกครับ เมืองท่องเที่ยว ราคาก็จะประมาณนี้ แต่ถ้าเข้าไปในย่าน ที่อยู่อาศัยของคนพื้นที่ ก็จะถูกลงเยอะ ..

การเดินทางที่นี่ จะสะดวกมากครับ จากสนามบินมา ก็นั่ง Airport (City) Bus มาได้ ราคา 65000VND ในเมืองก็เรียกใช้งาน grab ได้ .. รถไม่ติดมาก ไหลๆ สบายๆ มอไซค์ค่อนข้างเยอะ ตามสไตล์เวียดนาม

ด้าน Internet ที่นี่ก็จะเป็น 4G/4G+ นะครับ แต่บางที่ก็ยังเป็น 2G/3G อยู่ .. ตามโรงแรมที่พัก ก็จะมี Free WiFi ให้ใช้งาน แต่จะไม่เร็วเหมือนที่ไทยนะครับ แต่ก็พอใช้งานทั่วไปได้ .. ผมเองด้วยความที่ต้องใช้ Internet ตลอด ก็เลยเปิดใช้งาน Sim2Fly มาเลยจากไทยนะครับ เน้นชัวร์ ลงเครื่อง ก็ใช้งาน Internet ได้เลย ไม่ต้องลุ้น ว่าถ้ามาซื้อ SIM ที่นี่ใช้ จะใช้ค่ายไหนดี +___+

ด้านมืด ก็มีบ้างเรื่องการโกง การหลอกลวง ก็คือจะมีพวกขี่มอไซค์มาชวนไปอย่างว่านะครับ (ปั่มปั้ม) ก็อย่าหลงไปนะครับ .. อย่าเดินคนเดียว อย่าอยู่ในที่เปลี่ยว .. พยายามหาเพื่อนผู้หญิง เดินไปด้วย พวกนี้จะไม่กล้ามารบกวนครับ .. ถ้าไปชายล้วน ยังไงก็ต้องเจอ ไม่ว่าจะเป็นประเทศไทย ลาว จีน ก็มีหมดนะครับ ก็ต้อง Say “No” อย่างเดียวครับ .. แต่คนส่วนใหญ่ที่นี่จะดีครับ ช่วยเหลือนักท่องเที่ยวดีมาก

สำหรับผมเดินทางในเวียดนาม มาหลายปีแล้ว หลายแบบ หลายเมือง .. คิดว่าเวียดนามเค้าเจริญเร็วมาก .. เป็นเมืองแห่งความหวัง ของ Asia เมืองนึงจริงๆ .. ลูกเด็กเล็กแดงเค้าเยอะมาก คนหนุ่มสาว วัยแรงงานเยอะมาก .. ต่อไปไม่นานจะเป็นเมืองพัฒนา แบบสิงคโปร์ (SG) ได้แน่ๆ ครับ ตอนนี้ ก็ใกล้เคียงแล้ว ..

Facebook Comments Box

ครบรอบ 1 เดือน ในการกลับมาทำงานอยู่บ้าน

1 month at home

ครบรอบ 1 เดือน ในการย้ายถิ่นฐานจาก กทม. ที่อยู่เป็นหลักมาตั้งแต่สมัยเรียน เพื่อกลับมา WFH ที่บ้าน (จันทบุรี) เลยเขียน blog ไว้สักหน่อยครับ บันทึกความทรงจำ มะก่อนผมก็ชอบเขียน diary ..

เห็นมี ดราม่า ถกเถียงกัน ว่าเข้า office กับ WFH แบบไหนดีกว่ากัน .. ส่วนตัวคิดว่า แล้วแต่ลักษณะงานที่ทำด้วยครับ บางงานก็ต้อง on site 100% .. บางงาน ถ้ามันไม่จำเป็นต้องเข้า office การให้ WFH ก็ดีกว่าในทุกด้านครับ ..
ทั้งนี้ทั้งนั้น ขึ้นอยู่กับตัวบุคคลด้วยครับ ว่ามีความรับผิดชอบ มีความกระตือรือร้น ในการทำงานขนาดไหน tools ต่างๆ เกี่ยวกับ Project Management, Interaction ก็เป็นตัวช่วยทางนึงครับ ..

การกลับมาอยู่บ้าน ก็มีแต่ข้อดีซะเป็นส่วนใหญ่ ข้อเสียก็มีบ้างนิดหน่อย เช่นการเดินทาง ต้องมีรถส่วนตัว ไม่งั้นจะไปไหนมาไหนลำบาก ..
บ้านผมโชคดีหน่อย ที่มีสัญญาณมือถือ เข้าถึงทุกค่าย ทำให้สามารถเลือกใช้ Net SIM ในการทำงานได้ ..
อยู่ในรัศมี ที่สามารถสั่ง 7Deli มาส่งได้ ทำให้สะดวกมาก ในการสั่งกาแฟ จาก All Cafe เพราะถ้าออกไปซื้อเอง คงไม่คุ้มค่าน้ำมันรถ (ผมไม่มีมอไซค์ ปั่นจักรยานก็ไม่ไหวไกลไป รถ Jeep ก็ไม่ไหว ค่าน้ำมันแพงเกิน)

อยู่บ้านวันหยุดได้ทำพวก hobby ที่ชอบ ที่อยากทำได้ เพราะมีพื้นที่และอยู่ห่างไกลจากบ้านอื่น ทำให้เสียงไม่ไปรบกวนใคร ใช้สว่าน ใช้ค้อนได้ สบายใจ เหมือนเรามีห้องทดลอง มี Workshop ส่วนตัว 🙂

Facebook Comments Box

Life in 2024

สวัสดีครับทุกท่าน ไม่ได้ update blog มานานมากครับ ตั้งแต่ปี 2023 เกือบจะครบปี เพราะว่าช่วงนั้น จะวุ่นๆ มากด้วย ..

ตอนนี้ ตัดสินใจ คืนคอนโด ที่เช่า มาหลายปี กลับมา WFH อยู่ต่างจังหวัดครับ .. จะได้ลดรายจ่าย ลงไปได้บ้าง จะได้เอาไปโปะบ้าน-คอนโด ให้หมดไวๆ เพราะดอกเบี้ย ช่วงที่ผ่านมาแพงเหลือเกิน (6.xx) ..

อยากกลับมาดูแลพ่อแม่ด้วยครับ เค้าอายุมากแล้ว .. อยากสร้างบ้าน ที่อยู่สบายๆ เหมาะสำหรับคนสูงวัย สักหลัง แนวๆ แบบบ้านญี่ปุ่น (มูจิ) จะได้สะดวก ในการใช้ชีวิตอยู่อาศัย .. กำลังหาแบบ หรือคนออกแบบให้อยู่ครับ ใครมีก็ช่วยแนะนำมาได้ เอางบไม่สูงมาก เพราะแถวนี้ ค่าช่าง ค่าอะไร ราคาค่อนข้างสูง ..
อยู่บ้าน ก็พอมีเวลา ดูแลบ้าน ด้วยครับ ไม่งั้นไม่มีคนอยู่ จะโทรมเร็วมาก .. ได้ปลูกต้นไม้ ได้ทำอะไรที่ชอบ เพราะมีพื้นที่

แต่ก็ไม่รู้ว่าเค้าจะเรียกเข้า office เมื่อไรเหมือนกัน อาจจะต้องไปกลับๆ แบบเพื่อนๆ บางคน บางบริษัท ถ้าแบบนั้นก็ไม่ไหว เหนื่อยกว่าอยู่ กทม. อีก .. บางคนบินไปกลับตลอด กลายเป็นค่าใช้จ่ายสูงกว่าเดิม แต่ก็ยังดีที่บินได้ ไม่เหนื่อยเท่านั่งรถไปกลับ ..

ช่วงนี้ น่าจะพอมีเวลามากขึ้น เพราะไม่ต้องเสียเวลาเดินทางเยอะๆ ไม่ต้องเหนื่อยเดินทาง แบบตอนอยู่ กทม. ก็เลยคิดว่า จะมา update blog เรื่องราวต่างๆ บ่อยๆ หน่อย .. เพราะคิดว่าเรื่องบางอย่างที่ทำอยู่ อาจจะเป็นความรู้ เป็นประโยชน์ ให้คนอื่น ได้บ้าง .. เพราะเจอปัญหาใหม่ๆ ตลอดเวลา กับงานสาย tech ที่ทำอยู่ และพวก hobby ที่ชอบ .. จะทำเป็น YouTube ก็คงไม่ไหว ไม่มีเวลาขนาดนั้น ..

ถ้าใครมีงานพวกเป็นวิทยากร สอนพวก IoT, Robotics, AI, Software Deployment หรืออะไรแนวๆ นี้ ก็ติดต่อมาได้ครับ ถ้าอยู่ใกล้ๆ มารับผมก็พอ เพราะผมไม่สะดวกเดินทางเอง (ไม่มีรถ) .. ไม่คิดเงินครับ (เสาร์-อาทิตย์ วันธรรมดาผมทำงาน) .. ได้แบ่งปันความรู้ ได้แลกเปลี่ยนความรู้ กับคนอื่นบ้างก็ดี .. ไม่งั้นบางทีอยู่บ้านเฉยๆ ก็เบื่อได้เหมือนกัน ..

ปล. เศรษฐกิจแบบนี้ ประหยัดไว้ดีสุด .. หารายได้เพิ่มยากมาก .. แถมปีนี้ น่าจะมีการ layoff กันเยอะทั่วโลก ..

Facebook Comments Box

How to Install Magento 2.4.6 on Ubuntu 22.04

Magento
Install Diagram

สวัสดีครับ วันนี้ จะมาพูดถึงการ Install Magento 2 (Adobe Commerce) นะครับ
เป็น eCommerce Software ตัวนึง ที่น่าใช้มากๆ มาพร้อมกับ feature ที่ครบครัน ..

รายละเอียดเพิ่มเติม https://business.adobe.com/products/magento/magento-commerce.html

รายละเอียดของ System ประมาณนี้ครับ

- OS: Ubuntu 22.04
- Magento: 2.4.6-p2 (Open Source)
- Apache: 2.4.x
- PHP: 8.1.2
- Composer: 2.2.6
- MySQL: 8.0.34
- Elasticsearch: 7.17.13

มาเริ่มกันเลย ..

Step 1: Update Operating System

# apt update && apt upgrade -y

Step 2: Install Apache Web Server

# apt install apache2

Step 3: Install PHP and PHP extensions

# apt install php php-common libapache2-mod-php php-cli php-fpm php-mysql php-json php-opcache php-gmp php-curl php-intl php-mbstring php-xmlrpc php-gd php-xml php-zip php-soap php-bcmath php-apcu

Modify php.ini file (/etc/php/8.1/cli/php.ini)

memory_limit = 1GB
upload_max_filesize = 256M
zlib.output_compression = On
max_execution_time = 600
max_input_time = 900
date.timezone = Asia/Bangkok

Step 4: Install the MySQL server

# apt install mysql-server
# mysql_secure_installation

Step 5: Create a Magento Database

# mysql -u root -p
mysql> CREATE DATABASE magento;
mysql> CREATE USER 'magento'@'localhost' IDENTIFIED BY 'Str0ngPa$$w0rd';
mysql> GRANT ALL PRIVILEGES ON magento.* TO 'magento'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> EXIT;

Step 6. Install Elasticsearch

# curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
# echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list

# apt update && apt install elasticsearch

# systemctl start elasticsearch
# systemctl enable elasticsearch

Verify Elasticsearch

curl -X GET "localhost:9200"

{
"name" : "magento-01",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "-Or5raP6T5uEG3bUG1JYHw",
"version" : {
"number" : "7.17.13",
"build_flavor" : "default",
"build_type" : "deb",
"build_hash" : "2b211dbb8bfdecaf7f5b44d356bdfe54b1050c13",
"build_date" : "2023-08-31T17:33:19.958690787Z",
"build_snapshot" : false,
"lucene_version" : "8.11.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}

Step 7: Install Composer

# apt install composer

Step 8: Install Magento

Goto Magento Marketplace https://marketplace.magento.com/

Get Access Keys
My profile > Marketplace > My products > Access Keys

# composer global config http-basic.repo.magento.com Your-Public-Key Your-Private-Key

# composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition=2.4.6-p2 /var/www/magento
# cd /var/www/magento

# bin/magento setup:install \
--base-url=http://your-domain.com \
--db-host=localhost \
--db-name=magento \
--db-user=magento \
--db-password=Str0ngPa$$w0rd \
--admin-firstname=Admin \
--admin-lastname=User \
--admin-email=admin@your-domain.com \
--admin-user=admin \
--admin-password=admin123 \
--language=en_US \
--currency=USD \
--timezone=Asia/Bangkok \
--use-rewrites=1

# chown -R www-data: /var/www/magento

Step 9: Setup Cron jobs

# sudo -u www-data bin/magento cron:install

Step 10: Configure Apache for Magento

Create /etc/apache2/sites-available/magento.conf

<VirtualHost *:80>
ServerAdmin admin@your_domain.com
DocumentRoot /var/www/magento/pub
ServerName your_domain.com
ServerAlias www.your_domain.com

<Directory /var/www/magento>
AllowOverride All
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
# a2ensite magento.conf
# a2enmod rewrite

# systemctl restart apache2

Step 11: Access your Magento installation

Store Front: http://your_domain.com
Admin Dashboard: http://your_domain.com/admin_xxxxxx

Step 12: Diasable 2FA

# bin/magento mod:dis Magento_AdminAdobeImsTwoFactorAuth Magento_TwoFactorAuth
# bin/magento setup:di:compile

Options: Tuning Magento

https://experienceleague.adobe.com/docs/commerce-operations/performance-best-practices/software.html

Facebook Comments Box

Setup IKEA VINDRIKTNING + WeMos D1 mini (Tasmota Firmware)

IKEA VINDRIKTNING + WeMos D1 mini (Tasmota Firmware)

IoT 101 ของเรา วันนี้ จะมาพูดถึงวิธีการ Setup IKEA VINDRIKTNING + WeMos D1 mini (Tasmota Firmware) กันครับ
โดยมีขั้นตอนต่างๆ ประมาณนี้

1. เกาะ WiFi (AP): tasmota-XXXXXX-XXXX

2. เปิด Web Browser เข้า http://192.168.4.1

3. ทำการ Setup WiFi ที่ต้องการใช้งาน

4. จากนั้นเข้าผ่าน IP ใหม่ ของ Tasmota ที่ได้จาก WiFi ที่คุณใช้งาน

5. คลิก Configuration > Configure Module เลือก Generic (0) กด Save แล้วรอ Tasmota Restart

6. คลิกเข้า Configure Module อีกครั้ง
– PIN: D1 GPIO5 เลือก VINDRIKTNING
– PIN: D6 GPIO12 เลือก DHT11
กด Save แล้วรอ Tasmota Restart

7. เมื่อเรา config ถูกต้อง ก็จะได้ค่า Temperature, Humidity, Dew point และ PM 2.5 ตามรูปครับ

8. คลิก Configuration > Configure MQTT
– Host: mqtt.tono.tech
– Port: 1883
– Client: DVES_%06X (ค่า default)
– User: mqtt
– Password: XXXXXX
– Topic: tasmota_%06X (ค่า default)
* จากตัวอย่าง จะได้ค่า tasmota_1AB59B ตามเลข MAC Address ของตัว ESP8266
– Full Topic: %prefix%/%topic%/ (ค่า default)
กด Save แล้วรอ Tasmota Restart

9. คลิก Console จะเห็น Logs ที่ Tasmota ประมาณนี้ เป็นอันใช้ได้แล้ว

07:48:21.453 MQT: tele/tasmota_1AB59B/SENSOR = {"Time":"2023-03-21T07:48:21","DHT11":{"Temperature":24.7,"Humidity":72.0,"DewPoint":19.3},"VINDRIKTNING":{"PM2.5":7},"TempUnit":"C"}

10. Download IoT MQTT Panel จาก Play Store

11. เลือก Backup and Restore
จากนั้นเลือก RESTORE จาก pm25dashboard.json นี้ หรือจะเลือกสร้าง Dashboard ใหม่เองก็ได้
เปลี่ยนชื่อ topic เป์นของ Tasmota Device ของเรา
อย่างเช่นของผมจะเป็น tele/tasmota_1AB59B/SENSOR

pm25dashboard.json

{"dataVersion":120,"globalSettings":{"runInBackground":true,"appTheme":"dark"},"connections":[{"connectionName":"Tasmota PM2.5","clientId":"ub5bvpTlZA","host":"mqtt.tono.tech","port":1883,"connectionType":"tcp","username":"mqtt","password":"XXXXXX","connectionTimeout":30,"keepAlive":60,"autoConnect":true,"disableHostnameCheck":false,"caCertificateFileName":"","clientCertificateFileName":"","clientKeyFileName":"","sslClientPassword":"","enableWillMessage":false,"willTopic":"","willPayload":"","willRetain":false,"willQoS":0,"defaultDashboard":"dashboard_0","connectionId":"connection_0","notifyOnDisconnect":false}],"dashboards":[{"connectionId":"connection_0","dashboardId":"dashboard_0","dashboardName":"PM 2.5","dashboardPrefixTopic":"","lockPanels":true}],"panels":[{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_7","panelName":"WiFi Signal","type":"progress","mqttType":"sub","topic":"tele\/tasmota_1AB59B\/STATE","payloadMin":0,"payloadMax":100,"qos":0,"defaultColor":"success","dynamicColor":true,"firstColor":"danger","secondColor":"warning","thirdColor":"success","firstColorEnd":50,"secondColorEnd":80,"disableDashboardPrefix":true,"panelWidth":"100","panelMergeClass":"","showReceivedTimeStamp":true,"unit":"%","orientation":"horizontal","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.Wifi.RSSI","messageFactor":1,"step":1},{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_1","panelName":"Temp","type":"gauge","mqttType":"sub","topic":"tele\/tasmota_1AB59B\/SENSOR","payloadMin":0,"payloadMax":100,"qos":0,"disableDashboardPrefix":false,"panelWidth":"33","firstColor":"#009600","secondColor":"#fac800","thirdColor":"#ff5722","firstColorEnd":33.33,"secondColorEnd":66.67,"panelMergeClass":"","showReceivedTimeStamp":false,"unit":"°C","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.DHT11.Temperature","messageFactor":"","step":1},{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_2","panelName":"Humidity","type":"gauge","mqttType":"sub","topic":"tele\/tasmota_1AB59B\/SENSOR","payloadMin":0,"payloadMax":100,"qos":0,"disableDashboardPrefix":false,"panelWidth":"33","firstColor":"#009600","secondColor":"#fac800","thirdColor":"#ff5722","firstColorEnd":70,"secondColorEnd":100,"panelMergeClass":"","showReceivedTimeStamp":false,"unit":"%","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.DHT11.Humidity","messageFactor":1,"step":1},{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_3","panelName":"PM 2.5","type":"gauge","mqttType":"sub","topic":"tele\/tasmota_1AB59B\/SENSOR","payloadMin":0,"payloadMax":1000,"qos":0,"disableDashboardPrefix":false,"panelWidth":"33","firstColor":"#009600","secondColor":"#fac800","thirdColor":"#ff5722","firstColorEnd":35,"secondColorEnd":85,"panelMergeClass":"","showReceivedTimeStamp":false,"unit":"ug\/m3","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.VINDRIKTNING.['PM2.5']","messageFactor":1,"step":10},{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_0","panelName":"PM 2.5","type":"line-graph","mqttType":"sub","qos":0,"comboItemList":[{"topic":"tele\/tasmota_1AB59B\/SENSOR","label":"ug\/m3","color":"#7b00f5","showArea":true,"showPoints":true,"unit":"","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.VINDRIKTNING.['PM2.5']","messageFactor":1}],"disableDashboardPrefix":false,"panelWidth":"100","panelMergeClass":"","maxPersistence":50,"smoothCurve":true},{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_4","panelName":"Temp","type":"line-graph","mqttType":"sub","qos":0,"comboItemList":[{"topic":"tele\/tasmota_1AB59B\/SENSOR","label":"°C","color":"#99ff99","showArea":true,"showPoints":true,"unit":"°C","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.DHT11.Temperature","messageFactor":1}],"disableDashboardPrefix":false,"panelWidth":"100","panelMergeClass":"","maxPersistence":50,"smoothCurve":true},{"connectionId":"connection_0","dashboardId":"dashboard_0","panelId":"panel_5","panelName":"Humidity ","type":"line-graph","mqttType":"sub","qos":0,"comboItemList":[{"topic":"tele\/tasmota_1AB59B\/SENSOR","label":"%","color":"#007bf5","showArea":true,"showPoints":true,"unit":"%","enableNotification":false,"notificationFilter":"all","notificationMin":"","notificationMax":"","notificationValue":"","notificationRegex":"","notificationMessage":"","isJSONPayload":true,"jsonPath":"$.DHT11.Humidity","messageFactor":1}],"disableDashboardPrefix":false,"panelWidth":"100","panelMergeClass":"","maxPersistence":50,"smoothCurve":true}]}

12. ถ้าเสร็จเรียบร้อย เราก็จะได้ Dashboard ไว้ใช้งานแล้วครับ

PM 2.5 Dashboard

* เพิ่มเติมครับ วิธีการ Hard Reset Tasmota กลับไปเป็นค่า default

1. ถอดสาย USB ออก 30s
2. เสียบสาย ถอดสาย สลับกัน 7 ครั้ง (ครั้งละไม่เกิน 5s)

เป็นอย่างไรกันบ้างครับ ไม่ยากเลยใช่ไหมครับ ในการทำ Dashboard ดีๆ ไว้ดูคุณภาพอากาศ สำหรับช่วง PM 2.5 ประเทศเรา เป็นผู้นำอันดับโลก แบบนี้ 🙂
ถ้าสงสัยหรืออยากสอบถามเพิ่มเติม comment ไว้ตรงนี้ หรือ add LINE ID: pornpasok เข้ามาพูดคุยกันได้ครับ ..

Facebook Comments Box

Filebeat Lightweight shipper for logs from k8s to Elasticsearch

Beat

สวัสดีครับ DevOps 101 ของเรา วันนี้ จะมาพูดถึง Filebeat นะครับ ..

Filebeat คืออะไร?
Filebeat = Lightweight shipper for logs
“Whether you’re collecting from security devices, cloud, containers, hosts, or OT, Filebeat helps you keep the simple things simple by offering a lightweight way to forward and centralize logs and files.”

ถ้าเอาแบบเข้าใจง่ายๆ ก็คือ ตัวกวาด logs จากที่ต่างๆ เข้ามาที่ centralize logs ในที่นี้ ผมจะพูดถึง k8s cluster (EKS) logs ไปเก็บที่ Elasticsearch ละกันนะครับ ..

จริงๆ ยังมี ตัวอื่นๆ อีก นะครับ ที่ทำงานคล้ายๆ Filebeat เช่น Fluentd, Fluentbit

ในเมื่อเราใช้ ELK Stack ใน Ecosystem ของเราแล้ว การที่เราอยาก search logs ต่างๆ ที่เกิดจาก container ของเรา ได้ง่ายสุด ก็คือการ ship logs จาก k8s cluster ของเรา ไปเก็บไว้บน Elasticsearch แล้วทำการ search ผ่าน Kibana ..

วิธีการ Install Filebeat ใน k8s cluster

ทำได้หลายวิธีครับ ในที่นี้ ผมจะใช้วิธีง่ายๆ ผ่าน kubectl ดังต่อไปนี้

1. Create Secret โดยใส่ค่าที่จำเป็น พวกนี้ลงไป

ELASTICSEARCH_HOST = Endpoint ของ Elasticsearch เรา
ELASTICSEARCH_PORT = Port ที่ Elasticsearch เราทำงานอยู่
ELASTICSEARCH_USERNAME = Username ของ Elasticsearch
ELASTICSEARCH_PASSWORD = Password ของ Elasticsearch
ELASTIC_CLOUD_ID = Cloud ID ในกรณีที่เราใช้ผ่าน Cloud Service ของ Elastic.co
ELASTIC_CLOUD_AUTH = Username:Password ของ Elasticsearch

filebeat-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: filebeat
  namespace: kube-system
type: Opaque
data:
  ELASTICSEARCH_HOST: aHR0cDovL2xvY2FsaG9zdA==
  ELASTICSEARCH_PASSWORD: 
  ELASTICSEARCH_PORT: OTIwMA==
  ELASTICSEARCH_USERNAME: 
  ELASTIC_CLOUD_AUTH: 
  ELASTIC_CLOUD_ID: 

จากนั้น สั่ง create secret

kubectl create -f filebeat-secret.yaml

2. Create Deployment และ Resource อื่นๆ

filebeat-kubernetes.yaml

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: kube-system
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    # To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:
    filebeat.autodiscover:
      providers:
       - type: kubernetes
         node: ${NODE_NAME}
         hints.enabled: true
         hints.default_config:
           type: container
           paths:
             - /var/log/containers/*${data.kubernetes.container.id}.log

    # Filter by container.name
    # filebeat.autodiscover:
    #   providers:
    #     - type: kubernetes
    #       node: ${NODE_NAME}
    #       templates:
    #         - condition:
    #             contains:
    #               kubernetes.container.name: "container01"
    #           config:
    #             - type: container
    #               paths:
    #                 - "/var/log/containers/*-${data.kubernetes.container.id}.log"
    #         - condition:
    #             contains:
    #               kubernetes.container.name: "container02"
    #           config:
    #             - type: container
    #               paths:
    #                 - "/var/log/containers/*-${data.kubernetes.container.id}.log"

    processors:
      - add_cloud_metadata:
      - add_host_metadata:

    cloud.id: ${ELASTIC_CLOUD_ID}
    cloud.auth: ${ELASTIC_CLOUD_AUTH}

    output.elasticsearch:
      hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
      #index: "%{[fields.my_type]}-%{[agent.version]}-%{+yyyy.MM.dd}" 
      username: ${ELASTICSEARCH_USERNAME}
      password: ${ELASTICSEARCH_PASSWORD}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: kube-system
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: filebeat
          image: docker.elastic.co/beats/filebeat:8.6.2
          args: ["-c", "/etc/filebeat.yml", "-e"]
          env:
            - name: ELASTICSEARCH_HOST
              valueFrom:
                secretKeyRef:
                  name: filebeat
                  key: ELASTICSEARCH_HOST
            - name: ELASTICSEARCH_PORT
              valueFrom:
                secretKeyRef:
                  name: filebeat
                  key: ELASTICSEARCH_PORT
            - name: ELASTICSEARCH_USERNAME
              valueFrom:
                secretKeyRef:
                  name: filebeat
                  key: ELASTICSEARCH_USERNAME
            - name: ELASTICSEARCH_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: filebeat
                  key: ELASTICSEARCH_PASSWORD
            - name: ELASTIC_CLOUD_ID
              valueFrom:
                secretKeyRef:
                  name: filebeat
                  key: ELASTIC_CLOUD_ID
            - name: ELASTIC_CLOUD_AUTH
              valueFrom:
                secretKeyRef:
                  name: filebeat
                  key: ELASTIC_CLOUD_AUTH
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
            # If using Red Hat OpenShift uncomment this:
            #privileged: true
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 100Mi
          volumeMounts:
            - name: config
              mountPath: /etc/filebeat.yml
              readOnly: true
              subPath: filebeat.yml
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog
              mountPath: /var/log
              readOnly: true
      volumes:
        - name: config
          configMap:
            defaultMode: 0640
            name: filebeat-config
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
        - name: varlog
          hostPath:
            path: /var/log
        # data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
        - name: data
          hostPath:
            # When filebeat runs as non-root user, this directory needs to be writable by group (g+w).
            path: /var/lib/filebeat-data
            type: DirectoryOrCreate
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: filebeat
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: filebeat
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: kube-system
roleRef:
  kind: Role
  name: filebeat
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: filebeat-kubeadm-config
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: kube-system
roleRef:
  kind: Role
  name: filebeat-kubeadm-config
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: filebeat
  labels:
    k8s-app: filebeat
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources:
      - namespaces
      - pods
      - nodes
    verbs:
      - get
      - watch
      - list
  - apiGroups: ["apps"]
    resources:
      - replicasets
    verbs: ["get", "list", "watch"]
  - apiGroups: ["batch"]
    resources:
      - jobs
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: filebeat
  # should be the namespace where filebeat is running
  namespace: kube-system
  labels:
    k8s-app: filebeat
rules:
  - apiGroups:
      - coordination.k8s.io
    resources:
      - leases
    verbs: ["get", "create", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: filebeat-kubeadm-config
  namespace: kube-system
  labels:
    k8s-app: filebeat
rules:
  - apiGroups: [""]
    resources:
      - configmaps
    resourceNames:
      - kubeadm-config
    verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: kube-system
  labels:
    k8s-app: filebeat
---
 

จากนั้น สั่ง create deployment

kubectl create -f filebeat-kubernetes.yaml

3. Search k8s cluster logs ผ่าน Kibana

ถ้า config ทุกอย่างเราถูกต้อง container ทำงานได้ เราก็จะได้ logs ของ k8s cluster เรา ไปเก็บบน Elasticsearch และทำการ search ผ่าน Kibana ได้เลย

Kibana Search

* เราสามารถ filter input ของ Logs ที่จะ ship ไปเก็บ ที่ Elasticsearch ได้

ตัวอย่างอยู่ใน filebeat-kubernetes.yaml ที่ comment ไว้

เป็นอย่างไรกันบ้างครับ ไม่ยากเลยใช่ไหมครับ สำหรับการ ship logs จาก k8s cluster ของเรา ไปเก็บบน Elasticsearch 🙂

Git Repo: https://github.com/pornpasok/k8s-logs-es-filebeat
Ref: https://www.elastic.co/beats/filebeat

Facebook Comments Box

Happy New Year 2023 สวัสดีปีใหม่ 2566

กย 9666 จันทุบรี

สวัสดีปีใหม่ 2023 ครับ อาจจะช้าไปสักนิด พอดีช่วงหยุดปีใหม่ ที่ผ่านมา
ผมเองมีภารกิจ กลับไปทำ checklist ที่ list ไว้ว่าจะไปทำที่บ้าน
เพราะว่า นานๆ กลับที ไม่ได้กลับบ่อย ก็เลยต้องไปทำให้เสร็จครับ ..
จริงๆ list ไว้หลายอย่างมาก แต่ทำไม่สำเร็จ เพราะว่า ไม่มีเวลาพอ
บางอย่าง ก็ทำเองไม่ได้ทั้งหมด +___+
ที่ทำเสร็จไปแล้ว ก็มีประมาณนี้
– ติดม่านกันแสง UV หน้าต่าง ประตู ทั่วบ้าน หลังจากปล่อยโล่งๆ มา 8 ปี
– ติดกล้องวงจรปิดใหม่ ครอบคลุม และมีประสิทธิภาพมากขึ้น
– ติดระบบไฟ Solar รอบบ้าน ให้แสงสว่าง ประหยัดพลังงาน
– ซ่อมแซม เครื่องมือเครื่องใช้ต่างๆ ให้ทำงานได้ปกติ เหมือนเดิม
– ซ่อมแซม และทำระบบเพิ่ม ทั้ง IoT และ Weather Station
– ซ่อมแซม ตรวจสอบ Jeep ให้ทำงานได้ปกติ (ยังเหลือ switch ประตู และระบบไฟ)
– อื่นๆ ก็ทำนั้นทำนี่ ให้ดีขึ้น ให้สมบูรณ์ขึ้น

สำหรับปี 2022 ที่ผ่านมา ถือว่าเป็นปีที่เกิดการเปลี่ยนแปลง อย่างยิ่งเหมือนกันสำหรับผม
– เข้ามาอยู่ กทม. อีกรอบ ช่วงโควิด (Dec 2021) เช่าคอนโด อยู่ใจกลางเมือง ย่านรัชโยธิน
– งานส่วนใหญ่ ก็ยังเป็น เกี่ยวกับ DevOps ทำ Infrastructure, CI/CD Tools, Monitoring Tools ให้ Developers ใช้งาน
– ได้เข้าไปทำงาน ในระบบธุรกิจใหม่ๆ ที่ไม่เคยทำมาก่อน ก็สนุกดี ได้เจออะไรแปลกๆ ใหม่ๆ เยอะดี
– บริษัทที่ทำงานด้วย ดีมาก ไม่ได้เน้นระเบียบ หรือกระบวนการ ที่ไม่จำเป็น ทำให้ทำงานได้แบบมีประสิทธิภาพและคุณภาพ มากขึ้น, ไม่ต้องเข้า office ทุกวัน
– เดินทาง ท่องเที่ยว มากขึ้น เพราะโควิด เริ่มไม่รุนแรง
– รายได้ ของปีนี้ เริ่มดีขึ้น ทุกอย่างเริ่มลงตัวขึ้น
– หันมาออกกำลังกาย ช่วงปลายปี เพื่อสุขภาพ
– งดดื่ม ถ้าไม่จำเป็น +____+
– ผลตรวจสุขภาพ ประจำปี แบบละเอียด (package 5500 ของ รพ.สมิติเวช) พบว่าสุขภาพดีขึ้น จากปีก่อนๆ ที่ร่างกายหักโหม ดื่มหนัก ไม่ได้ออกกำลังกาย
– ได้มีเวลา หยุดยาว ช่วงปลายปี กลับไปอยู่บ้าน ที่จันทบุรี
– ได้ทะเบียนใหม่ มาใส่ Jeep ละครับ กย 9666 จันทบุรี ผลรวม = 36 ก็ถือว่าดีมาก สำหรับเลขนี้ ผลรวมนี้ ส่วนตัวผม เลขนี้ ก็มีความหมายของมันเอง สำหรับรถ ก็คือรถปี 1996 แล้วก็ทะเบียน ได้มาใช้ปี 2566 อีกด้วย ลงตัวเป๊ะ 🙂

สำหรับปี 2023 ที่คาดหวังไว้ และอยากทำ มีประมาณนี้
– ก็ยังคงเหมือนปี 2022 ที่ยังทำไม่ได้ทั้งหมด +___+
– ออกกำลังกาย มากขึ้น เลือกกินอาหาร ที่ดีต่อร่างกาย เน้นเรื่องสุขภาพเป็นหลัก
– ลดน้ำหนัก ให้เหลือ <= 75 (ปัจจุบัน 81-82)
– ทำงานที่ได้รับมอบหมาย ให้มีประสิทธิภาพ ดีที่สุด ให้เกินกว่าที่ต้องทำ ในทุกมิติ
– ศึกษาหาความรู้ เพิ่มเติมเสมอ
– เดินทาง ท่องเที่ยว ให้มากขึ้น ไปที่ใหม่ๆ ที่ไม่เคยไปบ้าง
– ใช้จ่ายอย่างประหยัด ใช้เท่าที่จำเป็น, ลงทุน หลายๆ ทางที่พอมีความเป็นไปได้
– ทำธุรกิจ เกี่ยวกับ technology ด้านการเกษตร (Agritech) จริงๆ จังๆ
– อยากทำ มอเตอร์ไซค์ ให้เช่าที่ปาย และเมืองท่องเที่ยวอื่นๆ
– เก็บสะสม รถที่ชอบ และราคาไม่น่าจะตกแล้ว
– กลับบ้านให้บ่อยขึ้น
– ช่วยเหลือสังคม เท่าที่กำลังกาย และกำลังทรัพย์ พอจะทำได้ 🙂

Facebook Comments Box

Setup Elasticsearch and Kibana OpenID Connect with Azure AD

elastic.co with Azure AD

สวัสดีครับ DevOps 101 ของเรา วันนี้มีเรื่องมาแนะนำ การ setup Single Sign-On (SSO) ของ App เรา .. ด้วย Azure AD โดยที่เรา ไม่จำเป็นต้องมีสิทธิเป็น admin ของ org นั้นๆ .. เป็น user ธรรมดา ก็สามารถ ทำได้
ในที่นี้ จะใช้ในส่วนของ OpenID Connect (OIDC) นะครับ ซึ่งสามารถ ใช้งานทั้งกับ Google, GitHub, AWS Cognito และอื่นๆ ได้ .. แต่ในที่นี้ผมจะใช้เป็น Azure AD นะครับ

จากความต้องการขององค์กร ที่ต้องการให้ พนักงานทุกคน login ด้วย Azure AD หรือถ้าพูดให้เข้าใจง่าย ก็คือใช้ email บริษัท ในทุกๆ App ที่ใช้งาน เนื่องจากเราใช้ Office365 อยู่แล้ว .. จะได้สะดวกในการจัดการ พนักงาน ที่มีการเข้าออก เปลี่ยนแปลงอยู่เสมอ ไม่ต้อง add แบบ local user ..

ในที่นี้ผมจะยกตัวอย่างการ นำ Azure AD (OpenID Connect) มาใช้กับ ELK Stack โดยสามารถใช้ได้ กับ ELK Stack ที่เรา hosted เอง และใช้ได้กับ elastic.co นะครับ ..

วิธีการ Setup OpenID Connect เราสามารถทำตามขั้นตอน ใน docs ของ elastic.co ได้เลยดังนี้
https://www.elastic.co/guide/en/cloud/current/ec-securing-clusters-oidc-op.html#ec-securing-clusters-oidc-op

จากนั้น เราสามาถทำ Role Mappings ได้ใน Kibana อย่างในที่นี้ ผมจะให้ user ที่ login ผ่าน Azure AD (OIDC) ทั้งหมด มี สิทธิแค่ viewer ก็สามารถทำได้ประมาณนี้

User field: realm.name
Type: text
Value: oidc1 (ชื่อ realm ที่เรา config ในหน้า login ของ Kibana)

Kibana Role Mappings

หรือถ้าเรา ต้องการสร้าง Role mapping เฉพาะเจาะจงว่า user (email) คนไหน สามารถทำอะไรเพิ่มเติมได้ บ้าง เราก็สามารถ สร้างเพิ่มได้ ประมาณนี้

User field: username
Type: text
Value: user@email.com (email ของ user ที่เราต้องการ)

Kibana Role Mappings Specific by Email

จะเห็นว่า เราสามารถนำ Azure AD (OpenID Connect) มาใช้กับ Kibana ของเราได้ ทำให้เราสะดวก ในการจัดการ user และการ ทำ Role Mappings ก็ช่วยให้เรา สามารถกำหนด permission ของแต่ละ user ให้แตกต่างกันได้ .. เราไม่ต้องไป add local user บน Elasticsearch และเราสามารถนำ OpenID Connect ไปใช้กับ App อื่นๆ ของเราได้ด้วยเช่นกันครับ .. ไม่ว่าจะเป็น App ที่เราเขียนเอง หรือ OpenSource ต่างๆ ก็รองรับ OpenID Connect กันเป็นส่วนใหญ่ 🙂

ถ้าเพื่อนๆ สงสัยตรงไหน comment กันเข้ามาถามได้นะครับ ไม่ยากครับ ลองไปทำเล่นดู elastic.co เอง ใช้งานได้ฟรี 14 วันครับ หรือถ้าจะ Hosted เองด้วย docker-compose ง่ายๆ ก็ได้ครับ 🙂

ตัวอย่าง: https://github.com/pornpasok/docker-elk

Facebook Comments Box

ลองใช้ Argo CD deploy application บน EKS

Argo CD Dashboard
Argo CD Dashboard

DevOps 101 ของเราวันนี้ จะมาทดลองใช้งาน Argo CD กันนะครับ .. ว่ามันดียังไง ทำอะไรได้บ้าง และเหมาะกับใคร? Logo ของ Argo CD ก็น่ารักดีครับ เป็นรูป มนุษย์ต่างดาว หรือ หมึก ก็ไม่รู้ ..

นิยามที่ทาง Argo CD เค้าบอกไว้ ในเว็บเค้าเองก็คือ ..

What Is Argo CD?
“Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.”

ถ้าสรุปให้เข้าใจได้ง่ายๆ ก็คือ เป็น Tools สำหรับทำ CD (Continuous Delivery) ที่ตรงไปตรงมา
ไม่ซับซ้อน สำหรับ deploy Application บน k8s ด้วยการใช้หลักการของ GitOps

รายละเอียดเพิ่มเติม : https://argo-cd.readthedocs.io/

เท่าที่ลองเล่นดู หลังจากที่เรามี k8s cluster แล้ว (ในที่นี่ผมใช้ EKS) เราก็จะต้อง Install เจ้า Argo CD ใน k8s cluster ของเรา จากนั้น เราก็จะใช้ความสามารถของ Argo CD ได้ ด้วยการผูกกับ Git Repository ที่ใช้ในการ deploy Application ของเรา เท่านี้ก็เป็นอันเรียบร้อยครับ .. เมื่อเรามีการเปลี่ยนแปลง configuration บน git เจ้า Argo CD ก็จะมา sync config ไป deploy บน k8s cluster ให้เรา ..

ดูรายละเอียดเพิ่มเติมที่ YouTube ของ Nana ได้ที่นี่ครับ : https://www.youtube.com/watch?v=MeU5_k9ssrs

สรุปความคิดเห็นส่วนตัว ที่ลองใช้งาน (ยังไม่ได้ใช้จริงๆ จังๆ บน Production)

ข้อดี
– Install ง่ายมาก ไม่เจอปัญหาอะไรเลย ใช้ resource น้อยมาก
– ไม่ต้องวุ่นวาย เรื่องการ Install kubectl เพราะอยู่ใน k8s cluster อยู่แล้ว
– ไม่ต้องวุ่นวาย เรื่องการจัดการ Credentials ในการเข้าถึง k8s cluster
– มี Dashboard ที่แสดงรายละเอียด ของการ deploy Application ได้ละเอียด ครบถ้วน
– Sync manifest จาก Git Repository ได้รวดเร็ว
– หน้าตาดูดี สวยงาม

ข้อเสีย
– Deploy (CD) บน k8s cluster ได้เท่านั้น
– ในส่วนของ CI (Continuous Integration) ยังต้องใช้ 3rd-party อื่นช่วย ไม่ว่าจะเป็น GitHub Action, GitLab CI, Jenkins
– ถ้าดูพวก Metrics ได้ด้วย น่าจะดีเลย แต่คิดว่า คงออกแบบมา ให้ simple ทำงาน CD ได้อย่างดี ก็พอ

Facebook Comments Box

[Trick] Deploy Docker Images with Jenkins Pipeline

docker-jenkins-love

DevOps 101 วันนี้ มาขอเล่าเรื่อง trick ง่ายๆ ในการ deploy docker images กันครับ

1. เรื่อง Time Zone โดยปกติแล้ว ถ้าเราไม่กำหนด ตัว container ที่ run จะเป็น UTC นะครับ ในตัวอย่าง ถ้าอยากให้ Time Zone ตรงกับบ้านเรา (UTC +7) เราสามารถ เข้าไป กำหนดได้ง่ายๆ ประมาณนี้ครับ
Dockerfile

FROM python:3.9
ENV TZ="Asia/Bangkok"
RUN date

Build

docker build -t dockertest .

Run

docker run -it dockertest -c "date"

ถ้าเป็น alpine based image จะต้อง install tzdata ก่อน ประมาณนี้ครับ

RUN apk add --no-cache tzdata
ENV TZ Asia/Bangkok

2. เวลา run docker ด้วย tag:latest แล้ว อาจจะมี การ cache บน local ทำให้ ไม่ได้ image ล่าสุด เราสามารถแก้ไขได้โดย ใส่ options –pull=always ตัวอย่างเช่น

docker run --pull=always

3. ถ้าอยาก run Jenkins Pipeliine แบบ trigger ด้วย cron เราสามารถเพิ่ม cron เข้าไปได้ ประมาณนี้


pipeline {
    agent any
    triggers {
        cron('00 20 * * *')
    }

    stages {
        stage('Hello') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

สำหรับการ Set Time Zone ในตัว Jenkins เอง ผมเคยเขียนรายละเอียดไว้แล้วครับ อ่านเพิ่มเติมได้ที่
https://ton.packetlove.com/blog/devops/devops-101-jenkins-set-time-zone.html

อันนี้เป็น trick เล็กๆ น้อยๆ ที่เอามาเล่าสู่กันฟังนะครับ ที่เจอตอน deploy app ที่เป็น docker images ด้วย Jenkins Pipeline 🙂

Facebook Comments Box