khanhnnvn

[Docker]- Part1 – Docker, Containers, Hypervisor

 Linux  Comments Off on [Docker]- Part1 – Docker, Containers, Hypervisor
Nov 112015
 

1, Đặt vấn đề.

Ảo hóa là vấn đề đang rất được quan tâm hiện nay
Ảo hóa là vấn đề đang rất được quan tâm hiện nay

Ảo hóa là vấn đề đã và đang dành được sự quan tâm rất lớn của những lập trình viên, các nhà nghiên cứu, các doanh nghiệp…. và ….Docker đang nổi lên như một hiện tượng đồng thời giành được rất nhiều sự quan tâm của cộng đồng mã nguồn mở. Trong phạm vi loạt bài về Docker, mình và các bạn sẽ cùng tìm hiểu những đặc điểm, tính chất và tính ứng dụng của nó trong một bài toán cụ thể.

Trong khuôn khổ bài viết này, mình sẽ tìm hiểu tổng quan về 3 phần chính được nêu trong tiêu đề là : Containers, Hypervisor và Docker.

2, Container và Hypervisor

containervshyper

Containers là ảo hóa nằm ở tầng Operation System (hệ điều hành), tức là container sẽ thay thế hệ điều hành, và chạy trực tiếp trên phần cứng.

Hypervisor là ảo hỏa nằm ở tầng Hardware (phần cứng), tức là mô phỏng phần cứng và chạy những OS con trên phần cứng đó (Các công cụ Hypervisor như Virtual Box, VMware..)

Containers khởi động và làm cho ứng dụng sẵn sàng chạy trong 500ms, mang lại tính khả thi cao cho những dự án cần sự mở rộng nhanh.

Hypervisor có thời gian khởi động trung bình là 20s, thay đổi phụ thuộc vào tốc độ của ổ đĩa.

Với Hypervisor, bộ nhớ được cấp phát cho các trường hợp khác nhau. Với Containers, thì sẽ có một không gian lưu trữ duy nhất cộng thêm những vùng nhớ nhỏ hơn được cấp phát cho các lớp (layer) khác nhau và do đó mang lại tính hiệu quả hơn nhiều so với Hypervisor.

Containers hỗ trợ các API có giá trị cao cho việc triển khai hệ thống điện toán đám mây. Còn Hypervisor hỗ trợ các API có giá trị bình thường cho triển khai hệ thống điện toán đám mây.

Đã đến lúc chúng ta phải lựa chọn một công cụ cho mình. Nếu người khác chọn Hypervisor vì tính dễ sử dụng (các công cụ như Virtual box hay VMware) thì tôi sẽ lựa chọn Containers như là một giải pháp tối ưu cho việc triển khai hệ thống điện toán đám mây của mình. Sự lựa chọn căn cứ trên những gì mà nó mang lại cho tôi về thời gian, bộ nhớ…..v.vvv.

3, Docker

dcoker

Sự lựa chọn Containers của tôi ở phía trên mang tính chất định hướng. Vì  nó là một tập hợp các công cụ có cùng đặc điểm chung. Và công cụ nổi bật trong đó chính là Docker. Docker mang đầy đủ tính chất của một Containers. Ngoài ra, nó còn có những đặc điểm, tính chất riêng mang lại cho nó những giá trị nhất định.

  • Với Docker, chúng ta có thể đóng gói mọi ứng dụng vd như webapp, backend, MySQL, BigData…thành các containers và có thể chạy ở “hầu hết” các môi trường vd như Linux, Mac, Window…
  • Docker Containers có một API cho phép quản trị các container từ bên ngoài. Giúp cho chúng ta có thể dễ dàng quản lí, thay đổi, chỉnh sửa các container.
  • Hầu hết các ứng dụng Linux có thể chạy với Docker Containers.
  • Docker Containers có tốc độ chạy nhanh hơn hẳn các VMs truyền thống (theo kiểu Hypervisor). Điều này là một ưu điểm nổi bật nhất của Docker

Với Docker, còn rất nhiều điều chúng ta cần nhắc đến và tìm hiểu.

Setup VSFTP can Access Apache

 Linux  Comments Off on Setup VSFTP can Access Apache
Nov 102015
 

Setup FTP Linux

  • Install FTP
yum install vsftpd
  • Configure
vi /etc/vsftpd/vsftpd.conf

anonymous_enable=NO

vi /etc/selinux/config

SELINUX=disabled

Then run from command line:
 setenforce 0
chkconfig vsftpd on
  • Create User to access Apache home
useradd -g apache -d /var/www/html $khanhnn
passwd $khanhnn
  • Start Service
service vsftpd start
  • Set permissions
vi /etc/group

apache:x:##:$user

  • Set permissions in web root /var/www/html
chown -R $user:apache *
chmod -R 775 *

Now we need to restrict new ftp user to its home directory by changing the configuration file:

vi /etc/vsftpd/vsftpd.conf
uncomment
chroot_local_user=YES

How to Install Varnish with Apache on Ubuntu

 Linux  Comments Off on How to Install Varnish with Apache on Ubuntu
Nov 072015
 

Varnish is an amazing frontend cache that is useful for serving static pages and reducing load on your server. In periods of high server activity and traffic, Varnish can be a life saver. Also, Varnish is extremely fast and effective at reducing your page load times, which helps with your SERPs and improves user experience.

1. Add the Varnish Repository

Varnish can be installed by adding the Varnish repository to your sources and using apt-get to install it.

To add the repository, run the following command:

2. Edit List of apt Sources

Open the /etc/apt/sources.list in your favorite text editor so we can add the Varnish repository.

Next, add the Varnish repository at the end of the file.

Save your work and exit out to the command line.

3.  Install Varnish

Use the usual apt-get to install Varnish.

4. Configure Varnish DAEMON_OPTS

Now it is time to configure Varnish. This process will vary depending upon your CMS and/or framework and how your site is set up, but we will get you started with a basic configuration.

Open the /etc/default/varnish file:

Look for “alternative 2” and uncomment the following code. Change the ports as necessary.

Basically, we are setting Varnish to use Port 80, using /etc/varnish/default.vcl as our configuration file, and allocating 256MB of memory.

5. Varnish VCL Configuration

The VCL file in Varnish is extremely important and allows for very specific configurations indicating which pages to cache, how to treat cookies, what to do about different user-agents, and so on.

The basics will be covered here, but you will need to look closely at the VCL file in the future to get optimal performance. Don’t worry because it’s straightforward and you can do it!

Open the VCL file:

Now we have to tell Varnish where to grab content for your site. Here we are using the same server and we will set up Apache on port 8888.

Save and exit the file.

6. Change the Apache Ports

By default, Apache is configured to run on Port 80. We will change the port to be 8888.

Open the Apache ports file:

Now look for the NameVirtualHost and Listen lines and change them to Port 8888.

7. In the Virtual Host, Change the Port to 8888

In the settings for your virtual host, you will need to tell Apache to look on Port 8888.

Now change the port:

Save and exit the file.

8. Restart Apache and Varnish

9. Watch in Amazement at the Details of your Varnish Server Running

You can check in on Varnish with its built-in stats readout.

You are done! That was easy wasn’t it? Now you are well on your way to having a fast and efficient server configuration.

Tìm hiểu RabbitMQ – Phần 2

 Database  Comments Off on Tìm hiểu RabbitMQ – Phần 2
Oct 282015
 

Trong phần 1, tôi đã giới thiệu về sơ lược rabbitmq, vai trò của rabbitmq trong hệ thống phân tán và hướng dẫn cài đặt. Trong phần này, tôi sẽ trình bày cách về cluster và cấu hình cluster trong rabbitmq

Cluster là gì

Cluster là nhóm các thành phần mà hoạt động cùng với nhau để cung cấp một dịch vụ nào đó. Thành phần ở đây gọi là một node. Mỗi node này là một process hoạt động. Thường thì node được đồng nhất với một server do mỗi node thường được cài đặt trên một server riêng rẽ ( để tránh bị chết chùm ). Khái niệm cluster này xuất hiện trong rất nhiều kiến trúc như galera, mysql, redis… Mục đích sử dụng cluster là để load balancing, high availibility (đảm bảo hệ thống vẫn hoạt động khi có sự cố), scale hệ thống.

Cluster trong rabbitmq

Trong rabbitmq, một cluster là một nhóm các erlang node làm việc cùng với nhau. Mỗi erlang node có một rabbitmq application hoạt động và cùng chia sẻ tài nguyên: user, vhost, queue, exchange…

alt text

Một số đặc điểm cần chú ý

  • Metadata của một node được replicate đến các node còn lại trong cluster ngoại trừ queue. Queue được tạo ra trên node nào thì vẫn nằm trên node đó, không có replicate gì hết nhưng bạn hoàn toàn có thể nhìn thấy một queue tạo ra trên một node khi truy xuất qua các node còn lại do đó đối với client một cluster rabbitmq chẳng khác gì một single rabbitmq.
  • Vì queue không được replicate nên bản thân cluster rabbitmq chưa cung cấp high availibility (HA). Bạn vẫn cần cấu hình thêm chút nữa nhưng cluster là tiền đề để rabbitmq có thể thực hiện được HA.
  • Một node có thể là disc node (mặc định) hoặc ram node
  • Như trong tài liệu của rabbitmq có khẳng định, rabbitmq không xử lý tốt network partition nên không khuyến khích sử dụng cluster của rabbitmq trên WAN. Có thể bạn sẽ thắc mắc network partition là gì ? Một network partition hay còn gọi là split brain là tình huống rất hay gặp trong hệ cluster.
alt text

Khi network partition xảy ra, hệ cluster bị chia đôi và mỗi phần không thể liên lạc được với phần còn lại nên đâm ra bản thân từng partition lại cứ ngỡ nó là toàn bộ cluster. Vấn đề chính là ở đây. Mỗi partition khi đó sẽ không đồng bộ được với phần còn lại nên chúng ta sẽ có hai tập dữ liệu riêng biệt trên mỗi partition. Nguyên do dẫn đến network partition thường là network không ổn định hoặc quá tải trên node (Khi quá tải do CPU hoặc IO bị nghẽn network của server thường rất chập chờn ). LAN network so với WAN network thì thường ổn định hơn nhiều nên rabbitmq cluster thích hợp khi các node được liên kết với nhau qua LAN network. Về network partition, tôi sẽ trình bày trong một phần khác.

  • Clustering rabbitmq chỉ là một trong ba cách cấu hình hệ phân tán rabbitmq. Clustering phù hợp cho môi trường LAN network còn với môi trường WAN network thì các mô hình như federation hay shovel lại được khuyến khích. Trong trường hợp của tôi, tôi không sử dụng rabbitmq trong môi trường WAN nên hai mô hình shovel và federation tôi không trình bày.

Điều kiện để thiết lập clustering

  • Tất cả các node phải cùng erlang version và rabbitmq version
  • Các node liên kết qua LAN network
  • Tất cả các node chia sẻ cùng một erlang cookie

Trong mô hình cluster, các node sử dụng phương thức trao đổi giữa của erlang. Khi sử dụng phương thức này, hai erlang node chỉ nói chuyện được với nhau khi có cùng erlang cookie. Erlang cookie chỉ là một chuỗi ký tự. Khi startup một rabbitmq server lần đầu tiên, mặc định một erlang cookie ngẫu nhiên được sinh ra nằm trong /var/lib/rabbitmq/.erlang.cookie

Làm viêc với cluster

Thực hiện tạo cluster

Chuẩn bị ba rabbitmq server thỏa mãn đủ điều kiện.

Đầu tiên, chúng ta cần chọn một node, sau đó copy erlang cookie của node đó sang các node còn lại.

Vì node name của rabbitmq có dạng rabbit@hostname nên bạn cần chuẩn bị sẵn hostname cho mỗi node. Hostname là bất cứ string nào bạn muốn nhưng tốt nhất đừng sử dụng các ký tự đặc biệt trong này. Sau đó đưa vào/etc/hosts của cả ba node:

192.168.3.241 rabbit1  ### gọi là node 1
192.168.3.242 rabbit2  ### gọi là node 2
192.168.3.252 rabbit3  ### gọi là node 3

Như bạn thấy, tôi lựa chọn cách đặt tên an toàn để tránh rắc rối.

Bước 1:
Khởi động rabbitmq-server trên mỗi node.
Trên mỗi node, bạn có thể chạy

service rabbitmq-server start
hoặc
rabbitmq-server -detached

Trong cách thứ hai, bạn có thể sẽ gặp một warning:
Warning: PID file not written; -detached was passed.
Đừng quá lo lắng. Trong manual của rabbitmq-server có cho biết khi chạy với tham số -detached server process sẽ hoạt động ở chế độ background và điều đó khiến cho pid của process không được ghi vào pid file.

Bước 2:
Chọn một node làm khởi điểm sau đó các node còn lại sẽ join với node khởi điểm để hình thành lên cluster.

Trước khi thực hiện, chúng ta thử xem cluster status của từng node trước khi join với nhau. Trên mỗi node, bạn thực hiện lệnh
rabbitmqctl cluster_status

Và đây là kết quả:

Trên rabbit@rabbit1

Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1]}]}]

Trên rabbit@rabbit2

Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit2]}]}]

Trên rabbit@rabbit3

Cluster status of node rabbit@rabbit3 ...
[{nodes,[{disc,[rabbit@rabbit3]}]}]

Có thể thấy mỗi node đang là một cluster riêng biệt. Tôi sẽ phải gom cả ba node này để hình thành một cluster duy nhất.

Giả sử, tôi chọn node rabbit@rabbit2 làm node khởi điểm. Với vai trò node khởi điểm, node rabbit@rabbit2 sẽ không cần cấu hình gì thêm.

Đảm bảo node 2 đang chạy

[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit2]}]},
 {running_nodes,[rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Tôi cần join node 1 với node 2

[root@rabbit1 ~]# rabbitmqctl stop_app
Stopping node rabbit@rabbit1 ...
[root@rabbit1 ~]# rabbitmqctl join_cluster rabbit@rabbit2
Clustering node rabbit@rabbit1 with rabbit@rabbit2 ...
[root@rabbit1 ~]# rabbitmqctl start_app
Starting node rabbit@rabbit1 ...

Làm tương tự với node 3

[root@rabbit3 ~]# rabbitmqctl stop_app
Stopping node rabbit@rabbit3 ...
[root@rabbit3 ~]# rabbitmqctl join_cluster rabbit@rabbit2
Clustering node rabbit@rabbit3 with rabbit@rabbit2 ...
[root@rabbit3 ~]# rabbitmqctl start_app
Starting node rabbit@rabbit3 ...

Bước 3:
Xem cluster status trên mỗi node.

Trên node 1

[root@rabbit1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit2,rabbit@rabbit3,rabbit@rabbit1]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Trên node 2

[root@rabbit2 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit3,rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Trên node 3

[root@rabbit3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit3 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Bạn có thể cấu hình cluster trong config. Trên mỗi node, bạn chỉ cần khai báo dòng sau trong /etc/rabbitmq/rabbitmq.config

{cluster_nodes, {['rabbit@rabbit1','rabbit@rabbit2','rabbit@rabbit3'], disc}}

Nhận xét:
Có thể thấy tất cả các node đã nhìn thấy nhau. Tất cả đều là disc node (mặc định). Tất cả các node đều đang running. Cluster_name được lấy theo node name của node khởi điểm và không có một partition nào trong cluster.

Một node trong cluster có thể bị stop/start (dùng rabbitmqctl stop_app/rabbitmqctl start_app trên chính node đó) đồng nghĩa ngừng cung cấp dịch vụ trong cluster nhưng bản thân node đó vẫn không bị loại khỏi cluster

Thực hiện restart cluster

Chúng ta sẽ restart lần lượt từng node.

Giả sử tôi thực hiện restart theo thứ tự sau:
stop node 3 -> stop node 1 -> start node 3 -> start node 1. Node 2 vẫn giữ hoạt động để đảm bảo dịch vụ không down.

Stop node 3, node 1

Trên node 3:

[root@rabbit3 ~]#  rabbitmqctl stop
Stopping and halting node rabbit@rabbit3 ...

Bạn có thể dùng service rabbitmq-server stop thay cho rabbitmqctl top

Trên node 1:

[root@rabbit1 ~]# service rabbitmq-server stop
Stopping rabbitmq-server: rabbitmq-server.

Xem cluster status trên node 2:

[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Chỉ còn một mình node 2 đang hoạt động

Start node 3, node 1

Trên node 3:

[root@rabbit3 ~]# service rabbitmq-server start
Starting rabbitmq-server: SUCCESS
rabbitmq-server.

Trên node 1:

[root@rabbit1 ~]# service rabbitmq-server start
Starting rabbitmq-server: SUCCESS
rabbitmq-server.

Xem cluster status trên node 2:

[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit3,rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Như vậy, ngay sau khi được start trở lại, các node sẽ tự động tham gia vào cluster và running luôn.

Trong các trường hợp có sự cố nghiêm trọng như toàn bộ các node đều down lần lượt hoặc tất cả đều down đồng thời thì quy trình start cluster lại hơi khác một chút. Chúng ta đi vào từng trường hợp một.

Trường hợp thứ nhất: Tình huống xảy ra khi bạn cần restart cluster để upgrade cho rabbitmq hoặc erlang. Sau khi node 1, node 2 được bạn stop thì thảm họa xảy ra với node còn lại. Node còn lại bị down ngoài ý muốn. Trong trường hợp này việc khởi động lại cluster đòi hỏi thứ tự: Node cuối cùng bị down phải là node đầu tiên được start. Giả sử các node bị down theo thứ tự: node 3 -> node 1 -> node 2. Sau đó tôi cố gắng start các node 3 hoặc node 1 đầu tiên. Tôi sẽ không thành công. Rabbitmq để lại vài dòng log sau:

This cluster node was shut down while other nodes were still running.
To avoid losing data, you should start the other nodes first, then
start this one. To force this node to start, first invoke
"rabbitmqctl force_boot". If you do so, any changes made on other
cluster nodes after this one was shut down may be lost.

Để khởi động được cluster, bạn chỉ cần tuân theo nguyên tắc, start node 2 đầu tiên. Với các node sau, thứ tự không quan trọng. Bạn có thể dùng thứ tự node 2 – > node 1 -> node 3 hoặc node2 -> node 3 -> node1.

Trường hợp thứ hai: Cũng giống trường hợp một nhưng đáng tiếc là node 2 bị sự cố quá nghiêm trọng không thể phục hồi được. Vậy là node cuối cùng không thể boot được. Lúc này bạn phải ép một node không phải node down cuối cùng làm node khởi điểm

[root@rabbit1 root]# rabbitmqctl force_boot
Forcing boot for Mnesia dir /var/lib/rabbitmq/mnesia/rabbit@rabbit1 ...
[root@rabbit1 root]# service rabbitmq-server start
Starting rabbitmq-server: SUCCESS
rabbitmq-server.

Sau đó bạn khởi động lại các node kế tiếp.

Trường hợp thứ ba: Khủng khiếp hơn ! Bạn chẳng làm gì nhưng cụm server mà chứa rabbitmq cluster bị crash đột ngột. Lúc này thì bạn chẳng thể biết node nào down trước hay down sau cả. Cách xử lý giống hệt trường hợp thứ hai

Rời một node khỏi cluster

Cách 1: Để cho bản thân node đó quên rằng nó đã từng ở trong cluster. Giả sử tôi muốn tách node 2 khỏi cluster hoàn toàn.

[root@rabbit2 root]# rabbitmqctl stop_app                                                                                                      
Stopping node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl reset
Resetting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit2]}]},
 {running_nodes,[rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Để reset thành công, bạn không được config cluster trong file cấu hình.
Reset đồng thời sẽ xóa mọi data của node 2 như vhost, user, exchange, queue…

Cách 2: Làm cho các node còn lại trong cluster hắt hủi node cần được tách khỏi cluster 🙁

[root@rabbit2 root]# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 …

[root@rabbit3 root]# rabbitmqctl forget_cluster_node rabbit@rabbit2
Removing node rabbit@rabbit2 from cluster …

Lúc này các node còn lại trong cluster đều đã không coi node 2 nằm trong cluster nhưng node2 vẫn không chịu chấp nhận thực tế phũ phàng đó. Nếu bạn start_app node 2

Error: {error,{inconsistent_cluster,"Node rabbit@rabbit2 thinks it's clustered with node rabbit@rabbit3, but rabbit@rabbit3 disagrees"}}

Để node 2 hoạt động được bình thường, bạn phải làm nó quên đi nó từng thuộc về cluster.

[root@rabbit2 root]# rabbitmqctl reset
Resetting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit2]}]},
 {running_nodes,[rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Thêm một node vào cluster

[root@rabbit2 root]# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl join_cluster rabbit@rabbit3
Clustering node rabbit@rabbit2 with rabbit@rabbit3 ...
[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
root@rabbit2 roorabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit3,rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Nếu cố join_cluster từ một running node, bạn sẽ gặp:

Error: mnesia_unexpectedly_running

Thêm một RAM node

So sánh RAM node với disc node
Sự khác biệt lớn nhất là ram node chỉ giữ metadata của nó trong memory còn bản thân các queue data vẫn lưu xuống disk. Sự khác biệt này cho phép ram node ít tạo ra các hoạt động IO hơn nên performance tốt hơn disc node. Một cluster hoàn toàn chỉ có ram node thì rất có nguy cơ mất metadata. Giải pháp an toàn hơn cả là trộn lẫn ram node và disc node. Trong cluster, phần metadata được replicate giữa các node (disc node lưu metadata trên disk) nên sẽ không lo mất sạch metadata.

[root@rabbit2 root]# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl join_cluster --ram rabbit@rabbit3
Clustering node rabbit@rabbit2 with rabbit@rabbit3 ...
[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit3,rabbit@rabbit1]},{ram,[rabbit@rabbit2]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit3,rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Thay đổi node type

[root@rabbit2 root]# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl change_cluster_node_type disc
Turning rabbit@rabbit2 into a disc node ...
[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit3,rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]
[root@rabbit2 root]# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl change_cluster_node_type ram
Turning rabbit@rabbit2 into a ram node ...
[root@rabbit2 root]# rabbitmqctl start_app
Starting node rabbit@rabbit2 ...
[root@rabbit2 root]# rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit3,rabbit@rabbit1]},{ram,[rabbit@rabbit2]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit3,rabbit@rabbit2]},
 {cluster_name,<<"rabbit@rabbit2">>},
 {partitions,[]}]

Mô hình load balancing với rabbitmq cluster

alt text

Nếu bạn cấu hình HA queue, queue data giữa các node sẽ được đồng bộ (Trong phần tới tôi sẽ trình bày cách cấu hinh HA cho queue). Nghe có vẻ rất giống mysql replication phải không. Nhưng thực tế thì không giống vậy. Trong hệ rabbitmq cluster, khi áp dụng HA policy, một queue sẽ có master và các slave. Queue được tạo ra trên node nào thì queue đó sẽ là master các replicate của queue đó trên các node còn lại sẽ là slave queue. Tính chất master-slave không áp dụng trên cụ thể một node mà trên cụ thể một queue. Một node có thể là master với queue này nhưng lại là slave với queue khác. Điểm thú vị là request đến queue đi từ client qua load balancer sẽ được chuyển hướng đến node mà chứa master queue

Xem hình minh họa ở dưới

alt text

Master queue nằm trên node 2 (nơi queue đó được tạo ra). Request từ client đến queue đó đi qua load balancer đập vào node 3 nhưng node 3 sẽ thay vì tự phục vụ luôn thì chuyển hướng request đến node 2 (nơi chứa master queue). Vì nguyên tắc họat động này mà HA policy trên rabbitmq không giúp chia tải trên các node được mà chỉ cho phép đảm bảo dịch vụ vẫn vận hành khi có sự cố. Khi node chứa master queue bị down, rabbitmq cluster sẽ promote node chứa slave queue có thời gian hoạt động lâu nhất lên làm master.

Vậy có cách nào khắc phục để chia tải giữa các node không ?

  • Bạn có thể tạo queue đều trên tất cả các node trong cluster do vậy các master queue sẽ trải đều trên toàn bộ cluster nên hạn chế các extra network hop giống như trong hình minh họa. Cách này bạn vẫn có thể sử dụng load balancer để điểm trup cập từ client được tập trung.
  • Client có một danh sách các queue và biết được master queue nằm trên node nào để truy cập trực tiếp. Cách này sẽ không còn cần đến load balancer nữa.

Vấn đề timeout

Bản thân client sẽ luôn giữ kết nối đến rabbitmq. Sẽ không có timeout nếu như bạn kết nối trực tiếp nhưng khi qua một proxy thì vấn đề xuất hiện. Proxy sẽ không giữ kết nối liên tục giữa client và backend nên trong quá trình sử dụng bạn có thể thấy hiện tượng client bị mất kết nối sau một quãng thời gian không sử dụng. Đáng tiếc rabbitmq client không có cơ chế reconnect lại.

Một linux client có cơ chế tự động gửi lại keep-alive packet để duy trì kết nối nhưng quãng thời gian này quá lâu. cat /proc/sys/net/ipv4/tcp_keepalive_time trả về giá trị 7200 nghĩa là cứ sau 2 tiếng mới có một cú gửi keep-alived. Muốn proxy duy trì kết nối thì keep-alived packet phải được gửi trước khi timeout của proxy kết thúc. Trong trường hợp của tôi proxy là haproxy. Tôi điều chỉnh chút ít về cấu hình. Tôi bổ sung ba dòng sau vào cụm backend rabbitmq

timeout client  3h
timeout server  3h
option          clitcpka

Kết thúc phần hai. Trong phần tới, tôi sẽ trình bày về network partition trong rabbitmq cluster

Nguồn tham khảo:
http://insidethecpu.com/2014/11/17/load-balancing-a-rabbitmq-cluster/
https://stackoverflow.com/questions/10461808/how-to-load-distribution-in-rabbitmq-cluster
https://deviantony.wordpress.com/2014/10/30/rabbitmq-and-haproxy-a-timeout-issue/

Tìm hiểu RabbitMQ – Phần 1

 Database  Comments Off on Tìm hiểu RabbitMQ – Phần 1
Oct 282015
 

Giới thiệu

RabbitMQ là một message broker ( message-oriented middleware) sử dụng giao thức AMQP – Advanced Message Queue Protocol (Đây là giao thức phổ biến, thực tế rabbitmq hỗ trợ nhiều giao thức). RabbitMQ được lập trình bằng ngôn ngữ Erlang. RabbitMQ cung cấp cho lập trình viên một phương tiện trung gian để giao tiếp giữa nhiều thành phần trong một hệ thống lớn ( Ví dụ openstack – Một công nghệ rất thú vị hi vọng một ngày nào đó tôi đủ sức để viết vài bài về chủ đề này ). RabbitMQ sẽ nhận message đến từ các thành phần khác nhau trong hệ thống, lưu trữ chúng an toàn trước khi đẩy đến đích.

Thực sự, với lập trình viên thì rabbitmq rất đáng giá. Nếu không có các hệ thống message broker như rabbitmq thì bất cứ lúc nào cần đẩy data giữa các thành phần trong hệ thống, lập trình viên cần một kết nối trực tiếp. Một hệ thống càng lớn. Số thành phần càng nhiều, mức độ trao đổi message giữa càng thành phần cũng vì thế tăng lên khiến việc lập trình trở nên phức tạp. Tôi từng đọc vài bài báo về lập trình thì thấy họ khuyến cáo các lập trình viên chỉ nên tập trung vào business logic của ứng dụng còn các công tác hậu trường thì nên được tái sử dụng các giải pháp đã có. Rabbitmq cũng là một giải pháp rất tốt trong các kiến trúc hệ thống lớn.

Tại sao lại sử dụng RabbitMQ

Chúng ta thử xem các message broker như rabbitmq đem lại lợi ích gì trong việc thiết kế ứng dụng. Trong một hệ thống phân tán (distributed system), có rất nhiều thành phần. Nếu muốn các thành phần này giao tiếp được với nhau thì chúng phải biết nhau. Nhưng điều này gây rắc rối cho việc viết code. Một thành phần phải biết quá nhiều đâm ra rất khó maintain, debug. Giải pháp ở đây là thay vì các liên kết trực tiếp, khiến các thành phần phải biết nhau thì sử dụng một liên kết trung gian qua một message broker. Với sự tham gia của message broker thì producer sẽ không hề biết consumer. Nó chỉ việc gửi message đến các queue trong message broker. Consumer chỉ việc đăng ký nhận message từ các queue này.

Tất nhiên, có thể có một giải pháp là sử dụng database để lưu các message trong các temporary table. Tuy nhiên xét về hiệu năng thì không thể bằng message broker vì một số lý do: Tần xuất trao đổi message cao sẽ làm tăng load của database, giảm performance đáng kể. Trong môi trường multithread, database cần có cơ chế lock. Lock cũng làm giảm performance. Sử dụng message broker sẽ không có vấn đề này.

Vì producer nói chuyện với consumer trung gian qua message broker nên dù producer và consumer có khác biệt nhau về ngôn ngữ thì giao tiếp vẫn thành công. Dù viết bằng java, python, php hay ruby… thì chỉ cần thỏa mãn giao thức với message broker thì thông suốt hết. HIện nay, rabbitmq cũng đã cung cấp client library cho khá nhiều các ngôn ngữ rồi. Tính năng này cho phép tích hợp hệ thống linh hoạt.

Một đặc tính của rabbitmq là asynchronous. Producer không thể biết khi nào message đến được consumer hay khi nào message được consumer xử lý xong. Đối với producer, đẩy message đến message broker là xong việc. Consumer sẽ lấy message về khi nó muốn. Đặc tính này có thể được tận dụng để xây dựng các hệ thống lưu trữ và xử lý log. ELK stack – Elasticsearch Logstash Kibana là một ví dụ. Đây là hệ thống được sử dụng trong môi trường DevOps khá hiệu quả. Giải quyết bài toán chia sẻ log của ứng dụng cho dev. Log được đẩy vào message broker rồi qua logstash lưu trữ vào elastic để đánh index. Sau đó index được kibana (một web interface) sử dụng để thực hiện truy vấn và hiển thị kết quả

alt text

Bản thân redis cũng có thể đảm nhận vai trò của message broker ( Dù cho mục đích ban đầu của nó không phải vậy. Đây là tính năng mở rộng sau này của redis ) Mô hình trên bạn có thể hoàn toàn thay redis queue bằng rabbitmq.

Bên cạnh các lợi ích kể trên, rabbitmq còn có nhiều tính năng thú vị khác như:

  • cluster: các bạn có thể gom nhiều rabbitmq instance vào một cluster. Một queue được đinh nghĩa trên một instance khi đó đều có thể truy xuất từ các instance còn lại. Có thể tận dụng để làm load balancing (tuy rằng có hạn chế, tôi sẽ nói sau)
  • high availibilty: cho phép failover khi sử dụng mirror queue.
  • reliability: có cơ chế ack để đảm bảo message được nhận bởi consumer đã được xử lý.

Mô hình

alt text

Có thể hiểu message broker gần như bưu điện. Site A theo cách gọi của rabbitmq là producer (người gửi thông điệp). Site B và Site C theo cách gọi của rabbitmq là consumer (người nhận thông điệp). Producer connect đến message broker để đẩy message. Message sẽ đi qua message broker để đến được consumer. Cấu trúc của message broker chỉ gồm hai phần exchange và queue.

Exchange có nhiều loại. Trong hình vẽ trên exchange type là fanout. Lựa chọn các exchange type khác nhau sẽ dẫn đến khác đối xử khác nhau của message broker với thông điệp nhận được từ producer. Exchange được bind (liên kêt) đến một số queue nhất định. Với exchange type là fanout, message sẽ được broadcast đến các queue được bind với exchange. Consumer sẽ connect đến message broker để lấy message từ các queue.

Cài đặt và cấu hình cơ bản

Các bạn có thể tham khảo hướng dẫn trực tiếp từ trang chủ của rabbitmq:
https://www.rabbitmq.com/install-rpm.html

Vì rabbitmq được lập trình bằng erlang nên bạn cần cài đặt erlang trước. Tôi cài đặt erlang từ epel repo:

wget http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
rpm -ivh epel-release-6-8.noarch.rpm
yum install --enablerepo=epel erlang

Sau đó, tôi cài tiếp rabbitmq:

wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.5.2/rabbitmq-server-3.5.2-1.noarch.rpm
rpm --import https://www.rabbitmq.com/rabbitmq-signing-key-public.asc
rpm -ivh rabbitmq-server-3.5.2-1.noarch.rpm

VIệc cài đặt đến đây là xong. Bạn có thể start thử service của rabbitmq bằng cách:
service rabbitmq-server start

Cấu hình mẫu của rabbitmq đi kèm gói cài đặt nằm ở:
/usr/share/doc/rabbitmq-server-3.5.2/
Tôi copy về khu vực đặt file cấu hình của rabbitmq rồi đổi tên:

cp /usr/share/doc/rabbitmq-server-3.5.2/rabbitmq.config.example /etc/rabbitmq/
mv /etc/rabbitmq/rabbitmq.config.example  /etc/rabbitmq/rabbitmq.config

Cấu hình của rabbitmq mặc định chạy khá ổn. Các bạn có thể sử dụng luôn mà không cần bận tâm tùy chỉnh cấu hình.

Cài đặt management plugin

Rabbitmq có đi kèm một plugin cho phép quản trị hoạt động qua một web interface trông rất trực quan và thân thiện. Nhưng mặc định, plugin này không được enable. Để enable, bạn thực hiện lệnh sau:

rabbitmq-plugins enable rabbitmq_management

Tất cả các hoạt động quản trị qua web cũng có thể thực hiện qua một command line tool có tên là rabbitmqadmin. Tool này đi kèm trong management plugin. Bạn cũng chỉ có thể sử dụng nó sau khi đã enable management plugin.

Cách download rabbitmqadmin tool:

Tôi cài đặt rabbitmq trên một server có ip 192.168.3.252 nên địa chỉ download sẽ là:

http://192.168.3.252:15672/cli/rabbitmqadmin

Cách sử dụng tool này trong các tình huống cụ thể sẽ nằm trong các phần tới.

Một số đoạn script tiện ích hay dùng

 Linux  Comments Off on Một số đoạn script tiện ích hay dùng
Oct 282015
 

Thời kỳ mới đi làm tôi nghĩ cứ phải gõ thật nhiều cho quen cho nhớ nhưng lâu dần việc đó cho cảm giác thật nhàm chán. Hiện giờ, những gì tôi hay làm thường xuyên tôi thường lưu vào một nơi. Khi cần tôi chỉ việc lôi ra, sửa lại đôi chút. Kipalog là một nơi lưu trữ như vậy, thậm chí còn tốt hơn 😀

Bài viết này mục đích sẽ tập trung các đoạn script nhỏ ngắn. Mỗi script tôi sẽ đề cập đến tình huống sử dụng nó. Nếu bạn nào thấy có thể làm tốt hơn, tối ưu hơn, hoặc chỉ cần một cách khác hơn thì hãy để lại comment. Những comment của bạn rất giá trị với tôi. Bài viết này sẽ được update dài dài. Bạn nào thích có thể bổ sung thêm các script nữa nhé 😀

Tắt hàng loạt process theo pid

Tình huống: 
Tại sao tôi không dùng killall ? Vì một số ứng dụng tạo ra nhiều process có tên khác nhau ví dụ mysql chẳng hạn. Khi start mysql service thường nó duy trì hai process mysqld_safe và mysqld và một còn một lý do là đôi khi process bị treo, signal SIGTERM không thể tắt được process. Trong tình huống đó tôi phải dùng SIGKILL. Tuy không phải giải pháp tốt nhưng đôi khi vẫn phải dùng. Killall mặc định lại sử dụng signal SIGTERM.

Script:
ps -elf | grep <process_name> | grep -v "grep" | awk '{print $4}' | xargs kill -s SIGTERM

grep -v “grep” để loại bỏ chính process grep mà đang sử dụng trong script
$4 là vị trí của PID – cột thứ 4 trong output của ps -elf

UPDATE 1:
Bạn Lê Mạnh Cường có đóng góp một cách khác và cũng ít phải qua nhiều pipe hơn nên sẽ tối ưu hơn. Tôi cập nhật luôn vào bài viết chính:

ps -elf | awk '/<process_name>/ && !/awk/ {print $4}' | xargs -r kill -s SIGTERM

  • Số pipe sử dụng đã giảm hẳn
  • Câu lệnh cuối có sử dụng tham số -r của xargs để ép xargs sẽ không làm gì cả nếu input không có. (-r là một gnu extension)

Sử dụng nohup để duy trì process ngay khi cả shell bị đóng

Tình huống: 
Một số process chạy background làm nhiệm vụ lắng nghe sự kiện nào đó thì cần được duy trì liên tục. Khởi động một lần và chạy liên tục. Nghe có vẻ giống một service. Thực ra có thể viết một init script để khởi chạy các process kiểu như vậy. Nhưng có một cách đơn giản hơn. Đó là dùng nohup. Tôi không chắc là tốt hơn nhưng chỉ là đơn giản hơn.

Tiện ích này cho phép duy trì process chạy trong chế độ background ngay cả khi shell mà tôi gọi nohup bị đóng. Nó cũng cho phép ghi log.

Script:

nohup  /usr/bin/php long_running_process.php > /var/log/nohup_long_running_process.log &

Nếu tôi cần câu lệnh trên được chạy sau khi hệ thống reboot thì tôi chỉ cần đặt câu lệnh đó vào một script. Ví dụ: test_long_running_process.sh Sau đó trong file /etc/rc.local (File này luôn được gọi mỗi khi hệ thống khởi động) Tôi khai báo:
/full/path/to/test_long_running_process.sh

Duy trì một số lượng file nhất định trong một thư mục

Tình huống:
Để đảm bảo hệ thống phục hồi khi có thảm họa xảy ra, tôi cần thực hiện backup định kỳ. Các bản backup này ban đầu thì không đáng kể về dung lượng nhưng quá trình tích lũy sẽ ngốn sạch không gian lưu trữ. Để tránh tình huống này xảy ra, tôi cần phải định kỳ xóa bớt các bản backup đã quá cũ. Ở đây có ba yêu cầu cho nhiệm vụ này:

  • Duy trì một số lượng nhất định các bản backup. Chú ý các bản backup ở đây là thư mục
  • Các bản backup được giữ lại phải là mới nhất
  • Định kỳ theo dõi và xóa bỏ nếu số lượng bản backup vượt quá số quy định.

Điều kiện:
Các thư mục kết xuất từ quá trình backup không nên đặt ở dạng quá đặc biệt như thư mục ẩn, có dấu – ở đầu dòng hoặc có new line trong tên. Script không hỗ trợ xử lý các thư mục có tên kỳ dị như vậy.

Script:
Ở đây tôi duy trì ba bản backup mới nhất
Script backup_cleaner.sh

ls -td1 /data/backup/*/ | tail -n +4 | xargs -r rm -rfv 2> /var/log/backup_cleaner.log

-t để sort các thư mục con trong thư mục /data/backup theo thời gian. Những thư mục mới nhất sẽ xếp trên đầu.
-d để chỉ list các directory trong /data/backup/*/ vì các bản backup được kết xuất ở dạng thư mục.

Chú ý:
Để ls chỉ liệt kê được thư mục con của /data/backup. Bạn phải dùng dạng cú pháp

ls -td /data/backup/*/

Sử dụng

ls -td /data/backup/*

sẽ trả về cả file lẫn thư mục con.

-1 để các kết quả được sắp xếp theo từng dòng, mỗi dòng một kết quả (Script vẫn chạy đúng mục đích khi không có tham số -1 này)

Kết quả của câu lệnh ban đầu được chuyển vào tail để lấy ra các kết quả từ thứ tư trở đi rồi đẩy vào rm -rf để xóa. Như vậy sẽ luôn giữ lai ba kết quả đầu tiên, cũng là mới nhất.

Chú ý:
Vì kết quả cuối cùng của script là xóa thư mục nên trong lệnh đầu tiên tôi phải sử dụng đường dẫn tuyệt đối để câu lệnh rõ ràng nhất có thể.

Cuối cùng để hoạt động này được định kỳ thực hiện, tôi đẩy script này vào crontab
sudo crontab -e

*/1 * * * * /full/path/to/backup_cleaner.sh

Deploying Django project with Nginx and Uwsgi

 Programing  Comments Off on Deploying Django project with Nginx and Uwsgi
Oct 272015
 

Sorry for a small pause, this time I will try to show you how to deploy a django project with Nginx and Uwsgi.

Speaking you have debian, follow these steps:

we first install virtualenv:

pip install virtualenv

then we open a new virtual environment for our new django project. Virtualenv is a cool stuff, you won’t have dependency hell with it, just your own virtualenv where you can install and run any modules you want without messing up with the modules that are installed systemwide or etc..

lets now create and activate our own virtualenv:

virtualenv project_env
cd project_env
source bin/activate

and now we will install our wonderful django framework making sure that our virtualenv is activated. It is not important that we are inside the virtualenv folder, main thing virtualenv is activated:

pip install Django
django-admin.py startproject mysite

now we install uwsgi into our virtualenv:

pip install uwsgi

Now, we need to install Nginx, here we go out of our virtualenv by doing:

deactivate

and install nginx:
sudo apt-get install nginx

Configure now Nginx:

first, you need to uwsgi_params file which is availablehere: https://github.com/nginx/nginx/blob/master/conf/uwsgi_params

Just copy this into your project directory where nginx will refer to. I will you this in a while.

Now create a mysite_nginx.conf file and put this content into it:

upstream mysite {
    server unix:///var/www/mysite/mysite.sock;
}

server {
    listen      80;
    server_name .mysite.com;
    charset     utf-8;
    client_max_body_size 75M;

    location /media  {
        alias /var/www/mysite/mysite/media;
    }

    location /static {
        alias /var/www/mysite/mysite/static;
    }

    location / {
        uwsgi_pass  mysite;
        include     /etc/nginx/uwsgi_params;
        proxy_read_timeout 150;
    }

    location /nginx_status {
        stub_status on;
        access_log   off;
        # allow 127.0.0.1;
        # deny all;
    }
}

Now we simlink this file to nginx sites-enabled folder:

sudo ln -s ~/path/to/your/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/

and collect all django static files into static folder:
python manage.py collectstatic

and restart the nginx:
sudo /etc/init.d/nginx restart

Now we create a ini file and put this content into it:

[uwsgi]
socket = /var/www/mysite/mysite.sock
chdir = /var/www/mysite
module = mysite.wsgi:application
virtualenv = /var/www/virtualenvs/project_env/
buffer-size = 8192
processes = 60
env = DJANGO_SETTINGS_MODULE=mysite.settings
enable-threads = True
single-interpreter = True
uid = www-data
gid = www-data
vacuum = True
disable-logging = true
logger = file:/var/www/mysite/log/uwsgi_err.log

with this, we have all our uwsgi configurations in one single file – easy to handle and configure.

As you noticed, we installed uwsgi only in our virtualenv, now we need to install it systemwide (look at deactivate with which we leave the virtualenv).

deactivate
sudo pip install uwsgi

and create vassals folder

mkdir /etc/uwsgi
mkdir /etc/uwsgi/vassals
cd /etc/uwsgi/vassals/

and simlink our ini file to this vassals folder:

ln -s /var/www/mysite/conf/uwsgi.ini mysite.ini

We are almost ready. Now we open the rc.local file and put this command into it before “exit 0”

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi/emperor.log

and save the file. With this, the uwsgi runs as daemon and restarts automatically if system reboots etc etc.. nice stuff

aaand last step: give this command into your console:

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi/emperor.log

and restart nginx:
/etc/init.d/nginx restart

Hope, you didnot get any errors while deploying and that this post will help someone! have fun!

Hướng dẫn tăng cường bảo mật hệ thống máy chủ Linux

 Linux, Security  Comments Off on Hướng dẫn tăng cường bảo mật hệ thống máy chủ Linux
Oct 272015
 

Hệ điều hành Linux được biết đến là hệ điều hành có tính bảo mật cao tuy nhiên cần có thêm một số cấu hình nhằm tăng độ an toàn cho hệ thống. Dưới đây là một số lời khuyên hữu ích dành cho hệ thống của bạn:

1. Bảo vệ an toàn từ phần cứng (BIOS)

Khi khởi động hệ thống máy tính thành phần đầu tiên được chạy chính là BIOS. Để đảm bảo an toàn cho hệ thống, người quản trị nên tắt chế độ boot từ các thiết bị như ổ đĩa CD/DVD, các thiết bị ngoại vi, đĩa mềm.. trong cấu hình BIOS. Sau đó cần tạo mật khẩu cho BIOS và  GRUB nhằm hạn chế các truy cập trái phép từ chính hệ thống của bạn

2. Phân vùng ổ cứng

Một cách thức để đảm bảo an toàn dữ liệu trước rủi ro là nên phân vùng ổ cứng cho hệ thống của mình. Bằng cách tạo ra các phân vùng khác nhau, dữ liệu được chia nhỏ và nhóm lại. Khi có sự cố xảy ra tại một phân vùng nào đó, chỉ có những dữ liệu ở cùng phân vùng đó bị hỏng còn tại các phân vùng khác dữ liệu an toàn. Hệ thống của bạn cần có các phân vùng như sau và chắc chắn các ứng dụng của bên thứ 3 cần được cài đặt tại phân vùng /opt

  • /
  • /boot
  • /usr
  • /var
  • /home
  • /tmp
  • /opt

 

3. Hạn chế các dịch vụ không cần thiết

Một hệ thống máy tính khi cài đặt quá nhiều các gói không cần thiết, không những làm giảm hiệu năng của hệ thống khi tranh giành tài nguyên với các dịch vụ khác mà còn làm cho hệ thống xuất hiện các lỗ hổng từ chính các gói không cần thiết đó. Một cách giảm thiểu rủi ro là xoá hay tắt các dịch vụ khi không cần thiết. Ví dụ trên hệ điều hành CentOS bạn có thể thực hiện như sau:

  • Kiểm tra các dịch vụ trong hệ thống đang chạy ở mức độ 3
# /sbin/chkconfig –list | grep ‘3:on’
  • Khi tìm thấy các dịch vụ không cần thiết đang chạy bạn thực hiện lệnh sau để tắt dịch vụ này:
# chkconfig ten_dich_vu off
  • Và có thể xoá dịch vụ khỏi hệ thống của bạn sử dụng lệnh:
# yum -y remove ten_goi

 

4. Kiểm tra các cổng dịch vụ đang chờ kết nối

Cũng như khi hạn chế các dịch vụ không cần thiết, bạn cũng nên tối thiểu các cổng dịch vụ không cần thiết để tăng hiệu năng cũng như giảm thiểu các lỗ hổng trong hệ thống của bạn. Bạn có thể sử dụng câu lệnh ‘netstat’ để xem tất cả các cổng được mở và các chương trình sử dụng kết nối mạng. Khi kiểm tra và phát hiện các dịch vụ mạng không cần thiết bạn có thể sử dụng ‘chkconfig’ để tắt các dịch vụ đó.

Sử dụng lệnh sau để xem thông tin tất cả các cổng:

# netstat –tulpn

 

5. Đảm bảo an toàn dịch vụ SSH

Trở về trước, khi kết nối điều khiển máy chủ từ xa sử dụng các giao thức telnet rlogin, đây là các giao thức kết nối không an toàn khi chỉ kết nối sử dụng bản rõ mà không được mã hoá khi gửi dữ liệu. Tuy nhiên hiện Secure Shell (SSH) là giao thức được sử dụng rộng rãi bởi nó sử dụng công nghệ mã hoá khi giao tiếp với máy chủ. Tuy nhiên để đảm bảo an toàn cần cấu hình cho dịch vụ này như sau :

  • Mở file cấu hình dịch vụ SSH và thay đổi một số cấu hình:
# vi /etc/ssh/sshd_config
  • Tìm tới dòng cấu hình cổng và thay đổi cổng mặc định từ cổng 22 sang cổng khác ví dụ chuyển sang cổng 22000
Port 22000
  • Không cho phép đăng nhập bằng tài khoản root:
PermitRootLogin no
  • Chỉ cho phép đăng nhập mởi một số người dùng:
AllowUsers tennguoidung
  • Sử dụng giao thức SSH phiên bản 2:
Protocol 2

 

6. Thường xuyên cập nhật các bản vá lỗi của nhà phát hành

Luôn luôn để hệ thống của bạn được cập nhật bản mới nhất và các bản vá bảo mật. Ví dụ trên hệ điều hành CentOS:

# yum updates
# yum check-update

 

7. Vô hiệu hoá các Cronjob

Cron là một tiện ích mà người dùng có thể cho phép hoặc không cho phép các tác vụ (tasks) tự động chạy nền trên hệ thống theo định kỳ bằng cách sử dụng các cron daemon. Nó được điều khiển bởi các file/etc/cron.allow /etc/cron.deny. Để khoá người dùng sử dụng cron, thêm tên người dùng đó vàocron.deny ; cho phép người dùng sử dụng cron, thêm tên người dùng vào file cron.allow. Để vô hiệu hoá tất người dùng sử dụng cron, thêm từ khoá ‘ALL’ vào dòng cuối cùng của file cron.deny. Sử dụng câu lệnh:

# echo ALL >> /etc/cron.deny

 

8. Tắt chức năng tự động phát hiện các thiết bị cắm vào cổng USB

Các thiết bị USB trở nên rất nguy hiểm đối với hệ thống khi tin tặc có thể thêm chương trình chạy tự động vào thiết bị. Khi chúng được cắm vào hệ thống sẽ có khả năng đánh cắp dữ liệu. Vì vậy cần tắt các chức năng tự động phát hiện USB đảm bảo hệ thống thoát khỏi nguy cơ trên. Tạo tệp tin /etc/modprobe.d/no-usb và thêm dòng dưới đây:

install usb-storage /bin/true

 

9. Luôn luôn bật cơ chế SELinux

Security-Enhanced Linux (SELinux) là một cơ chế bảo mật điều khiển truy cập bắt buộc quy định trong nhân. Nhiều hệ thống vì ưu tiên hiệu năng hệ thống nên đã tắt cơ chế này. Vô hiệu hoá SELinux có nghĩa là tự loại bỏ cơ chế bảo mật của hệ thống. Vì vậy cần suy nghĩ khi lựa chọn hiện năng và mức độ bảo mật của hệ thông khi đưa vào hoạt động

SELinux cung cấp 3 chế độ cơ bản:

  • Enforcing: Đây là chế độ mặc định cho phép thực hiện tất cả các chính sách bảo mật trên hệ thống
  • Permissive : Ở chế độ này SELinux không thực thi các chính sách bảo mật mà nó cung cấp các cảnh báo về các hoạt động. Chế độ này rất hưu ích để hạn chế các vấn đề của SELinux
  • Disable : Tắt cơ chế SELinux

Để xem trạng thái hiện tại của cơ chế này sử dụng câu lệnh :

# sestatus

Nếu nó đang tắt cần bật bởi câu lệnh:

# setenforce enforcing

Trong hệ điều hành CentOS các cấu hình của SELinux được quản lý bởi file ‘/etc/selinux/config’

10. Loại bỏ giao diện KDE/GNOME

Khi hệ thống có mục đích sử dụng chính là hệ thống web (LAMP server) không cần sử dụng tới các giao diện X Window như KDE hay GNOME. Vì vậy nên tắt hoặc loại bỏ chúng để cải thiện an toàn cũng như hiệu năng của hệ thống. Một cách đơn giản tắt chúng là mở tệp tin ‘/etc/inittab’ và đặt chúng chạy ở mức độ 3. Xoá chúng khỏi hệ thống sử dụng câu lệnh”

# yum groupremove "X Window System"

 

11. Tắt giao thức Ipv6

Giao thức IPv6 là giao thực ưu việt để thay thế IPv4 khi giao thức đang dần cạn kiện IP, tuy nhiên hiện nay hầu hết các hệ thống đều sử dụng IPv4 nên giao thức IPv6 là không cần thiết và nên tắt giao thực này. Mở tập tin cấu hình mạng và thêm các dòng cấu hình sau để tắt.

Mở file:

# vi /etc/sysconfig/network

Thêm các dòng cấu hình:

NETWORKING_IPV6=no
IPV6INIT=no

 

12. Hạn chế người dùng sử dụng các mật khẩu cũ

Trong hệ thống sẽ là rất hữu ích nếu không cho phép các người dùng sử dụng các mật khẩu cũ giống nhau để hạn chế các nguy cơ mất an toàn cho hệ thống. Trong các hệ điều hành RHEL / CentOS / Fedora passwork cũ được lưu lại trong tệp tin “/etc/security/opasswd” và được quản lý bởi module PAM. Để cấu hình người dùng không được dùng một mật khẩu cũ quá 5 lần bạn làm theo hướng dẫn sau :

  • Mở tệp tin /etc/pam.d/system-auth
# vi /etc/pam.d/system-auth
  • Thêm dòng sau vào dòng có từ khoá “auth”
 auth        sufficient    pam_unix.so likeauth nullok
  • Sửa dòng có từ khoá “password” để không cho phép người dùng sử dụng lại mật khẩu quá 5 lần:
password   sufficient    pam_unix.so nullok use_authtok md5 shadow remember=5

 

13. Cấu hình sử dụng mật khẩu mạnh.

Có rất nhiều người thường sử dụng các mật khẩu yếu và các mật khẩu của họ thường bị các tin tặc dễ dàng lấy đi thông tin từ các phương thức tấn công băng các phương pháp tấn công từ điển hoặc tấn công dò quét mật khẩu. Vì vậy cần có một cơ chế ép các ngươi dùng sử dụng các mật khẩu mạnh. Để thực hiến điều này cần thêm cấu hình trong modun ‘pam_cracklib’ như sau:

  • Mở tập tin cấu hình
# vi /etc/pam.d/system-auth
  • Và thêm dòng có cấu hình yêu cầu các thông số độ dài tối thiểu của mật khẩu, sử dụng cả chữ in thường, chữ in hoa, chữ số, kí hiệu đặc biệt có trong mật khẩu như sau :
/lib/security/$ISA/pam_cracklib.so retry=3 minlen=8 lcredit=-1 ucredit=-2 dcredit=-2 ocredit=-1

 

14. Bật chế độ tường lửa

Sẽ là rất tốt khi bật chế độ tường lửa trong hệ thống, đảm bảo an toàn trước các truy cập trái phép đối với hệ thống. Hệ thống cần được thêm các luật trong iptables để lọc các gói tin đến, gói tin đi và gói tin chuyển tiếp tới hệ thống. Và có thể chỉ định rõ các địa chỉ đích, địa chỉ nguồn cho phép hoặc không cho phép sử dụng các cổng và giao thức được chỉ định.

Đề xem các luật có trong hệ thống sử dụng lệnh sau:

# iptables -L -n -v 

 

15. Kiểm tra các tài khoản không có mật khẩu

Trong hệ thốn mỗi tài khoản có mật khẩu rỗng có nghĩa là đã để lộ các phương thức xác thực trái phép mà tất cả mọi người có thể thực hiện, đó là một mối nguy hiểm lớn đối với hệ thống. Vì vậy cần chắc chắn rằng tất cả các tài khoản cần có mật khẩu mạnh và không ai khác được cho phép truy cập. Vì vây cần kiểm tra các tài khoản không có mật khẩu như câu lệnh dưới đây và cần xem xet khoá các tài khoản này lại.

# cat /etc/shadow | awk -F: '($2==""){print $1}'

 

16. Tập trung log của các máy chủ về máy chủ chuyên dụng

Di chuyển các log ghi lại hoạt động của hệ thống về các máy chủ chuyên dụng là cách để phòng ngừa các tin tặc thay đổi dữ liệu khi chúng có quyền tryu cập trái phép vào hệ thống. Vì vậy có thể chắc chắn hệ thống đang an toàn. Dưới đây là hông tin về các tập tin log mặc định và cách sử dụng của chúng.

  • /var/log/message– Ghi lại các hoạt động của toàn hệ thống
  • /var/log/auth.log– Log xác thực hệ thống
  • /var/log/kern.log– Log của nhân
  • /var/log/cron.log– Log các tiến trình được tự động chạy
  • /var/log/maillog– Log dịch vụ mail
  • /var/log/mysqld.log– Log dịch vụ hệ quản trị dữ liệu mysql
  • /var/log/utmpor /var/log/wtmp : Lịch sử đăng nhập
  • /var/log/yum.log: Log dịch vụ YUM

 

17. Sao lưu dữ liệu quan trọng

Trong một hệ thống sản xuất, thực sự cần thiết khi sao lưu và giữ các giữ liệu quan trọng một cách cẩn thận. Khi có rủi ro trong hệ thống có thể dễ dàng phục hồi bởi các dữ liệu đã được sao lưu.

18. Không cho phép thay đổi thư mục /boot

Nhân hệ thống và các tập tin liên quan được đặt ở thư mục /boot, nó được đặt mặc địch cho phép đọc và sửa. Cần thay đổi để chỉ cho phép đọc thư mục này là thực sự cần thiết để đảm bảo cho hệ thống được hoạt động ổn định. Để thực hiện điều này cần thực hiện theo các bước sau:

  • Mở tệp tin “/etc/fstab”:
# vi /etc/fstab
  • Và cần thêm dòng sau vào cuối của tệp tin:
LABEL=/boot     /boot     ext2     defaults,ro     1 2

Cần ghi lại điều này mà thay đổi quyền của thư mục khi cập nhật nhân trong tương lai.

19. Chặn các gói tin ICPM và các yêu cầu Broadcast

Nhiều tin tặc sử dụng các gói tin ICMP để xác định các địa chỉ IP và tấn công các máy chủ có IP này. Để ngăn chặn điều này cần ngăn chặn các gói tin theo cách thay đổi tập tin “/etc/sysctl.conf” để chặn pinghoặc các yêu cầu broadcast.

  • Chặn các gói tin ICMP:
net.ipv4.icmp_echo_ignore_all = 1
  • Chặn các yêu cầu broadcast:
net.ipv4.icmp_echo_ignore_broadcasts = 1

Để cập nhật các thay đổi cần chạy câu lệnh :

# sysctl –p

Trên đây là một số mẹo để cải thiện an toàn cho hệ thống Linux hãy kiểm tra và bổ sung để hệ thống trách gặp các rủi do đáng tiếc

Key-Based SSH Logins With PuTTY from Windows

 Linux  Comments Off on Key-Based SSH Logins With PuTTY from Windows
Sep 152015
 

Chào các bạn,

Việc thiết điều khiển ssh máy chủ Linux từ Windows có lẽ không còn lại với các quản trị viên. Việc nhớ và xác thực mật khẩu khá phiền toái và đôi khi không an toàn khi bạn thực hiện ssh từ mạng không thực sự trust. SSH-KEY là một thay thế khá tốt đảm bảo tính ổn định và an toàn. Bài viết này sẽ hướng dẫn các bạn làm điều đó.

1.Các phần mềm cần thiết:

http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe

http://the.earth.li/~sgtatham/putty/latest/x86/puttygen.exe

http://the.earth.li/~sgtatham/putty/latest/x86/pageant.exe

2. Các bước cài đặt:

Bước 1: Sinh key thực hiện trên máy chủ Windows 7

onlinelab1

 

 

Screenshot_2

 

 

Screenshot_3

 

 

Screenshot_4

 

Bước 2: Bạn thực hiện thêm key vào máy chủ Linux

Screenshot_1

 

trao quyền key

 

Screenshot_6

 

Bước 3: Remote vào máy chủ Linux không cần mật khẩu.

 

Screenshot_7

 

Chúc bạn thành công.

Perl: Bài 2 – Cú pháp Perl cơ bản

 Perl, Programing  Comments Off on Perl: Bài 2 – Cú pháp Perl cơ bản
Sep 142015
 

Perl vay mượn khá nhiều cú pháp và ý tưởng từ các ngôn ngữ khác: awk, sed, C, Bourne Shell, … Tuy nhiên có một vài điểm khác giữa các ngôn ngữ. Trong bài này sẽ cung cấp một cách tổng quan nhất về cú pháp của Perl.

Ví dụ: Để in ra chuỗi “Hello World” ra màn hình ta có các cách sau:

Chạy trực tiếp từ trình thông dịch:

$perl e 'print "Hello World\n"'

hoặc có thể tạo một file với nội dung như sau:

#!/usr/bin/perl
# This will print "Hello, World"
print"Hello, world\n"

Sau đó, bạn thực hiện chạy câu lệnh đó.

File chưa mã nguồn được đặt tên với duôi mở rộng là .pl, đuổi mở rộng này dùng đề phân biệt với các ngôn ngữ lập trình khác.

Dấu commnet

Dấu comment khá quen thuộc với các lập trình viên. Comment dùng để giải thích làm cho chương trình tường minh và dễ hiểu hơn. Ví dụ:

# This is comment in Perl – Python Viet Nam

Để comment một đoạn văn bản bạn cần đặt chúng trong cặp = và =cut. Ví dụ như chương trình sau:

Khi chạy chương trình, kết quả sẽ như sau:

Khoảng trắng trong Perl

Có một điều khá thú vị là Perl không quan tâm đến dấu khoảng trắng. Chương trình vẫn thực hiện tốt khi có dấu khoảng trắng:

#!/usr/bin/perl
print       "Hello, world\n";

Kết quả sẽ vẫn in ra dòng Hello, world

Nếu khoảng trắng ở giữ đoạn thông báo thì sẽ hiện nguyên như vậy, ví dụ:

#!/usr/bin/perl

# This would print with a line break in the middle - Python Viet Nam
print "Hello
          world\n";

Kết quả như sau:

Hello
    world

Dấu ngoặc đơn và dấu ngoặc kép:
 Bạn thử xem qua ví dụ sau:
#!/usr/bin/perl

print "Hello, world\n";
print 'Hello, world\n';

Kết quả như sau:

Hello, world
Hello, world\n

Bạn sẽ thấy sự khác nhau cơ bản giữa hai dấu này là: dấu ngoặc kép sẽ hiển thị \n là xuống dòng, còn dấu ngoặc đơn sẽ in ra nguyên gốc đoạn code. Tương tự với ví dụ sau:

#!/usr/bin/perl

$a = 10;
print "Value of a = $a\n";
print 'Value of a = $a\n';
This will produce the following result −

Khi chạy chương trình sẽ có kết quả như sau:

Value of a = 10
Value of a = $a\n

Khai báo đoạn văn bản là một biến. Bạn hay xem ví dụ sau:

#!/usr/bin/perl

$a = 10;
$var = <<"EOF";
This is the syntax for here document and it will continue
until it encounters a EOF in the first line.
This is case of double quote so variable value will be
interpolated. For example value of a = $a
EOF
print "$var\n";

$var = <<'EOF';
This is case of single quote so variable value will not be
interpolated. For example value of a = $a
EOF
print "$var\n";

Trong chương trình bạn sẽ thấy đoạn văn bản sẽ được gán như một biến. Và trong đoạn văn bản đó ta có thể gọi một biến nào đó, ví dụ trong đoạn mã này là a.

Kết quả sẽ in ra:

This is the syntax for here document and it will continue
until it encounters a EOF in the first line.
This is case of double quote so variable value will be
interpolated. For example value of a = 10

This is case of single quote so variable value will be
interpolated. For example value of a = $a

Kết luận:
Chúng ta vừa nghiên cứu các cú pháp cơ bản nhất của Perl.
Chúc các bạn thành công.