New FAMILUG

The PyMiers

Sunday, 30 October 2022

GitLab CE tự host không như GitLab.com

Một đoạn code đơn giản, đã chạy ít nhất 5 năm trên gitlab.com, khi mang về gitlab CE tự host, dùng cùng gitlab CI runner, chạy CICD job lại fail.

$ git diff --name-only origin/master...HEAD
...
fatal: ambiguous argument 'origin/master...HEAD': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
...

Không có origin/master, kể cả master cũng không có.

img

Photo by Abdulaziz Alfawzan on Unsplash

Hóa ra bên trên output của GitLab CI job có 1 dòng

Fetching changes with git depth set to 20...

Config trên GitLab > CICD Settings của project, mặc định sau khi cài GitLab CE 15.4.2, giá trị Git shallow clone là 20.

Trên GitLab.com, giá trị này mặc định là không set (blank).

gitlab

The number of changes to fetch from GitLab when cloning a repository. Lower values can speed up pipeline execution. Set to 0 or blank to fetch all branches and tags for each job

Kết luận

Code chạy 5 năm, trên cùng 1 chỗ, vẫn fail, vì config từ web thay đổi.

Hết.

Friday, 21 October 2022

Tạm biệt VirtualBox, chào Debian trên libvirt thêm lần nữa

Có 3 giải pháp tạo máy ảo phổ biến: vmware, virtualbox và kvm (linux only).

Bắt đầu với Virtualbox từ khi dùng Windows, đi làm dùng Ubuntu chuyển qua kvm vì các dòng lệnh & công việc (openstack) dùng hàng ngày, rồi lại quay lại VirtualBox khi đó là lựa chọn duy nhất trên MacOs. Ngày nay, lại quay lại với kvm: vì open-source.

Mặc dùng VirtualBox là open-source, một số tính năng trong extension-pack lại chỉ của riêng Oracle và chỉ được dùng cho mục đích cá nhân, tức không thể dùng trên máy công ty/trong công việc. Nếu công ty đủ lớn, lỡ dùng trong công việc có thể bị kiện, đặc biệt là khi làm công ty nước ngoài.

Trên MacOS ngày nay có thể dùng UTM.

Cài đặt libvirt

virt-manager là chương trình giao diện đồ họa.

sudo apt install libvirt-daemon libvirt-clients virt-manager

Thêm user hiện tại vào group libvirt:

sudo usermod -a -G libvirt $(whoami)

Tải debian vagrant box

Vào https://app.vagrantup.com/debian/boxes/bullseye64

tải file libvirt, ví dụ:

https://app.vagrantup.com/debian/boxes/bullseye64/versions/11.20220912.1/providers/libvirt.box

Giải nén:

tar xf libvirt.box

sẽ thấy có file libvirt.img.

Bật virt-manager > File menu > New Virtual Machine > Import from disk > chọn file libvirt.img > next next next.

virt-manager

Bật máy lên, đăng nhập bằng user root password vagrant.

root@bullseye:~# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Happy hacking!

Monday, 17 October 2022

[AWS][SQS] Queue service dễ dùng, mà toàn trap

Trong ba vạn sáu ngàn chín trăm service của AWS cung cấp, mỗi cái một kiểu, có this có that. EC2, ALB, RDS, S3, SQS, Lambda là những cái tên "cơ bản" nhất, cũng là phổ biến nhất.

Đặc điểm chung là dễ dùng, đắt, và cũng dễ dính trap!!!

Let's go.

SQS là viết tắt của chữ Simple Queue Service, một dịch vụ cloud khá tương đương với các phần mềm message queue dưới đất như:

  • RabbitMQ
  • ActiveMQ
  • IronMQ

itatrap

Photo by Nick Fewings on Unsplash

Nếu bạn chưa nghe tên cả 3, thì nó giống như 1 cái ống nước, một đầu gửi thư, đầu kia nhận thư, nếu không ai nhận thì nó nằm trong cái ống.

Vì chỉ đơn giản có vậy, nên sau khi tạo 1 cái queue, thì dùng nó chỉ có 3 thao tác:

  • gửi message
  • nhận message
  • xóa message

message có thể là 1 đoạn text format JSON.

PS: bài viết không yêu cầu code Python, chỉ dùng minh họa.

Sử dụng Python lib boto3, mọi chuyện đơn giản đúng như nói. Ví dụ lấy từ tutorial của boto3 https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs.html

Tạo SQS queue

sqs = boto3.resource('sqs')

# Create the queue. This returns an SQS.Queue instance
queue = sqs.create_queue(QueueName='test', Attributes={'DelaySeconds': '5'})

# You can now access identifiers and attributes
print(queue.url)
print(queue.attributes.get('DelaySeconds'))

Gửi SQS message

sqs = boto3.resource('sqs')

# Get the queue
queue = sqs.get_queue_by_name(QueueName='test')

# Create a new message
response = queue.send_messages(Entries=[
    {
        'Id': '1',
        'MessageBody': 'world'
    },
    {
        'Id': '2',
        'MessageBody': 'boto3',
        'MessageAttributes': {
            'Author': {
                'StringValue': 'Daniel',
                'DataType': 'String'
            }
        }
    }
])

Nhận message rồi xử lý và xóa

Một mô hình đơn giản đó là có 1 đầu gửi lệnh tới SQS queue, đầu kia sẽ nhận lệnh và xử lý.

Nhận:

# Get the service resource
sqs = boto3.resource('sqs')

# Get the queue
queue = sqs.get_queue_by_name(QueueName='test')

while True:
# Process messages by printing out body and optional author name
    for message in queue.receive_messages(MessageAttributeNames=['Author']):
        # Get the custom author message attribute if it was set
        author_text = ''
        if message.message_attributes is not None:
            author_name = message.message_attributes.get('Author').get('StringValue')
            if author_name:
                author_text = ' ({0})'.format(author_name)

        # Print out the body and author (if set)
        print('Hello, {0}!{1}'.format(message.body, author_text))

        # Let the queue know that the message is processed
        message.delete()

Hết tutorial, quá dễ, quá đơn giản!!!

Traps

Hãy thử nghĩ các vẫn đề có thể xảy ra liên quan đến SQS ở đoạn code trên trước khi đọc tiếp, đây chỉ nói về SQS, không nói về code Python.

Trap 1: delete() chưa chắc đã delete message

Ở đây không nói về lỗi network. Đó có lẽ là điều cuối cùng bạn nghĩ tới, khi function delete đôi khi sẽ không delete

Điều này có ghi rõ 2 trường hợp có thể xảy ra chuyện này, và tất nhiên chỉ ai nhìn delete() mà không tin nó sẽ delete mới đọc doc:

Trường hợp 1 là khi dùng SQS standard queue.

For standard queues, it is possible to receive a message even after you delete it. This might happen on rare occasions if one of the servers which stores a copy of the message is unavailable when you send the request to delete the message. The copy remains on the server and might be returned to you during a subsequent receive request. You should ensure that your application is idempotent, so that receiving a message more than once does not cause issues.

Yep, SQS có 2 loại queue, 1 là standard queue (cũ) 2 là FIFO queue mới ra đời vào 2016, sau 12 năm tồn tại của SQS với vô số "bí mật". Standard queue có thể xảy ra trường hợp delete xong mà vẫn còn message.

Nếu ai từng học về cấu trúc dữ liệu trong lập trình, kiểu queue có nghĩa là phải FIFO (first-in first-out), thì queue của AWS có 2 loại là 1 không FIFO và 1 FIFO.

Trường hợp thứ 2, tinh vi hơn:

The ReceiptHandle is associated with a specific instance of receiving a message. If you receive a message more than once, the ReceiptHandle is different each time you receive a message. When you use the DeleteMessage action, you must provide the most recently received ReceiptHandle for the message (otherwise, the request succeeds, but the message might not be deleted).

Tức nếu có

  • C1 nhận messageA xử lý,
  • rồi C2 nhận messageA xử lý
  • C1 delete message -> return success, nhưng không thực sự xóa
  • C2 delete message -> nếu không có thằng nào khác (C3, C4...) thì mới xóa.

C1 và C2 có thể nhận cùng 1 message, nếu 1 hệ thống có nhiều worker cùng hoạt động, cùng gọi SQS, thì ban đầu chỉ C1 nhận được messageA, nhưng sau visibility timeout mặc định 30s, C2 cũng sẽ nhìn thấy messageA. Chỉ với 1 message có visibility timeout 30s, và 2 worker xử lý mỗi message sau 50s, bạn đã tạo được 1 vòng lặp gần vô hạn!

img

Trap2

receive_messages kể cả không nhận được message nào, cũng mất phí. Nhìn chung thì cứ gọi API của AWS là tính phí rồi, nên cái này không đến nỗi quá bất ngờ. Nhưng khi chứng kiến các backend engineer viết app "scale"/concurrency/parallel, gọi hàng triệu call mỗi 10 giây, số tiền bạn phải trả AWS 1 tháng đủ để trả lương kỹ sư ấy cả năm.

$0.4/1_000_000 call => 86400/10 * 0.4 == $3_456/ngày.

Trap N

Ôi dào, đấy là do không chịu đọc doc của từng function thôi.

Okie bạn ơi, còn 31 cái warning 56 cái note trong tài liệu này, chúc vui! https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs.html

Còn trang tutorial thân thiện, thì không có gì. https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs.html

Kết luận

AWS dễ, mà trap everywhere, và mỗi bài học phải được trả bằng tiền, rất nhiều tiền!

Có trong tay full các chứng chỉ cloud của 1 nhà cung cấp cloud hàng đầu (không phải AWS), tôi không tin có chứng chỉ nào dạy cho bạn những điều này.

Đó là việc của "best practice", của các chuyên gia tư vấn sẽ tới thăm bạn và xin cục tiền.

PS: Nếu lỗi nào có được đào tạo khi luyện thi các chứng chỉ của AWS, các chuyên gia AWS full chứng chỉ vui lòng PM mình để update vào đây, tạo động lực thi chứng chỉ cho quần chúng.

Happy crying!

Hết.

HVN at http://pymi.vn and https://www.familug.org.

Ủng hộ tác giả 🍺

Sunday, 16 October 2022

Hello world dùng x64 assembly

Assembly (asm) ở Việt Nam được gọi là "hợp ngữ cũng có thể được gọi là mã máy tượng trưng", là một ngôn ngữ lập trình cấp thấp, thường tương ứng 1 lệnh với 1 lệnh của CPU. Lập trình assembly ngày nay không còn phổ biến như trước khi có C.

C/Zig/Rust... được dùng để viết code "low level", nhưng khi cần tốc độ tối đa, lập trình nhúng, viết driver, hay thực hiện reverse engineering, binary exploitation, asm là ngôn ngữ được ưa chuộng.

cpu

Photo by Olivier Collet on Unsplash

  • Code Rust ---compile -> binary
  • Code C ---compile -> binary
  • Code ASM ---compile -> binary

Loạt bài viết này giới thiệu vài chương trình assembly đơn giản, cách compile, chạy, các tool dùng để tìm hiểu file binary.

Assembly đơn giản (giới hạn không nhiều lệnh, luật lệ rõ ràng), nhưng không dễ (mất rất nhiều bước để làm một việc, rất thủ công).

Hello world

Là một chương trình in ra màn hình dòng chữ "hello world".

Code Python:

print("Hello,world")

Code C:

#include <stdio.h>
int main(int argc, char *argv[])
{
    puts("Hello, world\n");
    return 0;
}

Code asm trong file hello.s - copy từ wikipedia https://en.wikipedia.org/wiki/GNU_Assembler#Example_program

.global _start

.text
_start:
    mov  $4, %eax   # 4 (code for "write" syscall) -> EAX register
    mov  $1, %ebx   # 1 (file descriptor for stdout) -> EBX (1st argument to syscall)
    mov  $message, %ecx # address of message string -> ECX (2nd argument)
    mov  $len, %edx # len (32 bit address) -> EDX (3rd arg)
    int   $0x80      # interrupt with location 0x80 (128), which invokes the kernel's system call procedure

    mov  $1, %eax   # 1 ("exit") -> EAX
    mov  $0, %ebx   # 0 (with success) -> EBX
    int  $0x80      # see previous
.data
message:
    .ascii  "Hello, PyMivn!\n" # inline ascii string
    len = 15

Compile dùng gcc

$ gcc -c hello.s
$ ls -l
-rw-rw-r--  1 hvn hvn  904 Oct 16 14:11 hello.o
-rw-rw-r--  1 hvn hvn  598 Oct 16 14:11 hello.s
$ file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

gcc -c compile source code hello.s sẽ sinh ra object file hello.o. GCC sẽ gọi GNU Assembler (gas - lệnh là as) để thực hiện compile. Ngoài as, trên Linux còn phổ biến nasm. Trên Windows phổ biến MASM

ld - linker

man ld

ld combines a number of object and archive files, relocates their data and ties up symbol references. Usually the last step in compiling a program is to run ld.

ld thực hiện link (các) file object, ở đây chỉ có 1 file hello.o, thành file binary cuối cùng chạy đuợc, có tên mặc định là a.out.

$ ld hello.o
$ ls -l
-rwxrwxr-x  1 hvn hvn 8920 Oct 16 14:13 a.out
$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
$ ./a.out
Hello, PyMivn!

ELF file

file binary chạy được tên a.out trên Linux có format ELF.

$ whatis elf
elf (5)              - format of Executable and Linking Format (ELF) files

Trên MacOS sử dụng format Mach-O, trên Windows sử dụng format Portable Executable (PE).

https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats.

Chi tiết code asm

AT&T và Intel syntax

asm có hai nhánh syntax chính, là AT&T và Intel. Intel phổ biến trên Windows, AT&T phổ biến trên Unix/Linux. Xem chi tiết so sánh tại https://en.wikipedia.org/wiki/AT%26T_syntax#Syntax

hello.s

Code asm trong bài này chứa 3 section. .global, .data.text, sử dụng AT&T syntax.

.global makes the symbol visible to ld

.global sẽ khai báo function nào được chạy, ở đây là _start (thực chất là export symbol _start cho linker nhìn thấy)

.global _start

.data còn gọi là data segment chứa các global variable & static variable.

.data
message:
    .ascii  "Hello, PyMivn!\n" # inline ascii string
    len = 15

.text chứa code của chương trình. Function _start

.text
_start:
    mov  $4, %eax   # 4 (code for "write" syscall) -> EAX register
    mov  $1, %ebx   # 1 (file descriptor for stdout) -> EBX (1st argument to syscall)
    mov  $message, %ecx # address of message string -> ECX (2nd argument)
    mov  $len, %edx # len (32 bit address) -> EDX (3rd arg)
    int   $0x80      # interrupt with location 0x80 (128), which invokes the kernel's system call procedure

    mov  $1, %eax   # 1 ("exit") -> EAX
    mov  $0, %ebx   # 0 (with success) -> EBX
    int  $0x80      # see previous

%eax %ebx %ecx %edx là 4 register (thanh ghi) trong CPU, để chứa các giá trị.

mov $4, %eax

tương đương với viết code C eax = 4. int $0x80 thực hiện interrupt tại địa chỉ 0x80, tức thực hiện gọi syscall. Dòng int $0x80 có thể viết thành syscall.

Về cơ bản đoạn code trên thực hiện gọi 2 syscall số 4-write và 1-exit

Code giả:

syscall(4, 1, message, len)
syscall(1, 0)

hay

write(stdout, message, len)
exit(0)

Chạy với lệnh strace để xem các syscall đã được dùng:

$ strace ./a.out > /dev/null
execve("./a.out", ["./a.out"], 0x7ffd32dba4c0 /* 58 vars */) = 0
strace: [ Process PID=327701 runs in 32 bit mode. ]
write(1, "Hello, PyMivn!\n", 15)        = 15
exit(0)                                 = ?
+++ exited with 0 +++

Phiên bản dùng Intel syntax:

.intel_syntax noprefix
.global _start

.text
_start:
    mov eax, 0x4
    mov ebx, 0x1
    lea ecx, [message]
    mov edx, 0xf
    int 0x80
    mov eax, 0x1
    mov ebx, 0x0
    int 0x80

.data
message:
    .ascii  "Hello, PyMivn!\n"

Hex view xxd

xxd in ra mã hex của từng byte.

$ whatis xxd
xxd (1)              - make a hexdump or do the reverse.
$ xxd a.out | grep -v '0000 0000 0000 0000 0000 0000 0000 0000'
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0200 3e00 0100 0000 0010 4000 0000 0000  ..>.......@.....
00000020: 4000 0000 0000 0000 5821 0000 0000 0000  @.......X!......
00000030: 0000 0000 4000 3800 0300 4000 0600 0500  ....@.8...@.....
00000040: 0100 0000 0400 0000 0000 0000 0000 0000  ................
00000050: 0000 4000 0000 0000 0000 4000 0000 0000  ..@.......@.....
00000060: e800 0000 0000 0000 e800 0000 0000 0000  ................
00000070: 0010 0000 0000 0000 0100 0000 0500 0000  ................
00000080: 0010 0000 0000 0000 0010 4000 0000 0000  ..........@.....
00000090: 0010 4000 0000 0000 2200 0000 0000 0000  ..@.....".......
000000a0: 2200 0000 0000 0000 0010 0000 0000 0000  "...............
000000b0: 0100 0000 0600 0000 0020 0000 0000 0000  ......... ......
000000c0: 0020 4000 0000 0000 0020 4000 0000 0000  . @...... @.....
000000d0: 0f00 0000 0000 0000 0f00 0000 0000 0000  ................
000000e0: 0010 0000 0000 0000 0000 0000 0000 0000  ................
00001000: b804 0000 00bb 0100 0000 b900 2040 00ba  ............ @..
00001010: 0f00 0000 cd80 b801 0000 00bb 0000 0000  ................
00001020: cd80 0000 0000 0000 0000 0000 0000 0000  ................
00002000: 4865 6c6c 6f2c 2050 794d 6976 6e21 0a00  Hello, PyMivn!..
00002020: 0000 0000 0000 0000 0000 0000 0300 0100  ................
00002030: 0010 4000 0000 0000 0000 0000 0000 0000  ..@.............
00002040: 0000 0000 0300 0200 0020 4000 0000 0000  ......... @.....
00002050: 0000 0000 0000 0000 0100 0000 0400 f1ff  ................
00002070: 0900 0000 0000 0200 0020 4000 0000 0000  ......... @.....
00002080: 0000 0000 0000 0000 1100 0000 0000 f1ff  ................
00002090: 0f00 0000 0000 0000 0000 0000 0000 0000  ................
000020a0: 1a00 0000 1000 0100 0010 4000 0000 0000  ..........@.....
000020b0: 0000 0000 0000 0000 1500 0000 1000 0200  ................
000020c0: 0f20 4000 0000 0000 0000 0000 0000 0000  . @.............
000020d0: 2100 0000 1000 0200 0f20 4000 0000 0000  !........ @.....
000020e0: 0000 0000 0000 0000 2800 0000 1000 0200  ........(.......
000020f0: 1020 4000 0000 0000 0000 0000 0000 0000  . @.............
00002100: 0068 656c 6c6f 2e6f 006d 6573 7361 6765  .hello.o.message
00002110: 006c 656e 005f 5f62 7373 5f73 7461 7274  .len.__bss_start
00002120: 005f 6564 6174 6100 5f65 6e64 0000 2e73  ._edata._end...s
00002130: 796d 7461 6200 2e73 7472 7461 6200 2e73  ymtab..strtab..s
00002140: 6873 7472 7461 6200 2e74 6578 7400 2e64  hstrtab..text..d
00002150: 6174 6100 0000 0000 0000 0000 0000 0000  ata.............
00002190: 0000 0000 0000 0000 1b00 0000 0100 0000  ................
000021a0: 0600 0000 0000 0000 0010 4000 0000 0000  ..........@.....
000021b0: 0010 0000 0000 0000 2200 0000 0000 0000  ........".......
000021c0: 0000 0000 0000 0000 0100 0000 0000 0000  ................
000021d0: 0000 0000 0000 0000 2100 0000 0100 0000  ........!.......
000021e0: 0300 0000 0000 0000 0020 4000 0000 0000  ......... @.....
000021f0: 0020 0000 0000 0000 0f00 0000 0000 0000  . ..............
00002200: 0000 0000 0000 0000 0100 0000 0000 0000  ................
00002210: 0000 0000 0000 0000 0100 0000 0200 0000  ................
00002230: 1020 0000 0000 0000 f000 0000 0000 0000  . ..............
00002240: 0400 0000 0600 0000 0800 0000 0000 0000  ................
00002250: 1800 0000 0000 0000 0900 0000 0300 0000  ................
00002270: 0021 0000 0000 0000 2d00 0000 0000 0000  .!......-.......
00002280: 0000 0000 0000 0000 0100 0000 0000 0000  ................
00002290: 0000 0000 0000 0000 1100 0000 0300 0000  ................
000022b0: 2d21 0000 0000 0000 2700 0000 0000 0000  -!......'.......
000022c0: 0000 0000 0000 0000 0100 0000 0000 0000  ................
000022d0: 0000 0000 0000 0000                      ........

Bài viết thực hiện trên Ubuntu 20.04.

Tham khảo

Free books:

Kết luận

Viết helloworld.asm không quá khó.

Happy hacking!

Thursday, 6 October 2022

Đọc một quyển sách 400 nghìn tốn bao nhiêu?

  • Sách là một người bạn
  • Sách là trí tuệ
  • Sách là một hình thức giải trí như film
  • ... blah blah blah ...

Đối với mỗi người sách là một thứ khác nhau. Nếu mua một cuốn sách giá 400.000 VND, thì đọc nó tốn bao nhiêu?

Câu trả lời không thực sự dễ dàng.

img

Photo by 🇸🇮 Janko Ferlič on Unsplash

Lấy vị dụ cuốn 1Q84 của Haruki Murakami bản tiếng Anh dày 1328, với tốc độ đọc 3 phút 1 trang, thì mất

>>> 1328*3
3984  phút
>>> 1328*3 / 60
66.4 giờ

66 tiếng (nếu mỗi ngày dành 1 tiếng đọc thì sau 2 tháng sẽ đọc xong, 1 năm đọc được 6 quyển).

Một tháng, 1 người lao động văn phòng đi làm ~168 tiếng.

Với mức lương trung bình 2021 của 1 lập trình viên Python có ~ 5 năm kinh nghiệm ở VN là ~1000 USD, 23 triệu/tháng. Thì thời gian để đọc hết cuốn sách này trị giá:

>>> usd_rate = 24000
>>> 66/168 * 1000 * usd_rate
9428571.428571427

Tức khoảng 9.5 triệu VND tại thời điểm hiện tại.

Như vậy, trừ khi thời gian là miễn phí, việc mua 1 cuốn sách chỉ tốn một phần nhỏ số tiền bỏ ra, nhưng thời gian để đọc nó có thể tốn gấp hơn 20 lần.

Vậy nên hãy chắc chắn đọc được những thứ đáng giá. Đừng nghĩ đọc sách là rẻ (hơn ra rạp ăn bỏng ngô và xem film và...).

Vài cuốn sách đắt giá theo độ dày

Kết luận

Khi mua một cuốn sách, bạn sẽ phải trả thêm một chi phí không nhỏ để đọc nó.

Tham khảo

https://www.raptitude.com/2022/01/everything-must-be-paid-for-twice/

Hết.

Tuesday, 4 October 2022

Tạm biệt Ubuntu, chào Debian

Ubuntu là distro đầu tiên đưa mình vào thế giới Linux, thế giới không Windows, với phiên bản 8.04. Nó cũng đi cùng luôn sự nghiệp khi đa phần server đều dùng Ubuntu.

https://pymi.vn ra đời năm 2015, chạy trên Ubuntu 14.04, sau 3 lần upgrade

  • sang 16.04, thay toàn bộ Upstart init file bằng systemd
  • sang 18.04, thay Python2 bằng Python3

thì lần này, mình quyết định chuyển sang dùng Debian.

debian

Debian không mới, nó là distro mà chính Ubuntu dựa trên, chỉ có một cộng đồng rất lớn, không có công ty đứng sau.

Lý do vì ở phía server, ngày nay không có gì chỉ chạy trên Ubuntu mà ko chạy trên Debian cả.

Debian cũng không có câu chuyện đáng sợ về motd luôn gọi về server của Ubuntu để chạy quảng cáo. Mà nếu để ý, các docker file chính thức đều dùng Debian, điển hình như Python bullseye

Việc sử dụng server debian thì gần như không khác gì Ubuntu, cấu trúc thư mục vẫn vậy, apt vẫn vậy.

Không phải toàn màu hồng

  • năm 2021, đã từng thử cài debian trên desktop, mà lần bật lên đầu tiên bị lỗi window server (lightdm), nghỉ. Nếu còn trẻ, rảnh, thì có lẽ sẽ ngồi tìm hiểu tại sao, rồi fix, nhưng khi chỉ muốn có cái máy chạy được thì lại quay về Ubuntu 20.04.
  • vì một lý do nào đó, tải file vagrant box về dùng không đăng nhập được bằng tài khoản mặc định (vagrant:vagrant)? -> UPDATE: solved -> user root pass vagrant.

Tài liệu

Debian Admin handbook https://www.debian.org/doc/manuals/debian-handbook/

Kết luận

Dùng Debian cho server là một điều hoàn toàn hợp lý.

Happy hacking!