Hi các bạn, mình sử dụng Django Framework trong công việc rất nhiều và vấn đề deploy này mình đã mất tương đối thời gian và phải trả giá bằng không ít lần nghe khách hàng chửi. Bởi vậy mình tạo post này để cho các bạn nào cũng gặp phải tình trạng tương tự như mình có thể sử dụng trong công việc. Nào bắt đầu thôi. Let’s go


Vài điều cần biết trước khi bắt đầu

Đọc qua tiêu đề có thể thấy ở đây có 5 thứ khác nhau cần biết trước khi bắt đầu cài đặt hệ thống:

    • Django 2.x
    • Postgresql (recommend version 10 vì tính ổn định)
    • Gunicorn
    • Nginx
    • CentOS 7

Tuy bạn không cần phải biết chi tiết đến từng chân tơ kẽ tóc của 5 thứ trên nhưng ít nhất cũng cần biết qua công dụng của chúng và lý do tại sao mình lại sử dụng 5 thằng này để deploy server.

Thứ nhất Django 2.x, ở thời điểm viết bài là Django 2.2 (đã có Django 3.0 rồi cơ nhưng không recommend nhé, bản mới lỗi người ta còn chưa fix hết) là một trong số ít framework phổ biến nhất được sử dụng bởi cộng đồng Python. Document và khóa học đầy rẫy trên mạng.

Thứ hai, Postgresql, mình sử dụng Postgresql vì nó hỗ trợ đánh chỉ mục rất tốt (tốt hơn cả Mysql) và Django có thư viện hỗ trợ giao tiếp với Postgresql khá mạnh, vì sao mình recommend version 10, vì đây là phiên bản có tính ổn định cao, có nhiều document.

Thứ 3, Gunicorn là một trong những python web server theo chuẩn WSGI (chả cần hiểu là gì luôn), tóm lại khi bạn đang dev với Django thì chạy lệnh /manager.py runserver thì tiến trình này của bạn chỉ cho phép thực hiện 1 hành động 1 lúc, ví dụ nếu bạn deploy mà dùng cái /manager.py runserver này thì khi 1 user đang query DB mà lỗi thì tất cả các thằng khác sẽ dừng không truy cập được luôn. Vì thế mà nếu project của các bạn mà có khoảng 20 thằng vào 1 lúc là chết sặc tiết luôn.

Thứ 4 Nginx, với Nginx bạn có thể cài domain để truy cập vào project, thiết lập quyền truy cập vào folder cho user, vân vân và mây mây

Cuối cùng là CentOS 7, mình đánh giá server dùng CentOS 7 cũng tương tự server dùng Ubuntu 16.04 vì cộng đồng cả 2 bên đều mạnh, nhu cầu ở đây là cần 1 server để deploy mà mình quen thuộc hơn với CentOS 7 nên mình dùng thôi.


Chuẩn bị

Rõ là chuẩn bị server rồi, recommend ae dùng của Vultr nhé, trả tiền theo giờ, gói nhỏ nhất là 5$/tháng, quá trình deploy server mới khá nhanh và quan trọng là server khá ổn định. Ae truy cập theo đường link này để tạo account Vutlr và nhận khuyến mãi nhé: https://vultr.com

Chi tiết cách mua server và connect server mình sẽ nói ở bài khác nhé


Deploy

Cài đặt Python 3.6 trên CentOS 7

Add the repository to Yum install:

$ sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm

Update Yum to finish adding the repository (quá trình này có thể hơn 1p):

$ sudo yum update

Download & cài đặt Python 3.6:

$ sudo yum install -y python36u python36u-libs python36u-devel python36u-pip

Kiểm tra lại xem đã cài Python3.6 thành công chưa bằng câu lệnh:

$ python3.6 -V

Cài đặt Postgresql10

Cài đặt repository RPM:

$ sudo yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm

Cài đặt client packages & server packages:

$ sudo yum install -y postgresql10 postgresql10-server postgresql10-devel postgresql10-contrib

Khởi tạo database và start postgresql service:

$ sudo /usr/pgsql-10/bin/postgresql-10-setup initdb
$ sudo systemctl enable postgresql-10
$ sudo systemctl start postgresql-10

Đăng nhập vào Postgresql10, check version:

$ sudo -u postgres psql

=# select version();

Cài đặt các Packages khác trên CentOS 7

Enable the EPEL repository:

$ sudo yum install epel-release

Cài đặt gcc, nginx, git,… :

$ sudo yum install -y gcc nginx git

Kích hoạt connect đến Postgres bằng password authentication

Mở file pg_hba.conf bằng lệnh $ sudo nano /var/lib/pgsql/10/data/pg_hba.conf & chỉnh lại:

. . .

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
#host    all             all             127.0.0.1/32            ident
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
#host    all             all             ::1/128                 ident
host    all             all             ::1/128                 md5

Restart lại postgres:

$ sudo systemctl restart postgresql-10

Create the PostgreSQL Database and User

Đăng nhập vào Postgres command line bằng lệnh $ sudo -u postgres psql, tạo DB:

=# CREATE DATABASE your_project;

Tạo User:

=# CREATE USER your_user WITH PASSWORD 'password';

Gán quyền access của your_user tới your_project:

=# GRANT ALL PRIVILEGES ON DATABASE your_project TO your_user;
=# \q

Pull code django từ Git về, tạo virtualenv, runserver

Trong thực tế, bạn thường có nhu cầu deploy code đang trong quá trình dev hay code đã chạy được ở local lên server chứ ít có TH nào lại lên server tạo mới 1 project Django cả, vì vậy để thực tế hơn, mình có tạo sẵn 1 project django ở dưới local rồi push nó lên server ở đường link Github https://github.com/Longdh57/deploy_django, trong project trên mình đã cấu hình cài đặt thư viện python-dotenv hỗ trợ đọc dữ liệu kết nối DB từ .env file, cài đặt thư viện psycopg2-binary để kết nối Django với Postgresql.

Clone project về thư mục /var/www:

$ sudo mkdir /var/www && cd /var/www
$ git clone https://github.com/Longdh57/deploy_django.git

Cài đặt virtualenv, tạo .venv:

$ cd /var/www/deploy_django
$ sudo pip3 install virtualenv
$ virtualenv -p python3.6 .venv

Activate virtualenv, cài đặt thư viện sử dụng trong project:

$ source .venv/bin/activate
(.venv)$ pip install -r requirements.txt

Tạo file .env với thông tin DB đã tạo trước đó, ở đây mình đã để sẵn dữ liệu trong file env.sample, mình chỉ cần copy nó rồi đổi tên thành .env là được, còn trong TH các bạn đặt tên DB và DB username khác thì các bạn check lại và thay đổi trong file .env:

$ cp env.sample .env

Giờ sẽ thực hiện migrate, createsuperuser, runserver để test xem code chạy ổn định chưa. Trước hết cần mở filewall để chấp nhận connect lên port 8000 của server:

$ sudo firewall-cmd --permanent --add-port=8000/tcp
$ sudo firewall-cmd --reload

sau đó thực hiện migrate, create superuser, runserver:

$ python manage.py migrate

$ python manage.py createsuperuser   #tạo superuser để connect admin dashboard

$ python manage.py runserver

Mở http://your_server_ip:8000 trên trình duyệt để check, nếu có thể kết nối đến và đăng nhập được vào trang http://your_server_ip:8000/admin là ok.

Cài đặt Gunicorn, test gunicorn và tạo services

Sử dụng Ctrl + C để thoát khỏi runserver, tiếp theo chúng ta cần cài gunicorn và cho ứng dụng start với gunicorn. Cài gunicorn:

$ source .venv/bin/activate
(.venv)$ pip install gunicorn

Start ứng dụng với gunicorn để test, để ý rằng bước này gunicorn sử dụng file wsgi trong thư mục deploy_django, các bạn chú ý check đường dẫn đến file wsgi này:

$ gunicorn --bind 0.0.0.0:8000 deploy_django.wsgi:application

nếu sau bước này, vẫn vào được http://your_server_ip:8000 thì ok, tuy nhiên khi vào http://your_server_ip:8000/admin sẽ thấy lỗi js, css, điều này là bình thường nhé. Sử dụng Ctrl + C để thoát khỏi gunicorn.

Gunicorn đã chạy bình thường, giờ là lúc tạo services cho project django. Nhớ gõ deactivate để thoát khỏi virtualenv. Tạo file deploydjango.service và edit:

$ sudo nano /etc/systemd/system/deploydjango.service

Sau đó thêm vào file đoạn cấu hình sau, chi tiết từng cấu hình và tại sao lại cấu hình như vậy các bạn tham khảo thêm tại service CentOS, lưu ý quan trọng là nhớ trỏ thư mục chính xác, không là khỏi chạy:

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=root
Group=nginx
WorkingDirectory=/var/www/deploy_django
ExecStart=/var/www/deploy_django/.venv/bin/gunicorn --workers 2 --bind 0.0.0.0:8000 deploy_django.wsgi:application

[Install]
WantedBy=multi-user.target

Lưu file deploydjango.service lại, Enable và Start nó lên hưởng thành quả nào:

$ sudo systemctl enable deploydjango
$ sudo systemctl start deploydjango

ta lại vào http://your_server_ip:8000 để check, nếu load như bình thường và trang admin vẫn lỗi js, css thì ok

Cấu hình Nginx, đặt set Debug=False và cấu hình trỏ static file

Đây, bước cuối cùng mới đụng đến Nginx, phần này ta sẽ sử dụng nginx để trỏ static file, cấu hình domain. Bắt đầu nào.

Đầu tiên, mở file .env trong deploy_django bằng cách nano /var/www/deploy_django/.env và chuyển Debug=False

Restart deploydjango.service:

$ sudo systemctl restart deploydjango

Reload lại trang http://your_server_ip:8000 – nó tèo rồi, vì bị tắt debug mà

Không sao, lỗi not found là do chúng ta chưa đưa code gì lên trong trang chủ, tiếp tục thôi, thực hiện collectstatic trong django, để thực hiện được lệnh collectstatic này, nhớ là phải cấu hình biến STATIC_ROOT = os.path.join(BASE_DIR, “static/”) trong file settings.py của django:

$ cd /var/www/deploy_django/
$ source .venv/bin/activate
(.venv)$ python manage.py collectstatic
(.venv)$ deactivate

Check lại thì thấy có 1 folder static được tạo ở trong thư mục /var/www/deploy_django rồi là ok

Mở file deploydjango.com.conf bằng cách sudo nano /etc/nginx/conf.d/deploydjango.com.conf để cấu hình nginx:

server {
    listen       80;
    server_name  deploydjango.com;

    #charset koi8-r;
    access_log  /var/log/nginx/8000.access.log  main;
    error_log /var/log/nginx/8000.err.log warn;

    allow all;


    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /var/www/deploy_django;
    }

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:8000/;
    }

}

Enable và Restart lại nginx:

$ sudo nginx -t
$ sudo systemctl enable nginx
$ sudo systemctl start nginx
$ sudo systemctl restart nginx

Sửa file host để cấu hình truy cập bằng domain nào, ở đây domain mình đặt là deploydjango.com, vậy nên mở file host ra, cách mở file host thì tìm ở đây nhé :

Thử vào bằng http://deploydjango.com trên trình duyệt xem nào

Thành quả là đây, trang http://deploydjango.com vẫn lỗi nhưng http://deploydjango.com/admin thì vào được, không lỗi css và đăng nhập được bình thường. Vậy là xong rồi, giờ chỉ cần ngồi code tiếp trang home hoặc các chức năng khác đưa lên github rồi thực hiện git pull ở trên server là xong thôi. Chúc các bạn deploy thành công nha.