Category: Webserver

  • Sử dụng Nginx để truy cập tới một Private S3 Bucket

    Sử dụng Nginx để truy cập tới một Private S3 Bucket

    Bài toán

    Mình được giao nhiệm vụ phát triển một ứng dụng quản lý chi tiêu cho khách hàng. Thông tin các hoá đơn và ảnh trong ứng dụng sẽ được lưu trên S3. Khách hàng có yêu cầu có thể xem được ảnh lưu trên S3 bằng domain của họ thay vì bằng đường link trực tiếp từ S3. Hệ thống Backend của họ đang sử dụng Nginx với Python Flask và mong muốn không sử dụng đến dịch vụ CloudFront.

    Giải pháp

    Sau hồi nguyên cứu mình đã tìm ra giải pháp là có thể dùng Nginx để truy cập tới một private S3 bucket.

    Để có thể demo được giải pháp nên mình sẽ lược bỏ hệ thống cho nó đơn giản hơn so với hệ thống của khách hàng. Đầu tiên giả sử hệ thống trên AWS đã được cấu hình như bên dưới:

    • VPC(10.0.0.0/16) với public subnet và private subnet
    • VPC Endpoint cho s3
    • A static web on ECS Fargate with Nginx
    • 1 trang web tĩnh được triển khai trên dịch vụ ECS Fargate với việc dùng Nginx
    • 1 private S3 bucket để lưu ảnh của trang web.

    Alt Text

    Kết quả sau khi cấu hình xong chúng ta sẽ có 1 trang web như bên dưới. Nhưng hình ảnh mọi nguời thấy là hình ảnh được tải từ trên mạng. Alt Text

    Bây giờ mình sẽ cần thay thể ảnh trên mạng này với ảnh trên S3. Để làm được điều đó các bạn theo dõi tiếp bên dưới nhé. Alt Text

    Thiết lập Nginx và S3

    1. Thay đổi S3 bucket policy để chỉ cho phép lấy dữ liệu từ VPC Endpoint.

    {
        "Version": "2008-10-17",
        "Id": "PolicyForCloudFrontPrivateContent",
        "Statement": [
            {
                "Sid": "Access-to-specific-VPCE-only",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::demo-static-s3/*",
                "Condition": {
                    "StringEquals": {
                        "aws:sourceVpce": "vpce-0d92e50f230bc8070"
                    }
                }
            }
        ]
    }
    

    2. Tiếp theo là việc quan trọng nhất, chúng ta sẽ cần cấu hình Nginx để có thể tải ảnh từ private S3

    location ~^/image/(.+)$ {
            resolver 10.0.0.2;
            proxy_pass http://s3-ap-southeast-1.amazonaws.com/demo-static-s3/image/$1; 
    }
    
    • resolver: Địa chỉ IP của DNS server trong VPC mà mình đã tạo.

      Ví dụ, VPC của mình tạo có CIRD là 10.0.0.0/16. AWS sẽ dùng 5 IPs bên dưới cho các mục đích bên của họ và mình sẽ không thể sử dụng các IP đó.

      • 10.0.0.0: Network address.
      • 10.0.0.1: Reserved by AWS for the VPC router.
      • 10.0.0.2: Reserved by AWS. The IP address of the DNS server is the base of the VPC network range plus two. For VPCs with multiple CIDR blocks, the IP address of the DNS server is located in the primary CIDR. We also reserve the base of each subnet range plus two for all CIDR blocks in the VPC. For more information, see Amazon DNS server.
      • 10.0.0.3: Reserved by AWS for future use.
      • 10.0.0.255: Network broadcast address. We do not support broadcast in a VPC, therefore we reserve this address.

      => Resolver sẽ có giá trị là 10.0.0.2

      Tham khảo: https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html

    • proxy_pass: s3 link

      Định dạng: http://s3-ap-southeast-1.amazonaws.com/[main_bucket]/[sub_bucket]/$1

    3. Thay đổi dường dẫn của tải ảnh của trang web

    <div class="container">
        <h1>Hey there</h1>
        <img src="https://cleandevs.com/image/668c1d479e27bb8750823655c83a6c9bd90263f9_hq.jpg"/>
      </div>
    

    4. Cuối cùng mình sẽ deploy lại trang web lên dịch vụ ECS Fargate. Kết quả sẽ như hình bên dưới. Trang web đã hiển thị ảnh được tải từ private S3 bucket

    Alt Text

  • Cost-effective, High Availability Cassandra with AWS EKS and EC2 Spot instance.

    Cost-effective, High Availability Cassandra with AWS EKS and EC2 Spot instance.

    Mở đầu

    Cassandra hay Apache Cassandra, là một hệ thống quản lý cơ sở dữ liệu NoSQL, mã nguồn mở, miễn phí, phân tán dựa trên mạng ngang hàng P2P, hiện tại thường dùng dễ lưu trữ dữ liệu dưới dạng timeseries.

    Bản thân Cassandra đã có khả năng High availability với thiết kế no single point of failure và bản thân Cassandra cũng hỗ trợ việc mở rộng node một cách dễ dàng, vậy tại sao không mang sức mạnh của EC2 Spot Instance (chi phí rẻ cho khả năng tính toán lớn).

    Chúng ta lợi dụng một số tính năng sau của Cassandra để xử lý:

    • Data Center

      image

      • Trong đó data center sẽ đóng vai trò như một cụm node, Cassandra có thể live backups giữa các data center, data sẽ tự động copy async sang DC khác, khi một DC down các DC khác vẫn hoạt động bình thường
    • Seed nodes: Seed nodes sẽ là nơi các node mới connect và thông báo về việc chúng join cluster Seed node hoạt động như các điểm chung chuyển, các node sẽ trao đổi với các node seeds hơn các node khác, và các node này thường sẽ có các thông tin mới nhất và đầy đủ nhất, nhưng chúng sẽ gặp vấn đề overhead nên đừng sử dụng mọi node làm seeds.

    • Data replication: Cassandra lưu trữ dữ liệu trên nhiều node để đảm bảo tính toàn vẹn và fault tolerance (mình khá không thích dịch tiếng việt tự này, có thể dịch là khả năng chịu lỗi). Có 2 strategy: Simple và NetworkTopology, vì chúng ta dự định sử dụng data center nên hãy chọn NetworkTopology

    Như vậy về mặt lý thuyết chúng ta có thể xử lý được toàn bộ vấn đề, hãy mapping chúng với, K8S và AWS thậm chí hoàn toàn có thể xử lý được với trường hợp sử dụng Spot Instance.

    image

    Chúng ta sẽ sử dụng luôn khái niệm Availability Zone của AWS cho tương ứng với data center. Như vậy sẽ có 1 Statefulset cài đặt Cassandra, 1 Service để expose với mỗi DC.

    Cài đặt nào

    Thực ra script đã được chuẩn bị ở đây rồi.

    Mình sẽ giải thích một vài điểm cần chú ý

    Chúng ta add label cho các pod, việc này để các service có thể chọn được các pod của cassandra

      template:
        metadata:
          labels:
            app: cassandra
            interface: cassandraa
    

    Chọn node để cài đặt cassandra, chúng ta có thể dùng các key khác nhưng để cho tiện thì mình dùng tạm key này, việc này đảm bảo node của DC được cài đặt theo AZ của AWS đúng tinh thần High availability

          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                    - ap-southeast-1a
    

    Cassandra seeds node, node đầu tiên của các statefulset được chọn làm seed, ở đây mình xử lý dùng 1 service cassandra thay vì dùng 3 service cho 3 AZ (một điểm nho nhỏ khác biệt), việc này không ảnh hưởng lắm.

      - name: CASSANDRA_SEEDS
        value: cassandraa-0.cassandra.thingsboard.svc.cluster.local,cassandrab-0.cassandra.thingsboard.svc.cluster.local,cassandrac-0.cassandra.thingsboard.svc.cluster.local
    

    Chúng ta không cần tất cả các seed cùng một lúc, nên ngay cả khi seed down thì node vẫn hoạt động bình thường.

    Ở các pod sử dụng cassandra này thì cần chỉ rõ DC nào của Cassandra để kết nối đến, ở đây mình đang cài đặt Thingsboard nên sẽ thêm environment variable sau, tất nhiên sẽ phải xử lý tách application của bạn ra 3 statefulset hoặc deployment khác nhau:

      - name: CASSANDRA_LOCAL_DATACENTER
        value: ap-southeast-1a
    

    Tada

    2021-08-17 18:08:36
    2021-08-17 11:08:36,628 [main] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
    2021-08-17 18:08:52
    2021-08-17 11:08:52,732 [main] INFO  c.d.o.d.internal.core.ContactPoints - Contact point cassandra:9042 resolves to multiple addresses, will use them all ([cassandra/10.0.1.112, cassandra/10.0.2.149, cassandra/10.0.1.150])
    2021-08-17 18:08:53
    2021-08-17 11:08:53,734 [main] INFO  c.d.o.d.i.c.DefaultMavenCoordinates - DataStax Java driver for Apache Cassandra(R) (com.datastax.oss:java-driver-core) version 4.10.0
    2021-08-17 18:08:54
    2021-08-17 11:08:54,956 [Thingsboard Cluster-admin-0] INFO  c.d.o.d.internal.core.time.Clock - Could not access native clock (see debug logs for details), falling back to Java system clock
    2021-08-17 18:08:56
    2021-08-17 11:08:56,621 [Thingsboard Cluster-admin-0] WARN  c.d.o.d.i.c.l.h.OptionalLocalDcHelper - [Thingsboard Cluster|default] You specified ap-southeast-1b as the local DC, but some contact points are from a different DC: Node(endPoint=cassandra/10.0.1.112:9042, hostId=a56560a6-1274-43f9-b72e-d8b1e7b33bf8, hashCode=6a745db0)=ap-southeast-1a, Node(endPoint=cassandra/10.0.1.150:9042, hostId=c7f9bc1c-c066-40d6-9def-7fbe58af90bb, hashCode=2c4f4fec)=ap-southeast-1a; please provide the correct local DC, or check your contact points
    

    Nếu dòng log cuối gây confuse thì hãy sử dụng các sevice riêng biệt nhé

    Happy Coding

  • Docker thường thức – Phần 1: Giới thiệu về Containers, Virtual machines và Docker

    Docker thường thức – Phần 1: Giới thiệu về Containers, Virtual machines và Docker

    Docker thường thức – Phần 1: Giới thiệu về Containers, Virtual machines và Docker

    Dù bạn là một Kỹ sư phần mềm hay một nhà Khoa học dữ liệu, dù bạn đang lập trình Web hay đang lập trình Mobile,… thì ít nhiều đã nghe nói về Docker. Theo một thống kê của Stack Overflow trong năm 2020; Docker xếp hạng thứ 2 trong số các nền tảng được yêu thích nhất, đồng thời dẫn đầu trong số các nền tảng mà các developers muốn tìm hiểu nhất. Như vậy có thể thấy, Docker đang dần trở thành xu thế tất yếu mà bất kỳ ai tham gia vào ngành công nghiệp công nghệ thông tin cũng nên tìm hiểu, để biết cách sử dụng nó, áp dụng nó, và biến nó trở thành công cụ hữu ích cho các dự án.

    Chuỗi bài viết về chủ đề Docker của tôi nhằm mang lại cho người đọc mới bắt đầu tìm hiểu về docker có những cái nhìn tổng quan, cơ bản nhất xung quanh công nghệ đang là hot trend này, từ đó họ có thể dễ dàng chuyển sang các chủ đề chuyên sâu hơn mà phù hợp với dự án của mỗi người.

    Trong phần 1, mục đích của bài viết này nhằm mang lại cho bạn đọc các khái niệm cơ bản liên quan đến Docker, chúng sẽ là những thứ mà bạn nhất định phải biết nếu muốn đi sâu vào công nghệ này, ngoài những giải thích bằng lời, tôi cũng cung cấp các hình ảnh trực quan cùng với các ví dụ dễ hiểu.

    Công nghệ đến rồi công nghệ đi, nhưng cái nhìn sâu sắc là ở lại trong ta mãi mãi!

    Danh mục nội dung

    Tại sao lại cần Docker?

    Trước khi đi vào các khái niệm cụ thể, tôi muốn đưa bạn qua một ví dụ để bạn có thể hình dung ra Docker hữu ích như thế nào. Giả sử như bạn đang xây dựng một hệ thống end-to-end với tech stack bao gồm: web server sử dụng NodeJs, database sử dụng MongoDB, messaging system sử dụng Redis, và một orchestration tool.

    Cách tiếp cận truyền thống

    Với các cách tiếp cận truyền thống (mà không sử dụng Docker), chúng ta sẽ gặp phải nhiều vấn đề với tech stack nói trên – chúng là các components/services khác nhau trong hệ thống cần xây dựng.

    • Đầu tiên là khả năng tương thích (compatibility) với hệ điều hành nền tảng (underlying os), chúng ta phải đảm bảo rằng tất cả các services khác nhau nói trên tương thích với OS mà chúng ta đang sử dụng. Trong trường hợp tồn tại một service trong tech stack đó có version mà chúng ta định sử dụng không tương thích với OS, thì chúng ta lại phải tìm kiếm OS khác tương thích với tất cả các services để phù hợp với nhu cầu của hệ thống ta muốn xây dựng.

    • Thứ 2 là chúng ta phải kiểm tra khả năng tương thích giữa các services khác nhau này với các libraries và các dependencies trên OS. Sẽ có vấn đề nếu như một service yêu cầu một phiên bản của dependent library, trong khi đó một service khác lại yêu cầu một phiên bản khác của dependent library đó.

    Kiến trúc của hệ thống sẽ thay đổi qua thời gian, chúng ta sẽ phải upgrade lên các phiên bản mới hơn của các thành phần này. Và mỗi lần có một thứ gì đó cần thay đổi, chúng ta lại phải kiểm tra khả năng tương thích của nó với underlying infrastructure (OS, libraries, dependencies,…). Hơn nữa, mỗi khi có một developer mới onboard, chúng ta sẽ gặp khó khăn khi set up môi trường làm việc cho developer đó.

    The Matrix from Hell !!

    Tất cả những vấn đề nói trên dẫn đến việc developing, building và shipping hệ thống gặp nhiều khó khăn.

    Cách tiệp cận sử dụng Docker

    Như vậy, chúng ta cần một cái gì đó có thể giúp chúng ta giải quyết vấn đề về tính tương thích giữa các thành phần này với OS, chúng ta cũng cần một thứ gì đó có thể giúp chúng ta sửa đổi hoặc thay đổi các thành phần này mà không ảnh hưởng đến các thành phần khác trong hệ thống. Docker đã giải quyết tốt cho chúng ta.

    The services with containers

    Với Docker, ta có thể chạy mỗi component trong một container riêng biệt với các dependencies và các libraries của riêng nó, tất cả trên một VM (Virtual machine) và một OS nhưng tách biệt môi trường. Chúng ta chỉ phải build cấu hình Docker một lần và các developer có thể bắt đầu với một lệnh docker run đơn giản, không phân biệt underlying operating system mà chúng ta đang chạy. Tất cả những cái chúng ta cần là có Docker đã được cài đặt.

    Containers vs Virtual Machines

    Cả Containers và Virtual Machines (VMs) đều giống nhau ở mục tiêu, đó là: cô lập môt ứng dụng và các dependencies của nó thành một đơn vị khép kín (self-contained unit) mà có thể chạy ở bất cứ đâu, bất cứ môi trường nào.

    Hơn nữa, các Containers và VMs loại bỏ nhu cầu về phần cứng vật lý, cho phép sử dụng hiệu quả hơn các tài nguyên máy tính, cả về tiêu thụ năng lượng và hiệu quả chi phí.

    Sự khác biệt chính giữa Containers và VMs là ở cách tiếp cận kiến trúc của chúng.

    Virtual machines

    VMs về cơ bản là một sự mô phỏng của một máy tính thực, thực thi các chương trình giống như một máy tính thực.

    VMs chạy trên một máy vật lý sử dụng cái gọi là hypervisor. Một hypervisor chạy trên một host machine hoặc trên một bare-metal.

    • Một hypervisor là một phần của software, firmware hoặc hardware mà VMs chạy trên đó. Bản thân các hypervisors chạy trên một máy tính vật lý, được gọi là host machine. Host machine cung cấp các tài nguyên cho VMs bao gồm RAM và CPU. Các tài nguyên này được phân chia giữa các VMs và có thể được phân phối khi bạn cảm thấy phù hợp. Vì vậy, nếu một VM đang chạy một ứng dụng cần nhiều tài nguyên hơn thì bạn có thể phân bổ nhiều tài nguyên hơn cho VM đó so với các VM khác đang chạy trên cùng một host machine.

    • VM đang chạy trên một host machine thường được gọi là guest machine. Guest machine này chứa ứng dụng và cả những thứ khác nó cần để chạy ứng dụng đó. Nó chiếm hữu toàn bộ phần cứng được ảo hóa của riêng nó, bao gồm virtualized network adapters, storage, và CPU,… và nó cũng có một guest operating system của riêng nó. Nhìn từ bên trong, guest machine hoạt động riêng biệt với các tài nguyên chuyên dụng dành cho nó. Nhìn từ bên ngoài, nó là một máy ảo – chia sẻ tài nguyên được cung cấp bởi host machine.

    Như đã đề cập ở trên, một guest machine có thể chạy trên một hosted hypervisor hoặc trên một bare-metal hypervisor. Có một vài khác biệt quan trọng giữa chúng:

    • Đầu tiên, một hosted hypervisor chạy trên OS của một host machine. Lấy ví dụ, một máy tính đang chạy OSX có thể có một VM được cài đặt trên OS đó. VM không có quyền truy cập trực tiếp vào hardware, nó phải thông qua OS của host machine. Lợi ích của hosted hypervisor đó là underlying hardware đóng vai trò ít quan trọng. OS của máy chủ chịu trách nhiệm về các hardware drivers thay vì chính hypervisor, và do đó có khả năng tương thích phần cứng tốt. Mặc khác, tầng trung gian này (OS của máy chủ) giữa hardware và hypervisor tạo ra nhiều tài nguyên hơn, làm giảm performance của VM.

    • Một bare-metal hypervisor giải quyết vấn đề hiệu năng nói trên bằng cách cài đặt và chạy ngay trên hardware của host machine. Vì nó giao tiếp trực tiếp với phần cứng nên nó không cần OS của máy chủ để chạy. Trong trường hợp này, thứ đầu tiên được cài đặt trên máy chủ đó là hypervisor. Không giống như hosted hypervisor, một bare-metal hypervisor có device drivers của riêng nó và tương tác trực tiếp với từng thành phần cho bất kỳ tác vụ cụ thể nào. Điều này dẫn đến performance, scalability, và stability tốt hơn. Sự đánh đổi ở đây là khả năng tương thích phần cứng bị hạn chế bởi vì hypervisor chỉ có thể có rất nhiều device drivers được tích hợp trong đó.

    Sau tất cả những gì đã nói về hypervisor, bạn có thể sẽ hỏi rằng tại sao chúng ta lại cần thêm một layer "hypervisor" giữa VM và host machine ? Câu trả lời đó là vì VM có một virtual OS của riêng nó, hypervisor đóng vai trò thiết yếu trong việc cung cấp cho VMs một platform để quản lý để thực thi hệ điều hành khách này. Nó cho phép các host computers chia sẻ tài nguyên của chúng tới các VMs đang chạy với tư cách là guest trên chúng.

    Virtual machines

    Như bạn có thể thấy trên diagram, hypervisor đóng gói virtual hardware, kernel và user space cho mỗi VM mới.

    Containers

    Containers có một lịch sử lâu đời trong lĩnh vực điện toán. Không giống như hypervisor virtualization, nơi mà có một hoặc nhiều VMs độc lập chạy ảo trên physical hardware qua một layer trung gian; thay vào đó, containers chạy trong user space ở trên kernel của OS. Do đó, container virtualization thường được gọi là ảo hóa cấp OS. Công nghệ container cho phép nhiều phiên bản user space độc lập được chạy trên một máy chủ duy nhất.

    Do trạng thái của chúng là guest của OS, nên các containers đôi khi được xem là kém linh hoạt hơn: chúng thường chỉ có thể chạy cùng hệ điều hành hoặc hệ điều hành khách tương tự trên máy chủ. Lấy ví dụ: bạn có thể chạy Redhat Enterprise Linux trên một máy chủ Ubuntu, nhưng bạn không thể chạy Microsoft Windows trên máy chủ Ubuntu. Containers cũng được coi là kém an toàn hơn so với sự cô lập hoàn toàn của hypervisor virtualization.

    Bất chấp những hạn chế này, các containers đã được triển khai dưới nhiều user cases khác nhau. Chúng phổ biến cho việc triển khai hyperscale của các dịch vụ multi-tenant, cho lightweight sandboxing,… bất chấp những lo ngại về bảo mật của chúng.

    Các công nghệ container gần đây bao gồm OpenVZ, Solaris Zones và Linux containers như lxc. Sử dụng các công nghệ mới này, containers giờ đây có thể được xem như là một máy chủ hoàn chỉnh theo đúng nghĩa của chúng thay vì chỉ là môi trường thực thi. Trong trường hợp của Docker, vì có các features hiện đại của Linux kernel, như là control group và namespaces –> các containers có sự độc lập mạnh mẽ, network và storage stacks của riêng chúng, cũng như khả năng quản lý tài nguyên để cho phép sự tồn tại thân thiện của nhiều containers trên cùng một máy chủ.

    Mặc dù các containers trước đây đã không đạt được large-scale adoption. Một phần lớn của vấn đề này có thể nằm ở độ phức tạp của chúng: các containers có thể phức tạp, khó để set up, khó để quản lý và tự động hóa. Docker nhằm mục đích thay đổi điều đó.

    Containers

    Tóm lại, một khác biệt lớn giữa containers và VMs đó là các containers share kernel của máy chủ với các containers khác.

    Containers vs VMs

    Dưới đây là một sự so sánh những điểm khác biệt chính giữa VMs và Containers.

    Containers vs VMs

    Ở bên phải hình trên, trong trường hợp của Docker, ta có underlying hardware infrastructure, OS ở phía trên và Docker được cài đặt trên OS, Docker sau đó quản lý các containers – chúng hoạt động cùng với các libraries và dependencies.

    Trong trường hợp của VMs, ở phía bên trái, ta có Hypervisor ở trên hardware và sau đó là VMs ở trên chúng. Và như bạn nhìn thấy, mỗi VMs có OS riêng bên trong nó, sau đó là các libs và deps rồi đến Application –> việc sử dụng các tài nguyên phần cứng trở nên lớn hơn khi có nhiều virtual operating systems đang chạy. VMs cũng tiêu thụ không gian đĩa lớn hơn vì mỗi VM khá nặng – thường lên đến hàng GB, trong khi đó docker containers nhẹ hơn – thường chỉ đến hàng MB –> điều này cho phép Docker container khởi động nhanh hơn – thường chỉ trong vài giây, trong khi đó các VMs sẽ mất khoảng vài phút để khởi động vì nó cần khởi động toàn bộ cả Operating System.

    Một điều quan trọng cần lưu ý là Docker có ít sự cô lập (isolation) hơn vì có nhiều tài nguyên được chia sẻ giữa các containers, như Kernel. Trong khi đó, VMs có sự cô lập hoàn toàn với nhau vì chúng không dựa trên underlying os hay kernel.

    Mặc dù có sự khác biệt nhất định giữa Container và VM, nhưng sự kết hợp giữa chúng có thể mang lại sự hữu ích nếu biết cách phối hợp chúng hợp lý.

    Containers and VMs

    Khi bạn có môi trường lớn với hàng ngàn containers chạy trên hàng ngàn docker host, bạn sẽ thường thấy các containers được cung cấp trên các virtual docker host. Bằng cách này, chúng ta có thể tận dụng được ưu điểm của cả 2 công nghệ, chúng ta có thể sử dụng virtualization để dễ dàng kiểm soát các docker host theo nhu cầu, đồng thời tận dụng Docker để dễ dàng kiểm soát các ứng dụng và scale chúng theo nhu cầu.

    Giới thiệu về Docker

    Đến đây thì chắc hẳn nhiều bạn đọc đặt câu hỏi, vậy tóm lại Docker là gì? Tôi sẽ trả lời câu hỏi này ngay sau đây.

    Docker là một open-source engine, tự động hóa việc triển khai các ứng dụng vào các containers. Nó được viết bởi một team tại Docker, Inc và được họ phát hành theo giấy phép Apache 2.0.

    Vậy Docker có gì đặc biệt? Docker thêm một công cụ triển khai ứng dụng trên môi trường thực thi container đươc ảo hóa. Nó được thiết kế để cung cấp môi trường nhẹ và nhanh chóng để chạy code của bạn, cũng như workflow hiệu quả để đưa code từ laptop –> môi trường test –> môi trường production.

    Docker cực kỳ đơn giản. Thật vậy, bạn có thể bắt đầu với Docker trên một máy chủ minimal không chạy gì ngoài một Linux kernel tương thích và một Docker binary. Nhiệm vụ của Docker là cung cấp:

    Một cách dễ dàng và nhẹ nhàng để mô hình hóa thực tế:

    Docker rất nhanh, bạn có thể Dockerize ứng dụng của mình trong vài phút. Docker dựa trên mô hình copy-on-write nên việc thực hiện các thay đổi đối với ứng dụng của bạn cũng cực kỳ nhanh chóng.

    Sự phân chia logic giữa các tác vụ:

    Với Docker, các Developers quan tâm về các ứng dụng của họ chạy trong các containers và các Operations quan tâm đến việc quản lý các containers. Docker được thiết kế để tăng cường tính nhất quán bằng cách đảm bảo môi trường mà các developers viết code khớp với môi trường mà các ứng dụng được triển khai thực tế. Điều này làm giảm rủi ro: "worked in dev, now an ops problem".

    Vòng đời phát triển nhanh và hiệu quả:

    Docker nhằm mục đích giảm thời gian trong chu kỳ giữa code được viết, code được kiểm tra, code được triển khai và được sử dụng. Nó cũng làm cho các ứng dụng của bạn trở nên khả chuyển, dễ để build, và dễ cộng tác.

    Khuyến khích kiến trúc hướng dịch vụ (SOA):

    Docker cũng khuyến khích các kiến trúc service-oriented và microservices. Docker recommends rằng mỗi container nên chạy một process hoặc một application duy nhất. Điều này thúc đẩy mô hình ứng dụng phân tán, trong đó một ứng dụng hoặc dịch vụ được đại diện bởi một loạt các containers được kết nối với nhau. Điều này giúp dễ dàng distribute, scale, debug và introspect các ứng dụng.

    Các khái niệm cơ bản

    Tôi sẽ không nhắc lại khái niệm về VMs và Containers nữa; mà thay vào đó, tôi sẽ đề cập đến 3 khái niệm quan trọng khác mà bạn sẽ gặp thường xuyên khi làm việc với Docker.

    Docker image:

    Docker image giống như các blueprints, chúng là cá immutable master image được sử dụng để tạo ra các containers hoàn toàn giống nhau.

    Một docker image chứa Dockerfile, các libraries, và mã nguồn ứng dụng bạn cần chạy, tất cả chúng được bundled lại với nhau.

    Dockerfile:

    Dockerfile là một tệp chứa các lệnh chỉ dẫn cách Docker nên build image của bạn.

    Dockerfile đề cập đến một base image, đươc sử dụng để xây dựng initial image layer. Các base images phổ biến như python, ubuntu, redis…

    Các layers bổ sung sau đó có thể được xếp chồng lên các base image layers, theo các lệnh chỉ dẫn trong Dockerfile. Ví dụ, một Dockerfile cho một ứng dụng học máy có thể yêu cầu Docker thêm Numpy, Pandas, và Scikit-learn trong một layer trung gian.

    Cuối cùng, một thin layer có thể được xếp chồng lên trên các layers khác theo Dockerfile code.

    Container Registry:

    Nếu bạn muốn người khác có thể tạo các containers từ image của bạn tạo ra, bạn cần gửi image đó tới một container registry. Docker hub là registry lớn nhất và là mặc định.

    Một phép ẩn dụ

    Để khép lại phần 1, tôi đưa ra một phép ẩn dụ để minh họa các khái niệm vừa nói ở trên, bằng cách sử dụng hoạt động Nấu ăn, cụ thể là việc làm một chiếc bánh Pizza.

    Khi nấu một món ăn, ta cần có công thức cho món ăn đó, công thức giống như một Dockerfile. Nó cho bạn biết cần phải làm gì để đạt được mục tiêu. Các thành phần của món ăn giống như các layersa, bạn đã có vỏ bánh, nước sốt và pho-mát cho chiếc bánh pizza này.

    Hãy nghĩ về công thức và các thành phần được kết hợp lại thành một công cụ làm bánh pizza. Nó giống như Docker image.

    Công thức (Dockerfile) cho chúng ta biết những gì chúng ta sẽ làm. Dưới đây là kế hoạch:

    • Lớp vỏ được định dạng sẵn và immutable. Nó giống như một basic ubuntu parent image. Đây là bottom layer và được xây dựng đầu tiên.

    • Sau đó bạn sẽ thêm một ít pho mát. Thêm second layer này vào bánh pizza giống như cài đặt thêm một thư viện bên ngoài – ví dụ Numpy.

    • Sau đó bạn rắc thêm một ít húng quế. Nó giống như mã trong một tệp bạn viết để chạy ứng dụng.

    Được rồi, chúng ta hãy bắt đầu nấu ăn:

    • Lò nướng bánh pizza giống như Docker platform. Bạn đã lắp đặt lò nướng vào nhà khi chuyển đến để có thể chế biến mọi thứ với nó. Tương tự như vậy, bạn đã cài đặt Docker vào máy tính của mình để có thể "nấu" các containers.

    • Bạn khởi động lò nướng bằng cách xoay núm. Lệnh Docker run image_name giống như núm của bạn – nó tạo và khởi động container của bạn.

    • Bánh pizza đã chín giống như một Docker container đang chạy.

    • Ăn pizza giống như việc sử dụng ứng dụng.

    Giống như làm bánh pizza, tạo một ứng dụng trong một Docker container mất một số công việc, nhưng cuối cùng bạn đã có một thứ tuyệt vời!

    Lời kết: Bài viết đến đây cũng khá dài. Trong Phần 2, tôi sẽ đi sâu vào kiến trúc, các thành phần của Docker, và không phải chờ đợi lâu, ngay trong phần 2 tôi cũng sẽ giúp bạn đọc bắt đầu viết các lệnh đầu tiên với Docker.

    Tài liệu tham khảo

    [1]: James Turnbull, The Docker Book (2018)

    [2]: Preethi Kasireddy, A Beginner-Friendly Introduction to Containers, VMs and Docker (2016)

    [3]: Jeff Hale, Learn Enough Docker to be Useful (2019)

    [4]: Mumshad Mannambeth, Docker for the Absolute Beginner – Hands On – DevOps, Section 1 – Docker overview.

    Author

    Hà Hữu Linh

    [email protected]

  • Mô phỏng AWS Lambda & API Gateway bằng Serverless Offline

    Mô phỏng AWS Lambda & API Gateway bằng Serverless Offline

    Khi phát triển ứng dùng bằng AWS Lambda không phải lúc nào chúng ta cũng có thể phát triển trực tiếp trên AWS được. Do đó việc giả lập môi trường AWS để có thể chạy được Lambda và API Gateway là cần thiết. Nó không chỉ giúp chúng ta có thể học mà còn giúp cho quá trình phát triển nhanh hơn. Trong bài viết này tôi sẽ hướng dẫn các bạn giả lập AWS Lambda và API Gateway bằng Serverless Offline

    Các công cụ cần thiết

    Trước tiên bạn cần cài đặt các tool cần thiết, bạn có thể tham khảo hướng dẫn cài đặt trong các bài viết sau:

    Bạn có thể dùng lệnh sau để cài serverless

    hieunv@HieuNV lambda % yarn global add serverless
    yarn global v1.22.0
    [1/4] ?  Resolving packages...
    [2/4] ?  Fetching packages...
    [3/4] ?  Linking dependencies...
    [4/4] ?  Building fresh packages...
    success Installed "[email protected]" with binaries:
          - serverless
          - slss
          - sls
    ✨  Done in 14.23s.
    

    Tạo một project mới

    • Tạo project với yarn
    hieunv@HieuNV hieunv % mkdir lambda
    hieunv@HieuNV hieunv % cd lambda
    hieunv@HieuNV lambda % yarn init
    yarn init v1.22.0
    question name (lambda):
    question version (1.0.0):
    question description:
    question entry point (index.js):
    question repository url:
    question author:
    question license (MIT):
    question private:
    success Saved package.json
    ✨  Done in 3.53s.
    
    • Cài đặt serverless-offline
    hieunv@HieuNV lambda % yarn add serverless-offline -D
    
    • Cài đặt serverless-python-requirements để viết lambda handler bằng python
    hieunv@HieuNV lambda % yarn add serverless-python-requirements -D
    

    Cấu hình serverless.yml

    serverless.yml

    service: lambda
    
    frameworkVersion: '>=1.1.0 <2.0.0'
    
    provider:
      name: aws
      runtime: python3.7
    custom:
      serverless-offline:
        port: 4000
    plugins:
      - serverless-offline
      - serverless-python-requirements
    

    Cấu hình lambda handler đầu tiên trong serverless.yml

    Chúng ta tạo một Rest API sử dụng lambda bằng cách thêm đoạn sau vào file serverless.yml

    functions:
      test:
        handler: src.api.test.lambda_handler
        events:
          - http:
              method: get
              path: api/test
              cors: true
    

    Ở đây chúng ta tạo ra một Rest API với phướng thức GET và path /api/test. Các bạn nhìn thấy handler: src.api.test.lambda_handler đúng không. Đây là cấu hình hàm lamda sẽ được gọi bởi API Gateway

    Viết code cho lambda handler

    src/api/test.py

    import json
    
    
    def lambda_handler(event, context):
        headers = {"Access-Control-Allow-Origin": "*", "Accept": "application/json"}
        return {
            "statusCode": 200,
            "headers": headers,
            "body": json.dumps({"status": "success", "data": {}}),
        }
    

    Tạo script để run server

    Thêm đoạn sau vào package.json

        "scripts": {
            "start": "sls offline start"
        },
    

    Giờ thì chạy thôi nào các thanh niên

    hieunv@HieuNV lambda % yarn start
    yarn run v1.22.0
    $ sls offline start
    Serverless: Starting Offline: dev/us-east-1.
    
    Serverless: Routes for test:
    Serverless: GET /api/test
    Serverless: POST /{apiVersion}/functions/lambda-dev-test/invocations
    
    Serverless: Offline [HTTP] listening on http://localhost:4000
    Serverless: Enter "rp" to replay the last request
    

    Dùng Postman để call api vừa tạo nhé:

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết có thể giúp các bạn tiếp tục học và làm việc cùng với AWS Lambda và API Gateway trong các dự án của mình.

  • Sử dụng nhiều phiên bản node cùng lúc

    Sử dụng nhiều phiên bản node cùng lúc

    Khi sử dụng node nhiều bạn nghĩ rằng chỉ cần sử dụng phiên bản LTS mới nhất là đủ rồi. Tuy nhiên nếu bạn phải tham gia nhiều dự án cùng lúc (như mình chẳng hạn) thì mới thấy là chẳng dễ gì các dự án sống chung với nhau được. Nói vậy để thấy rằng dùng có thể dùng nhiều phiên bản cùng lúc là cần thiết. Trong bài viết này tôi sẽ hướng dẫn các bản cách sử dụng nhiều phiên bản node cùng lúc.

    nvm là gì?

    nvm là viết tắt của Node Version Manager. Như đã nói ở trên bài viết này sẽ hướng dẫn cách các bạn có thể sử dụng nhiều phiên bản node cùng lúc. Vậy thì nm là cần thiết nhỉ.

    Để cài đặt nvm bạn có thể sử dụng lệnh sau:

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
    
    wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
    

    Tuỳ thuộc vào hệ điều hành bạn đang sử dụng thì cần thêm đoạn sau vào ~/.bash_profile hoặc ~/.profile hoặc ~/.bashrc hoặc ~/.zshrc. Mình đang sử dụng zsh nên mình sẽ thêm vào ~/.zshrc

    export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    

    Kiểm tra xem nvm đã được cài thành công chưa

    nvm -v
    

    Giờ thì cài đặt phiên bản node mà muốn sử dụng thôi nào

    Cài đặt phiên bản mới nhất:

    nvm install node
    

    Cài đặt phiên bản xác định mà bạn muốn

    nvm install 10.10.0
    

    Để chuyển qua phiên bản node bản muốn sử dụng

    nvm use v13.9.0
    

    v13.9.0 là tên phiên bản các bạn nhìn thấy sau khi sử dụng nvm ls như ở trên.

    Chi tiết cách sử dụng nvm thì các bạn có thể tham khảo hướng dẫn ở link sau

    https://github.com/nvm-sh/nvm
    
  • Authorization and JWT

    Authorization and JWT

    Thực ra bài này chỉ muốn viết về JWT thôi, nhưng tiện thì sẽ nói về các loại Authorization luôn.

    Authorization và Authentication

    2 cái này cũng khác nhau:

    • Authentication
      • Được sử dụng bởi một Server khi mcần biết chính xác ai đang truy cập thông tin hoặc trang web của họ.
      • Được sử dụng bởi Client khi Client cần biết rằng máy chủ là hệ thống mà nó tuyên bố.
      • Trong Authentication, Client hoặc Machine phải chứng minh danh tính của mình với Server hoặc Client. Thông thường, xác thực bởi một máy chủ đòi hỏi phải sử dụng tên người dùng và mật khẩu. Các cách khác để xác thực có thể thông qua thẻ, quét võng mạc, nhận dạng giọng nói và dấu vân tay. Xác thực bởi khách hàng thường liên quan đến việc máy chủ cấp chứng chỉ cho khách hàng trong đó một bên thứ ba đáng tin cậy như Verisign hoặc Thawte nói rằng máy chủ đó thuộc về thực thể (như ngân hàng) mà khách hàng mong đợi. Xác thực không xác định những nhiệm vụ mà cá nhân có thể làm hoặc những tập tin cá nhân có thể nhìn thấy. Xác thực chỉ xác định và xác minh người hoặc hệ thống là ai.

    Xác thực, quá trình này xác định bạn là ai trong hệ thống. Ví dụ: login là một quá tình xác thực, bạn gửi username/password lên hệ thống, hệ thống sẽ thẩm tra nhận dạng của bạn (bằng username/password hoặc thêm một số factor nữa như trắc sinh học, token,… trong multi-factor authentication).

    • Authorization
      • Xác minh, cái này thường sau xác thực, để kiểm tra xem bạn có quyền truy cập tài nguyên không, ví dụ bạn nói với server tôi là A tôi cần truy cập tài nguyên B bằng một request:
      GET /b HTTP/1.1
      Host: example.com
      Authorization: Bearer i_am_A
      
      Như vậy server cần xác định Bearer i_am_A có phải là Authorization hợp lệ hay không và có quyền truy cập GET /b hay không.
      • Gần như 2 quá trình trên sẽ không khác nhau với các website hay application, vì vậy việc hiểu rõ khá là hữu ích.
      • Authorization cũng thường lấy kết quả của Authentication (hoặc một dẫn xuất từ việc Authentication) để xác nhận. Ví dụ sau khi đăng nhập bạn sẽ được Server gán cho một giá trị nào đó vào Session để xác nhận bạn đã đăng nhập, và dùng giá trị đó cho việc Authorization. Có một vài trường hợp khác như Basic Authentication bạn sẽ gửi Base64 của chuỗi username:password trong Authorization header, thì gần như sẽ ko thấy Authentication đâu cả.

    Vì vậy cũng có vài loại Authorization khác nhau:

    • Basic (RFC 7617, base64-encoded credentials. Đơn giản là truyền chuỗi Base64 của chuỗi username:password)
    • Bearer (RFC 6750, bearer tokens để access các resource được bảo vệ bởi OAuth 2.0)
    • Digest (RFC 7616)
    • HOBA (RFC 7486, HTTP Origin-Bound Authentication, digital-signature-based),
    • Mutual (RFC 8120,
    • AWS4-HMAC-SHA256 dùng cho AWS SDK và AWS API.

    Hiện tại thì OAuth 2.0 rất phổ biến hơn nữa nảy sinh ra nhu cầu chống làm giả token được tạo ra bởi server, đến đây thì mới xuất hiện JWT.

    JWT

    Thôi đi copy định nghĩa vậy: JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties. JWT.IO allows you to decode, verify and generate JWT.

    Hình dung như này, khi bạn vào một trang web như TIKI chẳng hạn, bạn đăng nhập với Facebook hoặc tài khoản cá nhân. Vậy khi bạn đăng nhập với Facebook, TIKI sẽ kết nối đến Facebook GraphAPI với Facebook token mà bạn vừa đưa cho TIKI để verify. Khi đó bạn sẽ nhận được token từ TIKI để truy cập các resource.

    Structure

    JWT gồm 3 phần:

    • Header: Hay còn gọi là JOSE header, đề cập đến loại JWT (JWEJWS)và kiểu mã hóa hay thuật toán mã hóa, ở hình trên là dùng RSA Signature with SHA-256
    • Payload: hay còn gọi là claims, là một đoạn data public có trong JWT, JWT thường có một vài data có thể public như
      • sub: Username hoặc UserId
      • iat: issue at, token được tạo ra lúc nào
      • exp: expire at, token hết hạn khi nào
      • iss: issuer, ai là người tạo token này ra. Ngoài ra còn có jti(JWT ID), aud(Audience), nbf(Not before), mấy cái tên này thì có thể tìm thấy ở đây này, cái này được gọi là Public Claims. Private Claims thì những cái bạn define thôi : ).
    • Signature: là phần quan trọng nhất, thì cái này lại phụ thuộc vào JOSE Header để mã hóa, tức là dùng cái thuật toán ở trên ấy, mã hóa dùng security factor như nào thì lại phụ thuộc vào JWE hay JWS.

    Xong xuôi, chúng ta sẽ dùng process base64url encode cả 3 phần rồi nối với nhau bằng dấu chấm (.).

    JWT vs Thế giới

    So với các web token khác như SWT hoặc SAML, JWT đơn giản hơn nhiều vì nó dựa trên JSON nên dễ hiểu hơn XML. Nếu chúng ta mã hóa JSON, nó sẽ trở nên nhỏ hơn kích thước so với SAML, giúp việc chuyển qua môi trường HTML và HTTP dễ dàng hơn. Về bảo mật, SWT sử dụng một khóa duy nhất, trong khi cả JWT và SAML đều sử dụng cặp khóa chung và khóa riêng để xác thực tốt hơn. Nhìn chung, JWT được sử dụng ở quy mô Internet. Điều này có nghĩa là việc xử lý trên các thiết bị của người dùng dễ dàng hơn, có thể là máy tính xách tay hoặc thiết bị di động. Ngoài khả năng tự động hóa, Mã thông báo Web JSON là một cách tuyệt vời và an toàn để truyền dữ liệu giữa nhiều bên. Việc JWT có chữ ký giúp mọi người dễ dàng xác định người gửi thông tin hơn. Tất cả bạn cần là chìa khóa chính xác.

    Một bài viết khác sẽ nói về một loại JWT của Auth0. Hãy đón chờ : )

  • Tối ưu Nginx & PHP-fpm cho lượng truy cập lớn

    Tối ưu Nginx & PHP-fpm cho lượng truy cập lớn

    PHP hiện tại là ngôn ngữ được triển khai rộng rãi trên Internet.

    Tuy nhiên PHP lại hay được nhìn nhận là 1 ngôn ngữ có khả năng hiệu suất (performance) kém, do đó khi các website, api có lượng truy cập lớn lại nghĩ tới sử dụng các ngôn ngữ khác như Nodejs, Golang…

    Mặc dù vậy chúng ta vẫn có thể cải thiện điều này. Bài viết này sẽ hướng dẫn các bạn 1 số cách cải thiện tốc độ xử lý của PHP, cụ thể là PHP-fpm trên server Nginx.

    PHP-fpm là gì?

    Không phải tất cả Developer đều quan tâm tới tất cả các khía cạnh của DevOps, và trong số đó không phải ai cũng hiểu cách server xử lý trong 1 thời gian ngắn. Một điều thú vị là khi có 1 request tới server PHP thì không phải PHP xử lý nó trực tiếp mà là các máy chủ (Nginx / Apache), sau đó các máy chủ này mới quyết định truyền dữ liệu, type, header tới PHP.

    Trong các ứng dụng sử dụng PHP hiện tại, thì phần lớn file index được cấu hình là index.php, file sẽ nhận mọi request từ server tới. Bây giờ thì chính xác server đã gọi tới các file php như thế nào? Nếu tìm hiểu vấn đề này sâu xa thì tất mất thời gian, do đó ở bài này chúng ta chỉ tìm hiểu 1 cách sơ lược thôi. Đại khái trong giai đoạn mà web server Apache thống trị thì PHP là 1 module trong đó. Khi mà mỗi request được gửi tới server, server sẽ tiến hành xử lý 1 tiến trình (process), process này sẽ bao gồm xử lý php. Phương thức này sẽ gọi mod_php trong Apache, như vậy php là 1 module. Cách tiếp cận này có các hạn chế nhất định, điều mà Nginx đã giải quyết với php-fpm.

    Đối với php-fpm thì trách nhiệm quản lý cũng như các quy trình xử lý đều nằm trong chương trình PHP trong server. Nói 1 cách khác là web server (cụ thể là Nginx) sẽ ko quan tâm file PHP ở đâu, nó được load như thế nào nếu như biết cách gửi và nhận data từ nó. Nếu như bạn muốn, bạn có thể coi PHP trong trường hợp này như là 1 server khác và nó sẽ quản lý các tiến trình php trong các request được gửi tới.

    Nếu như bạn đã setup server Nginx, bạn sẽ thấy các cấu hình như sau:

    location ~ \.php$ {

    try_files $uri =404;

    fastcgi_split_path_info ^(.+\.php)(/.+)$;

    fastcgi_pass unix:/run/php/php7.2-fpm.sock;

    fastcgi_index index.php;

    include fastcgi_params;       

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    }

    Chú ý dòng fastcgi_pass unix:/run/php/php7.2-fpm.sock; Cấu hình này chỉ ra cho Nginx sẽ kết nối tới tiến trình PHP thông qua socket có tên là php7.2-fpm.sock . Do đó tất cả các request Nginx gửi data tới file này và nhận output sau đó trả về cho browser.

    Tóm lại điều chúng ta cần nắm được ở đây là

    • PHP không trực tiếp nhận các request từ trình duyệt, các web server (Nginx) sẽ chặn chúng
    • Các web server biết cách kết nối tới các tiến trình PHP và gửi các dữ liệu tới chúng.
    • Sau khi các tiến trình PHP xử lý xong chúng sẽ trả output về các web server, web server sẽ trả lại các client

    Vậy cuối cùng PHP-FPM là cái gì?

    FPM là viết tắt của “Fast Process Manager” điều này có nghĩa là PHP chạy trên server không phải là một tiến trình đơn lẻ, mà nó bao gồm nhiều tiến trình được sinh ra, điều khiển, tắt bới trình quản lý fpm. Nó chính là trình quản lý mà web server sẽ gửi các request tới.

    Tại sao phải tối ưu php-fpm?

    Nếu server của bạn vẫn đang đáp ứng tốt nhu cầu sử dụng, cũng như đang ổn định thì tất nhiên không việc gì phải tối ưu nó cả. Tuy nhiên trong trường hợp server của bạn đang không đáp ứng đủ nhu cầu, cũng như lượng server của bạn bị hạn chế thì việc tối ưu từng server lại là điều cần thiết.

    Một khía cạnh khác là Nginx được xây dựng để xử lý 1 số lượng công việc khổng lồ, nó có thể đáp ứng hàng nghìn kết nối, và thật lãng phí nếu như bạn không sử dụng hết sức mạnh của nó để tối ưu tài nguyên vì Nginx sẽ phải chờ tiến trình PHP hiện tại xử lý xong mới xử lý tới request tiếp theo, điều này không đúng với những ưu điểm mà Nginx được tạo ra.

    Vậy tối ưu php-fpm như thế nào?

    File cấu hình của php-fpm ở các server có thể sẽ khác nhau, với ubuntu thì nó được để tại /etc/php/7.2/fpm/php-fpm.conf (Đây là đường dẫn của php version 7.2)

    Một vài config ban đầu bạn có thể thấy

     ;;;;;;;;;;;;;;;;;;;;;
    ; FPM Configuration ;
    ;;;;;;;;;;;;;;;;;;;;;
    
    ; All relative paths in this configuration file are relative to PHP's install
    ; prefix (/usr). This prefix can be dynamically changed by using the
    ; '-p' argument from the command line.
    
    ;;;;;;;;;;;;;;;;;;
    ; Global Options ;
    ;;;;;;;;;;;;;;;;;;
    
     [global] 
    ; Pid file 
    ; Note: the default prefix is /var 
    ; Default Value: none 
    pid = /run/php/php7.2-fpm.pid 
    ; Error log file 
    ; If it's set to "syslog", log is sent to syslogd instead of being written 
    ; into a local file. 
    ; Note: the default prefix is /var 
    ; Default Value: log/php-fpm.log 
    error_log = /var/log/php7.2-fpm.log 

    Một vài điểm cần chú ý trong cấu hình trên:

    pid = /run/php/php7.2-fpm.pid 

    Cấu hình này chỉ ra file chứa process id của tiến trình php-fpm

    error_log = /var/log/php7.2-fpm.log

    Còn đây là cấu hình file mà php sẽ ghi log.

    Bên cạnh đó còn 3 cấu hình

    emergency_restart_threshold 10
    emergency_restart_interval 1m
    process_control_timeout 10s

    Hai dòng đầu chỉ ra rằng nếu 10 quy trình con không thành công trong vòng 1 phút thì php-fpm sẽ tự động khởi động lại. Điều này nghe có vẻ “yếu” nhưng thực ra PHP là một tiến trình ngắn, nó làm tốn dữ liệu vì vậy việc khởi động lại trong trường hợp lỗi sẽ giải quyết được nhiều vấn đề. Cấu hình thứ 3 là thời gian các tiến trình con chờ đợi tín hiệu từ tiến trình cha .

    Thực ra bên trên vẫn chưa phải là cấu hình chính của php-fpm. Bởi vì để phục vụ các request từ server, php-fpm tạo ra một pool mới để quản lý các tiến trình, và nó sẽ có các cấu hình khác nhau. Ví dụ 1 pool có tên là www. File config là: /etc/php/7.2/fpm/pool.d/www.conf

    ; Start a new pool named 'www'. 
    ; the variable $pool can be used in any directive and will be replaced by the 
    ; pool name ('www' here) 
    [www] 
    ; Per pool prefix 
    ; It only applies on the following directives: 
    ; - 'access.log' 
    ; - 'slowlog' 
    ; - 'listen' (unixsocket) 
    ; - 'chroot' 
    ; - 'chdir' 
    ; - 'php_values' 
    ; - 'php_admin_values' 
    ; When not set, the global prefix (or /usr) applies instead. 
    ; Note: This directive can also be relative to the global prefix. 
    ; Default Value: none 
    ;prefix = /path/to/pools/$pool 
    ; Unix user/group of processes 
    ; Note: The user is mandatory. If the group is not set, the default user's group 
    ;       will be used. 
    user = www-data 
    group = www-data  

    Cấu hình mặc định thường như sau:

    pm = dynamic
    pm.max_children = 5
    pm.start_servers = 3
    pm.min_spare_servers = 2
    pm.max_spare_servers = 4
    pm.max_requests = 200

    Chú ý “dynamic” ở đây có ý nghĩa như thế nào. Xem các option có thể setting:

    ; Choose how the process manager will control the number of child processes.
    ; Possible Values:
    ;   static  - a fixed number (pm.max_children) of child processes;
    ;   dynamic - the number of child processes are set dynamically based on the
    ;             following directives. With this process management, there will be
    ;             always at least 1 children.
    ;             pm.max_children      - the maximum number of children that can
    ;                                    be alive at the same time.
    ;             pm.start_servers     - the number of children created on startup.
    ;             pm.min_spare_servers - the minimum number of children in 'idle'
    ;                                    state (waiting to process). If the number
    ;                                    of 'idle' processes is less than this
    ;                                    number then some children will be created.
    ;             pm.max_spare_servers - the maximum number of children in 'idle'
    ;                                    state (waiting to process). If the number
    ;                                    of 'idle' processes is greater than this
    ;                                    number then some children will be killed.
    ;  ondemand - no children are created at startup. Children will be forked when
    ;             new requests will connect. The following parameter are used:
    ;             pm.max_children           - the maximum number of children that
    ;                                         can be alive at the same time.
    ;             pm.process_idle_timeout   - The number of seconds after which
    ;                                         an idle process will be killed.
    ; Note: This value is mandatory.

    Giải thích sơ lược thì như sau

    pm.max_children = Số process con (child processes) tối đa được tạo (tương đương tổng số request có thể phục vụ)
    pm.start_servers = Tổng số child processes được tạo khi khởi động php-fpm (được tính bằng công thức `min_spare_servers + (max_spare_servers – min_spare_servers) / 2` )
    pm.min_spare_servers = Tổng số child process nhàn rỗi tối thiểu được duy trì.
    pm.max_spare_servers = Tổng số child process nhàn rỗi tối đa được duy trì.

    Chúng ta có các option sau:

    • Static: fix cứng 1 số lượng process được duy trì
    • Dynamix: set số lượng min và max các process có thể được duy trì ở bất cứ thời điểm nào
    • ondemand: Các process sẽ được tạo ra và tắt đi theo yêu cầu

    Vậy các con số này có ý nghĩa như thế nào? Nếu như web server của bạn có lượng truy cập rất ít thì việc chọn cấu hình là dynamic sẽ rất phí tài nguyên, trong trường hợp này bạn có thể set pm.min_spare_servers = 3 và chọn option “ondemand” để server quyết định số lượng process.

    Trong trường hợp ngược lại với 1 web site có số lượng truy cập lớn, thì nên setting về static, và setting với số lượng tối đa mà server có thể sử dụng.

    Cách tính pm.max_children

    B1. Xác định số lượng bộ nhớ cần thiết trung bình cho 1 process php-fpm

    ps -ylC php-fpm --sort:rss

    Ouput sẽ tương tự như sau, column RSS sẽ chứa giá trị mà chúng ta cần xác định

    S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD
    S 0 24439 1 0 80 0 6364 57236 - ? 00:00:00 php-fpm
    S 33 24701 24439 2 80 0 61588 63335 - ? 00:04:07 php-fpm
    S 33 25319 24439 2 80 0 61620 63314 - ? 00:02:35 php-fpm

    Như kết quả ở trên là khoảng 61620KB, tương đương với ~60MB/process
    B2: Tính toán ra pm.max_children

    Ví dụ server hiện tại có khoảng 4GB RAM, đang chạy cả web và DB, chúng ta sẽ tính con số ước lượng là DB hoạt động khoảng 1GB và 0.5G dành cho buffer. Với các con số như vậy thì dung lượng RAM còn lại cho hoạt động của php-fpm tương đương với: 4 – 1 – 0,5 = 2,5 GB RAM hoặc 2560 Mb.

    pm.max_children = 2560 Mb / 60 Mb = 42

    Làm tròn con số xuống (để đảm bảo server hoạt động không bị quá tải), thì pm.max_children = 40
    Cách tính pm.min_spare_servers

    pm.min_spare_servers có giá trị tương đương với 20% của pm.max_children.
    Nếu như với gía trị ở trên thì pm.max_spare_servers = 60% * 40 = 24
    Cũng có hướng dẫn ghi là pm.max_spare_servers = (cpu cores) * 4
    Cách tính pm.max_requests

    Tham số này chính là số lượng request xử lý đồng thời mà server có thể chịu tải được, giá trị phụ thuộc vào pm.max_children và số lượng request trên 1s vào server. Con số này tính toán cũng khá hên xui, nhưng có thể có 1 phương pháp là sử dụng tool ab của apache sau đó giảm giá trị dần dần sao cho phù hợp.

    ab -n 5000 -c 100 http://domain.com/

    Khi chạy command trên thì có nghĩa là tạo ra 5000 request với 100 session hoạt động cùng lúc truy cập vào url http://domain.com. Giá trị pm.max_requests có thể set là 1000 sau đó tăng/giảm dần đến mức phù hợp (Phù hợp là khi server vẫn còn chịu được tải).

    Cấu hình Nginx để tăng performance

    Mở file /etc/nginx/nginx.conf và điều chỉnh theo các hướng dẫn sau.
    Trước hết bạn cần nắm công thức:

    max_clients = worker_processes * worker_connections
    số lượng người truy cập tối đa Nginx có thể phục vụ bằng thông số worker_processes nhân với worker_connections. Mặc định sau khi cài đặt Nginx thì

    worker_processes = 1

    worker_connections = 1024.

    Các bạn cần chỉnh lại worker_processes bằng với số lượng CPU core trong server bạn cấu hình. Có thể xem số CPU Core thông qua lệnh sau:

    cat /proc/cpuinfo |grep processor

    Với số lượng CPU bằng 4 bạn có thể setting worker_processes  = 4, như vậy lượng truy cập tối đa sẽ là 4 * 1024

    Để tăng thêm số lượng connection bạn cũng có thể thay đổi thêm

    worker_rlimit_nofile 2048;

    Cấu hình này giúp bạn có thể setting worker_connections  lên tới 2048

    Ngoài ra các bạn cũng cần thiết giới hạn kích thước body của các http request và buffer dùng xử lý http request thông qua việc thêm hai thông số sau đây vào file cấu hình

    client_max_body_size 20m;

    client_body_buffer_size 128k;

    Tăng tốc bằng cache file. Với các file tĩnh trên server thì chúng ta hoàn toàn có thể cache lại bằng config

    location ~* .(jpg|jpeg|gif|png|css|js|ico|xml)$ {
    access_log off;
    log_not_found off;
    expires 360d;
    }

    Anh em đọc tham khảo. Bài cóp nhặt từ nhiều nguồn, khá hữu ích cho các anh em PHP.

  • Nguyên nhân và giải pháp để tối ưu và tăng tốc độ tải trang web

    • Tại sao tốc độ website lại chậm ?
    • Làm sau để khắc phục website quá chậm như vậy ?
    • Tăng tốc website bằng cách nào ?
    • Tốc độ website làm ảnh hướng đến việc SEO của tôi giải quyết thế nào ?

    Đối với những website cao cấp tốc độ tải trang rất quan trọng. Người dùng chỉ hứng thú với những website load nhanh, còn khi một trang web đáp ứng chậm, khách sẽ mất kiên nhẫn và khả năng họ quay lại sẽ là rất thấp. Như vậy, những người tìm kiếm thông tin thường rất sốt ruột khi phải đợi những trang web được tải xuống. Nếu những trang Web của bạn không đủ nhanh, nhiều người tìm kiếm thông tin sẽ ra đi mà không thèm xem trong website có thứ gì.

    Cải thiện tốc độ tải trang không chỉ quan trọng đối với người dùng mà còn quan trọng với công cụ tìm kiếm. Tháng 4 năm ngoái Google đã công bố tốc độ tải trang là một trong những yếu tố xếp hạng trong thuật toán của họ.

    Có vài điều giúp bạn có thể làm tăng tốc độ web site của bạn. Tất nhiên, bạn cần phải chắc chắn rằng web của bạn được lưu giữ bởi những máy chủ đáng tin cậy và nhanh. Ngoài việc lưu giữ website của bạn trên một máy chủ nhanh, bạn có thể làm những việc sau đây để cải thiện thời gian tải của những trang Web của bạn.

    Nguyên nhân phổ biến khiến tốc độ tải trang chậm

    Nguyên nhân phổ biến khiến tốc độ tải trang chậm

    – Cái đặt Plugin, Script,… từ bên thứ 3: Có rất nhiều Plugin cả miễn phí, cả trả phí rất hấp dẫn với bạn. Bạn cài đặt chúng vào và không biết chúng ảnh hưởng như thế nào đến tốc độ tải trang? Cài đặt quá nhiều ứng dụng bên thứ 3 thiếu kiểm soát chính là một trong những nguyên nhân hàng đầu tăng gánh nặng cho Website bạn.

    – Chưa tối ưu HTML, CSS, js..: Dư thừa mã css và js, viết mã tạo nhiều file css và js. Css dùng nhiều hình ảnh làm hình nền. Mã nguồn cồng kềnh, bừa bộn, là một nguyên nhân không nhỏ tăng dung lượng Website của bạn lên và từ đó sẽ khiến thời gian tải về tăng lên đáng kể.

    – Không gzip source code trong khi truyền tải dữ liệu đến người xem qua đường truyền internet.

    – Người coder không xóa các ghi chú trong quá trình phát triển website.

    – Hình ảnh chất lượng cao và nặng: Do kích thước hình ảnh quá lớn so với kích thước người dùng xem. Làm tăng thời gian tải trang web. Chúng tôi biết là trông chúng sẽ rất đẹp, hình ảnh sắc nét, nhưng nếu bạn cứ Update thẳng những tấm hình 4, 5MB hoặc hơn lên Web, bao giờ người dùng mới tải xong chúng đây?.

    – Dịch vụ hosting kém chất lượng: Khách hàng lớn nhưng cấu hình server thấp, bảo mật kém, khoản cách địa lý…

    – Người quản trị copy từ các nguồn như: tin tức báo trí, các diễn đàn… không xử lý lại thông tin làm tạo các mã mà hệ thống không hỗ trợ.

    – Lượng khác hàng truy cấp website lớn nhưng dịch vụ hosting chưa nâng cấp xứng tầm.

    – Sử dụng dịch vụ web (webservice) từ nhà cung cấp thứ ba hay bạn đặt quá nhiều quảng cáo.

    – Hacker add các đoạn mã ăn cấp thông tin người dùng hay thực hiện các lệnh nhằm phá hỏng hệ thống.

    – Sử dụng nhiều file flash ảnh hưởng đến quá trình xử lý của trình duyệt web.

    Và theo thống kê sơ bộ của ADC việc ảnh hưởng đến tốc độ website thì với hơn 50% là xuất phát từ công ty thiết kế web vì họ không tối ưu website trước khi bàn giao. Trong đó 20% từ nhà cung cấp hosting, không tối ưu hóa và chất lượng dịch vụ hosting không đảm bảo. Còn lại 30% chính từ người quản trị website không am hiểu hệ thống.

    Những giải pháp phổ biến để tối ưu và tăng tốc độ tải trang web

    Những giải pháp phổ biến để tối ưu và tăng tốc độ tải trang web

    Chứa hình ảnh của website ở các domain khác nhau. Các dịch vụ như Amazon S3 làm chuyện này rất dễ dàng. Tạo 1 tài khoảng S3. Trỏ subdomain như “abc.yoursite.com” về S3 lưu trữ. Đặt các hình ảnh website của bạn ở đây. Các trình duyệt web có thể load từ nhiều domain cùng một lúc, tạo cảm giác rằng website của bạn load nhanh hơn. Hơn nữa, bạn sẽ sử dụng ít CPU và bandwidth của server chính hơn.

    Sử dụng Flickr để chứa hình ảnh website của bạn và dùng như một domain riêng.

    Nén các file hình ảnh theo đúng loại file nén. Sử dụng loại nén “lossy” – JPEG cho các hình ảnh nhiều màu sắc. Sử dụng loại nén “lossless – PNG và GIF – cho các hình ảnh ít màu sắc.

    Resize hình ảnh trước khi bạn upload chúng. Đừng resize hình ảnh theo chiều rộng và cao. Resize chúng bằng Photoshop, Fireworks hoặc các chương trình xử lí ảnh chuyên nghiệp.

    Học cách viết code thật rõ ràng, súc tích. Các hệ quản trị nội dung (CMS) hoặc các shopping cart thường phát sinh rất nhiều code HTML dư thừa. Xóa bỏ bớt hoặc làm gọn nó khi cần thiết.

    Đưa các cấu hình CSS vào các file .css riêng biệt, không nên nhúng thẳng vào mỗi trang.

    Chia rõ các cấu hình CSS ra. Tạo 1 stylesheet chứa duy nhất cấu hình sử dụng chung cho tất cả các trang. Sau đó, tạo các stylesheet riêng biệt cho mỗi layout của từng trang như: trang chủ, trang sản phẩm, trang tin tức,…Chỉ load những gì cần thiết trên mỗi trang.

    Học cách sử dụng CSS. Nếu bạn có thể sử dụng thẻ <p> thay vì sử dụng &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=”blue” style=”font-size:10pt;font-weight:bold;”>, bạn sẽ tiết kiệm được rất nhiều không gian.

    Đưa các đoạn mã javascript vào các file .js. Không nên nhúng thẳng vào mỗi trang. Nếu bạn nhúng javascript vào thì cứ mỗi lượt viếng thăm trang web, kể cả Googlebot, đều phải download code đó mỗi lần tại mỗi trang. Nếu bạn tách riêng ra một file .js thì Googlebot sẽ bỏ qua nó và các browser sẽ cache nó lại được.

    Tách riêng các file javascript ra, giống như bạn tách riêng các file CSS vậy.

    Hoãn lại việc load các javascript khi có thể. Bạn có thể search Google với từ khóa “deferred javascript” để biết thêm chi tiết. Về cơ bản, kỹ thuật này sẽ cho các web browser biết nó sẽ load các javascript có thuộc tính “defer” cuối cùng, sau khi đã load hết các thành phần các của trang web. Điều này sẽ làm giảm nguy cơ bị chậm, bị lỗi hoặc bị đứng đang web khi các file javascript bị lỗi.

    Mã: http://common.js

    Bỏ các file Flash. Có rất nhiều cách để hiển thị các thành phần động trên một trang. Nếu bắt buộc sử dụng Flash, bạn nên sử chỉ sử dụng ở 1 phần nhỏ trên trang web.

    Sử dụng chuẩn nén GZIP trên web server của bạn.

    Giảm thiểu mọi thứ từ HTML, javascript cho đến CSS. Lưu lại một bản chưa được tối ưu của tất cả mọi thứ để chỉnh sửa lại sau này.

    Tối thiểu hóa việc redirect. Không sử dụng 301 redirect trừ khi bạn bắt buộc phải dùng.

    Sửa lại các vấn đề phù hợp với tiêu chuẩn chung. Sửa lại không có nghĩa là sử dụng “rel=canonica”, mà nó có nghĩa là phải đảm bảo rằng trên mỗi trang website của bạn phải có một địa chỉ đơn. Điều này sẽ làm tăng caching performance, giảm memory usage và tăng tốc mọi thứ lên.

    Đầu tư vào hosting có chất lượng tốt, uy tín. Nếu quy mô website lớn, lượng truy cập nhiều thì nên cân nhắc đầu tư một dedicated server để có thể tối đa được tốc độ website.

    Thiết lập caching trên server. Nếu bạn sử dụng WordPress, sử dụng plugin như W3 Total Cache.

    Go static. Nếu bạn đang xây dựng trang web với ngôn ngữ PHP, ASP hoặc ngôn ngữ nào khác thì các sự thay đổi thường xảy tra trên tất cả các trang đó. Một vài trang như “Giới thiệu”, “Liên hệ” việc thay đổi ít xảy ra nên bạn có thể để những trang đó là static (.html hoặc .htm). Làm như vậy sẽ giảm thiểu được một số lượng call tới CPU server, tăng performance.

    Nếu bạn đang làm việc với ngôn ngữ .NET, nghiên cứu để nén biến VIEWSTATE.

    Cấu hình đúng phần quản lý bộ nhớ của server (server’s memory management). Bạn tìm hiểu chi tiết thêm phần này ở Google nhé.

    Đặt database ở một server khác. Nếu bạn có một website với nhiều traffic, lượng truy cập lớn, khi đó bạn nên để website ở một server riêng và database ở một server riêng khác. Các database transaction tiêu tốn rất nhiều hiệu năng server.

    Học cách sử dụng JOIN để viết các câu truy vấn SQL lấy dữ liệu ở nhiều bảng khác nhau. Sử dụng JOIN sẽ nhanh hơn nếu dùng đúng cách.

    Học cách sử dụng Stored Procedures. Stored Procedures được biên dịch bởi database server và chạy nhanh hơn rất nhiều so với các script SQL thuần.

    Không sử dụng SSL trừ khi bạn buộc phải dùng nó (cách này còn gây rất nhiều tranh cãi, nên tạm thời không bàn chi tiết ở đây)

    Nếu bạn sử dụng Apache Server, chỉ nên load những module cần thiết. Hầu hết người dùng đều để thiết lập mặc định, và như vậy sẽ bao gồm những module không cần thiết. Học cách sử dụng AllowOverride, khi bạn thực sự cần DNS lookup, và các tip khác như FastCGI.

    Nếu bạn sử dụng Information Server (IIS), học cách sử dụng performance logging. Bạn có thể bắt đầu với trang Technet (http://technet.microsoft.com/en-us/library/bb727100.aspx). Nhớ kiểm tra IIS version mà bạn đang sử dụng.

    Học cách sử dụng một server accelerator như Squid, hoặc sử dụng Apache hoặc nginx như là một caching proxy. Các caching proxy và accelerator được thiết kế để lưu giữ các trang web động và phân phối chúng ra public một cách nhanh hơn.

    Lưu ý: Tùy theo từng trường hợp mà sẽ đưa ra các giải pháp khác nhau. Đảm bảo tốc độ tài trang chậm nhất dưới 3s

    Ngoài ra còn có nhiều cách khách cho bạn tối ưu trang của mình, và một website không bao giờ là “đủ nhanh” cả (thường các chuyên gia SEO khuyên nên tối ưu load trang dưới 3 giây).

    Điều quan trọng là bạn phải liên tục cải tiến, làm cho tốc độ của nó càng ngày càng nhanh. Khi đó bạn sẽ thấy được kết quả tốt hơn như: khách viếng thăm nhiều hơn, traffic nhiều hơn, xếp hạng cao hơn,…

    ST

  • Webserver (Part 2)

    Webserver (Part 2)

    Trong Phanaf

    Trong phần trước, mình đã đề cập đến Host, WebServer. Vậy magz.techover.io hay google.com từ đâu mà có. Phần này sẽ tiếp tục với DNS.

    DNS

    Như phần trước, chúng ta có Host header, header này báo cho WebServer website mà client yêu cầu, vậy làm cách nào mà khi chúng ta điền google.com lên thanh URL và request đó đến đựoc WebServer?

    Đó chính là nhiệm vụ của DNS – Domain Name Service, đúng như cái tên nó là một service cung cấp tên miền (Domain Name). Khi chúng ta mua domain từ một nhà cung cấp (ví dụ như godaddy.com, hay namecheap.com), chúng ta thường thêm một số Domain Name Server vào domain đó. Nó sẽ kiểu như này:

    Domain name Server của một domain sử dụng AWS Route53

    Thực ra vụ này cũng không cần thiết lắm, vì nhiều nhà cung cấp cài đặt sẵn cho mọi người rồi, mọi người chỉ cần làm việc này khi chuyển việc quản lý domain cho service khác thôi (ví dụ khi mua bạn mua ở namecheap.com) và bạn chuyển qua cloudflare.com)), và chuyện này cũng phổ biến và thậm chí được khuyên dùng, lý do: security và high availability. Nhiều Name Server đã bị tấn công nhiều lần, khi đó, DNS sẽ không hoạt động và tất nhiên trang web của bạn cũng không thể truy cập bằng domain. Dùng nhiều DNS khác nhau cũng là một cách, vì bạn có thể setup nhiều ns record, một cách dễ hiểu là đừng bỏ trứng vào chung rổ và tất nhiên có nhiều bên cung cấp service này:

    • AWS Route 53
    • CloudFlare DNS
    • DynDNS
    • OpenDNS
    • EasyDNS
    • DNSMadeEasy

    Một khi Name Server của bạn được cài đặt, bạn có thể bắt đầu tạo DNS record ở trang web hay công cụ của nhà cung cấp Domain, đợi một vài phút là bạn có thể truy cập trang web của bạn từ trình duyệt.

  • Webservers

    Webservers

    Về cơ bản bài viết này đưa cho các bạn khái niệm rất cơ bản về WebServer, các bạn web developer có thể rất cần Đầu tiên, mình nghĩ chúng ta nên đề cập đến HTTP, làm thế nào để match incoming HTTP request với website, sau đó là 2 Web Server rất phổ biến: Apache và Nginx, cuối cùng sẽ đề cập đến 1 ngôn ngữ cụ thể và cách kết nối với web server ở đây là PHP với PHP-FPM.

    HTTP, Web Server và Web Sites

    Mọi người có lẽ đều nghĩ rằng một WebServer chỉ có thể xử lý phục vụ một trang web, nhưng thực sự là ngược lại. Trong Apache thì dùng khái niệm VirtualHost, còn Nginx sử dụng bằng cách định nghĩa Server trong Nginx Configuration hay còn gọi là Virtual Servers.

    Nếu một WebServer đang xử lý nhiều trang web, làm thế nào để máy chủ định tuyến đến đúng trang web mà người dùng muốn truy cập?

    Chúng ta quay lại với HTTP – HyperText Transfer Protocol, là một trong năm giao thức chuẩn của mạng Internet, giao thức sử dụng để giao tiếp giữa WebServer và WebClient. Về cơ bản, WebServers sẽ đọc Host header của các Web HTTP request, nếu không tồn tại Host header hoặc không phù hợp, WebServer sẽ chuyển yêu cầu đến một trang web mặc định.

    Chúng ta có thể dùng curl để kiểm tra. Ví dụ mình sẽ kiểm tra magz.techover.io và Google.

    Chúng ta có thể thấy IP của WebServer là 104.28.19.140, chúng ta dùng curl để xem response khi gọi đến địa chỉ này.

    Chúng ta có thể thấy là magz.techover.io sử dụng Cloudflare để bảo vệ, và chúng ta bị chuyển đến trang mặc định 403 khi không có quyền truy cập.

    Còn với Google:

    Có thể thấy Google sử dụng GWS – Google Web Server. GWS thông báo cho Client rằng, Client cần phải truy cập đến http://www.google.com thông qua Location Header. Có 2 điều bạn thấy ở đây:

    • http://www.google.com mới là trang mặc định, thay vì http://google.com (cái này liên quan đến một khái niệm khác http://google.com được gọi là Naked Domain Name, sẽ có một bài viết liên quan đến vụ này sau).
    • GWS gửi một response chuyển hướng 301 đến http://www.google.com.

    Bây giờ nếu thêm Host header vào trang web thì sao:

    Kết quả không khả quan lắm, có vẻ như magz.techover.io và google.com vẫn không phải trang mặc định. Với trường hợp của magz.techover.io là do cloudflare chuyển hướng với non-SSL request sang SSL site.

    Đến đây một session mới được khởi tạo với Set-Cookie Header. Chúng ta có thể thử với một static site khác, site này không hề có Set-Cookie Header.

    Phần tiếp theo sẽ nói về việc cài đặt và cấu hình Nginx và Apache cho một hoặc nhiều Website.