Bài viết
Docker: Chưa biết gì đến biết dùng
Phần 1- Lịch sử
1. Vì sao nên sử dụng
Vào một ngày đẹp trời "trăng thanh gió mát", bạn được phân bổ vào dự án mới, và tất nhiên là hào khí ngút trời, thế như chẻ tre nhảy vào happy coding:
Bạn hứng khởi vào đọc README.md
một hồi, thấy project này sao mà cài cắm nhiều thứ thế, nào là ruby, rồi rails, redis, mysql, nginx, ... mỗi thứ lại phải kèm theo version bao nhiêu, một tá thư viện, vân vân và mây mây với với hàng tá thứ khác. (Định kể thêm tý nữa cho nó nguy hiểm nhưng mà thôi các bạn cứ hiểu là nhiều nhé )
Lẩm bẩm một hồi, giờ ngồi search google, cài cắm, setup một tá thứ này thì hết bao lâu ta ?
Sếp ơi, em cần 1 buổi sáng để setup ạ.
Cài chưa xong đã conflic tùm lum, cái nọ xung đột cái kia chẳng hạn, lại còn ảnh hưởng tới những chương trình cũ đã cài đặt trong máy nữa chứ, thôi cài lại luôn cả hệ điều hành cho máy.
Sếp ơi, em cần thêm 1 buổi nữa để setup ạ -_- Hic
Thôi xong, mất thời gian, mệt mỏi với nhưng thao tác phụ mà chưa tập trung được vào việc chính.
Đó chính là lúc bạn nên nghĩ tới Docker, mọi thứ sẽ đơn giản hơn nhiều.
Chỉ vài dòng lệnh thôi, cạch cạch cạch, bạn sẽ có thể nhanh chóng tạo được
môi trường ảo hóa
chứa đầy đủ nhữngcài đặt
cần thiết cho project rồi.
Một ví dụ đơn giản vậy thôi, không
dừng lại ở đó, công dụng của Docker
còn khá nhiều, chúng ta cùng tìm hiểu dần nhé !
2. Quá trình hình thành
Cùng đọc lịch sử một chút đã:
2.1 Containerlization là gì ?
-
Ngày lâu lâu rồi, mô hình máy chủ thường là
máy chủ vật lý
+hệ điều hành(OS)
+application
.Vấn đề gặp phải ở đây là lãng phí tài nguyên, một máy chủ chỉ cài được một OS, cho dù có ổ cứng khủng, ram khủng thì cũng không tận dụng hết lợi thế.
-
Sau đó ra đời công nghệ ảo hóa
vitualization
.Bạn có thể đã nghe tới cái tên Vitualbox hay VMware rồi đúng không, đó đó chính nó đó. Với công nghệ này, trên một máy chủ vật lý mình có thể tạo được nhiều OS, tận dụng tài nguyên đã tốt hơn nhưng lại nảy sinh vấn đề tiếp.
Về tài nguyên
: Khi bạn chạy máy ảo, bạn phải cung cấp "cứng"dung lượng ổ cứng
cũng nhưram
cho máy ảo đó, bật máy ảo lên để đó không làm gì thì máy thật cũng phải phân phát tài nguyên.
Ví dụ khi tạo một máy ảo ram 2GB trên máy thật ram 4GB, lúc này máy thật sẽ mất 2GB ram cho máy ảo, kể cả khi máy ảo không dùng hết 2GB ram, đó là một sự lãng phí.
Về thời gian
: Việc khởi động, shutdown khá lâu, có thể lên tới hàng phút.
-
Ở bước tiến hóa tiếp theo, người ta sinh ra công nghệ
containerlization
Với công nghệ này, trên một máy chủ vật lý, ta sẽ sinh ra được nhiều máy con (giống với công nghệ ảo hóa
vitualization
), nhưng tốt hơn ở chỗ là các máy con này (Guess OS) đềudùng chung
phần nhân của máy mẹ (Host OS) và chia sẻ với nhau tài nguyên máy mẹ.Có thể nói là khi nào cần tài nguyên thì được cấp, cần bao nhiêu thì cấp bấy nhiêu, như vậy việc tận dụng tài nguyên đã tối ưu hơn. Điểm nổi bật nhất của
containerlization
là nó sử dụng cáccontainer
, và một kĩ sư của Google đã phát biểu rằng:Một công ty
hàng đầu
về công nghệ đã áp dụng nó, chứng tỏ lợi ích, độ tin cậy của công nghệ này rồi nhé ! Chúng ta cùngáp dụng
nó thôi.
2.2 Container là gì ?
Các phần mềm, chương trình sẽ được Container Engine
( là một công cụ ảo hóa tinh gọn được cài đặt trên host OS) đóng gói thành các container
.
Thế Container
là gì, nó là một giải pháp để chuyển giao
phần mềm một cách đáng tin cậy giữa các môi trường
máy tính khác nhau bằng cách:
- Tạo ra một môi trường chứa
mọi thứ
mà phần mềm cần để có thể chạy được. - Không bị các yếu tố liên quan đến môi trường
hệ thống
làm ảnh hưởng tới. - Cũng như không làm ảnh hưởng tới các phần còn lại của
hệ thống
.
Bạn có thể hiểu là ruby, rails, mysql ... kia được bỏ gọn vào một hoặc nhiều cái thùng (container), ứng dụng của bạn chạy trong những chiếc thùng đó, đã có sẵn mọi thứ cần thiết để hoạt động, không bị ảnh hưởng từ bên ngoài và cũng không gây ảnh hưởng ra ngoài.
Các tiến trình (process) trong một container
bị cô lập với các tiến trình của các container khác trong cùng hệ thống tuy nhiên tất cả các container
này đều chia sẻ kernel của host OS (dùng chung host OS).
Đây một nền tảng mở dành cho các lập trình viên, quản trị hệ thống dùng để xây dựng, chuyển giao và chạy các ứng dụng dễ dàng
hơn. Ví dụ, bạn có một app java, bạn sẽ không cần
cài đặt JDK vào máy thật để chạy app đó, chỉ cần kiếm
container đã được setting tương ứng cho app về, bật
nó lên, cho app chạy
bên trong môi trường container đó, vậy là ok. Khi không sài nữa thì tắt hoặc xóa bỏ
container đó đi, không ảnh hưởng gì tới máy thật của bạn.
Ưu điểm:
Linh động
: Triển khai ở bất kỳ nơi đâu do sự phụ thuộc của ứng dụng vào tầng OS cũng như cơ sở hạ tầng được loại bỏ.Nhanh
: Do chia sẻ host OS nên container có thể được tạo gần như một cách tức thì. Điều này khác với vagrant - tạo môi trường ảo ở level phần cứng, nên khi khởi động mất nhiều thời gian hơn.Nhẹ
: Container cũng sử dụng chung các images nên cũng không tốn nhiều disks.Đồng nhất
:Khi nhiều người cùng phát triển trong cùng một dự án sẽ không bị sự sai khác về mặt môi trường.Đóng gói
: Có thể ẩn môi trường bao gồm cả app vào trong một gói được gọi là container. Có thể test được các container. Việc bỏ hay tạo lại container rất dễ dàng.
Nhược điểm:
Xét về tính an toàn
:
- Do dùng chung OS nên nếu có lỗ hổng nào đấy ở kernel của host OS thì nó sẽ ảnh hưởng tới toàn bộ container có trong host OS đấy.
- Ngoài ra hãy thử tưởng tượng với host OS là Linux, nếu trong trường hợp ai đấy hoặc một ứng dụng nào đấy có trong container chiếm được quyền superuser, điều gì sẽ xảy ra? Về lý thuyết thì tầng OS sẽ bị crack và ảnh hưởng trực tiếp tới máy host bị hack cũng như các container khác trong máy đó (hacker sử dụng quyền chiếm được để lấy dữ liệu từ máy host cũng như từ các container khác trong cùng máy host bị hack chẳng hạn).
2.3 Docker ra đời
Công nghệ ảo hóa (vitualization
) thì ta có thể dùng công cụ Vitualbox hay VMware thế còn đối với containerlization
thì dùng gì đây ? Google họ dùng gì ?
Oh mình không biết được, mỗi một ông lớn có một cách để áp dụng công nghệ này và họ private
source code.
Gần đây, mà cũng lâu rồi Có một công ty tiến hành public
source code của họ về công nghệ này, họ tung ra sản phẩm mang tên là Docker và nhận được nhiều sự chú ý.
Sau đó công ty cũng đổi tên thành Docker luôn. Công ty này cung cấp công cụ Docker free nhưng họ kiếm được rất nhiều tiền từ những dịch vụ khác đi kèm với nó.
Với sự bùng nổ của việc sử dụng container
cùng với những lợi ích lớn mà nó mang lại, gã khổng lồ phần mềm Microsoft
không muốn bỏ qua cơ hội màu mỡ này với việc cho ra mắt tính năng mới có tên Windows Container
.
- Các bạn có thể tham khảo, áp dụng công cụ Windows Container của công ty Microsoft cho Windows tại đây.
- Còn phạm vi bài viết này xin giới hạn lại áp dụng sản phẩm Docker của công ty Docker cho Linux.
Đó, dân ta phải biết sử Tây là thế đó, chứ cứ lao vào học Docker luôn rồi cũng chẳng biết nó sinh đẻ thế nào, từ đâu mà ra, có anh em họ hàng gì không ?
3. Cài đặt ra sao ?
-
Docker
hỗ trợ nhiều nền tảng hệ điều hành khác nhau bao gồmLinux
,Windows
và cảMac
. Ngoài ra, Docker còn hỗ trợ nhiềudịch vụ
điện toán đám mây nổi tiếng như Microsoft Azure hay Amazon Web Services. -
Lưu ý là
ban đầu
nó được xây dựng trên nền tảng Linux. Vì Docker cần can thiệp vàophần lõi
, nhân Kernel trong khí đó Linux làmã nguồn mở
, gọi là cần gì có nấy. -
Đến khi thấy Docker
hay quá
, bác Windowsngỏ lời
, thế là công tyDocker
và công tyMicrosoft
hợp tác với nhau nhưng nghe chừngchưa khả quan
lắm bởi vì nhân Windows có nhưng thứkhông
public được ( bản quyền mà ).Cho tới hiện tại khi
cài
Docker trên Windows hay Mac thì Docker sẽ cài mộtmáy ảo
Linux trên máy thật và Docker hoạt độngdựa trên
máy ảo Linux đó. Còntương lai
về sau thì ai biết được. -
Docker có 2 phiên bản, CE( dành cho nhà phát triển, nhóm nhỏ,
coder
như chúng ta) và EE (dành chodoanh nghiệp
).Dưới đây mình sẽ giới thiệu cài đặt đối với bản
CE
trênUbuntu
thông quarepository
như sau:
I. Chuẩn bị một chút:
# Update the apt package index:
$ sudo apt-get update
# Install packages to allow apt to use a repository over HTTPS:
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
# Add Docker’s official GPG key:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Verify that you now have the key with the fingerprint 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88, by searching for the last 8 characters of the fingerprint.
$ sudo apt-key fingerprint 0EBFCD88
pub 4096R/0EBFCD88 2017-02-22
Key fingerprint = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid Docker Release (CE deb) <docker@docker.com>;
sub 4096R/F273FCD8 2017-02-22
# Use the following command to set up the stable repository
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
II. Cài đặt docker CE:
## Update the apt package index:
$ sudo apt-get update
## Install the latest version of Docker CE, or go to the next step to install a specific version. Any existing installation of Docker is replaced.
$ sudo apt-get install docker-ce
## Verify that Docker CE is installed correctly by running the hello-world image.
$ sudo docker run hello-world
- Nếu câu lệnh cuối cùng của bạn ra kết quả như sau thì bạn đã cài đặt Docker thành công:
Ngoài ra bạn có thể tham khảo cài đặt tại trang chủ.
4. Hoạt động như thế nào ?
Docker image
là nền tảng củacontainer
, có thể hiểu Docker image nhưkhung xương
giúp định hình cho container, nó sẽ tạo ra container khi thực hiệncâu lệnh chạy
image đó. Nếu nói với phong cáchlập trình hướng đối tượng
, Docker image làclass
, còn container làthực thể
(instance, thể hiện) của class đó.
Docker có hai khái niệm
chính cần hiểu, đó là image
và container
:
-
Container
: Tương tự như mộtmáy ảo
, xuất hiện khi mìnhkhởi chạy
image.Tốc độ
khởi chạy containernhanh hơn
tốc độ khởi chạymáy ảo
rất nhiều và bạn có thểthoải mái
chạy 4,5 container mà không sợ treo máy.Các
files
vàsettings
được sử dụng trong container được lưu, sử dụng lại, gọi chung làimages
của docker. -
Image
: Tương tự như file.gho
để ghost win mà mấy ông cài win dạo hay dùng.Image
này không phải là một file vật lý mà nó chỉ được chứa trong Docker.Một image bao gồm
hệ điều hành
(Windows, CentOS, Ubuntu, …) và cácmôi trường
lập trình được cài sẵn (httpd, mysqld, nginx, python, git, …).Docker hub là nơi lưu giữ và chia sẻ các file images này (hiện có khoảng 300.000 images)
Bạn có thể tìm tải các image mọi người chia sẻ sẵn trên mạng hoặc có thể tự tạo cho mình một cái image như ý.
5. Các câu lệnh trong Docker
- Chuẩn chỉnh & đầy đủ nhất thì bạn cứ tham khảo trên trang chủ của docker docs. Còn ở bài viết này sẽ trích dẫn những câu lệnh cơ bản nhất giúp các bạn nhanh chóng nắm bắt:
- Pull một image từ Docker Hub
sudo docker pull image_name
- Tạo mới container bằng cách chạy image, kèm theo các tùy chọn:
sudo docker run -v <forder_in_computer>:<forder_in_container> -p <port_in_computer>:<port_in_container> -it <image_name> /bin/bash
Ví dụ:
sudo docker pull ubuntu:16.04
sudo docker run -it ubuntu:16.04 /bin/bash
- Bây giờ bạn đã dựng thành công một môi trường ubuntu ảo rồi đó.
Câu lệnh
uname -a
sẽ hiển thị thông tin của Kernel ubuntu, cùng so sánh nhé:
Kết quả của dòng uname-a
thứ nhất là thông tin Kernel của máy ảo (tức là của container)
Linux 5ed7d9f282fe 4.15.0-36-generic #39~16.04.1-Ubuntu SMP Tue Sep 25 08:59:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Kết quả của dòng uname-a
thứ hai là thông tin Kernel của máy "thật" (Linux) bạn đang dùng.
Linux hoanki-Nitro-AN515-51 4.15.0-36-generic #39~16.04.1-Ubuntu SMP Tue Sep 25 08:59:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
-> Thông tin nhân Kernel như nhau nhé ! Do container sử dụng chung tài nguyên với host OS mà.
- Một vài câu lệnh khác:
docker images:
Liệt kê các images hiện có
docker rmi {image_id/name}:
Xóa một image
docker ps:
Liệt kê các container đang chạy
docker ps -a:
Liệt kê các container đã tắt
docker rm -f {container_id/name}:
Xóa một container
docker start {new_container_name}:
Khởi động một container
docker exec -it {new_container_name} /bin/bash:
Truy cập vào container đang chạy
Phần 2 - Dockerfile
2.1 Dockerfile là gì ?
Thì đơn giản, Dockerfile là một file
dạng text, không có đuôi, giúp thiết lập cấu trúc
cho docker image
nhờ chứa một tập hợp các câu lệnh
.
Từ những câu lệnh đó, Docker có thể thực hiện đóng gói
một docker images theo yêu cầu tùy biến của riêng bạn.
=> Như vậy Dockerfile sẽ quy định
Docker image được khởi tạo từ đâu
, gồm những gì
trong đó.
2.2 Cách viết Dockerfile
Demo như sau:
-
Đầu tiên chúng ta sẽ viết
Dockerfile
để tạo nênimage
rồi tạo nêncontainer
, sau khi tạo đượccontainer
rồi thì đồng nghĩa là đã tạo ra đượcmáy ảo
để bạn có thể khởi chạyứng dụng
của bạn trên máy ảo đó. -
Thư mục
webroot
chứa mã nguồn chương trình, có thể là mộtc++ app
,java app
hoặcweb app
được viết bằng php hoặc ruby,.... (Ở đây, để cho đơn giản, chúng ta chỉ đặt filehello.html
, chạy trên trình duyệt sẽ hiển thị dòng Hello Word)Sau này, bạn dùng
editor
để lập trình trên máy thật, chỉnh sửamã nguồn
trong thư mục này, mọi sự thay đổi được cập nhậtngay lập tức
trên máy ảo. -
File
start.sh
chứa những câu lệnh được chạy khi bật container (có thể dùng để start mysql, nginx, redis ...)
Nào, bắt đầu viết Dockerfile
nhé:
2.2.1 Thiết lập image gốc
Đầu tiên, ta cần khai báo thằng cha
của image này là thằng nào
, tức là nó khởi nguồn
từ đâu, sử dụng:
- FROM
Image gốc
có thể là centos:7, ubuntu:16.04, vân vân và mây mây.
Vi dụ:
FROM ubuntu:16.04
Có thể bạn sắp biết, Docker hub - nơi lưu trữ và chia sẻ các image sẽ chứa những image gốc
mà từ đó, bạn có thể phát triển
, cài cắm
, thay tháo
, chỉnh sửa
, thêm bớt
để tạo ra những images tùy biến
cho riêng bạn.
Khi Docker đọc tới câu lệnh này, nó sẽ tự động tìm xem image ubuntu:16.04 này đã tồn tại trong máy chưa, nếu chưa thì Docker sẽ tự động pull image này về. Trong đó ubuntu là tên của image, 16:04 là tag, bạn cũng có thể hiểu nó nôm na như là branch trong git.
- MAINTAINER : Một optional dùng để đặt tên cho tác giả của Dockerfile mà bạn đang viết. Ví dụ:
MAINTAINER HoanKi<hoanki2212@gmail.com>;
2.2.2 Cài đặt ứng dụng
Bây giờ, chúng ta sẽ cài thêm
các ứng dụng, thiết lập
môi trường cần thiết trên ubuntu:16.04
này
Bạn có thể cài nginx, php, python, ruby, java ... phụ thuộc vào nhu cầu
của bạn, sử dụng:
-
RUN : Để thực thi một câu lệnh nào đó trong
quá trình build images
. -
CMD : Để thực thi một câu lệnh trong quá trình
bật container
.Mỗi Dockerfile
chỉ có
một câu lệnh CMD, nếu như cónhiều hơn
một câu lệnh CMD thì chỉ có câu lệnh CMDcuối cùng
được sử dụng.Một
câu hỏi
đặt ra là nếu tôi muốn khởi độngnhiều ứng dụng
khi start container thì sao, lúc đó hay nghĩ tớiENTRYPOINT
-
ENTRYPOINT: Để thực thi
một số câu lệnh
trong quá trìnhstart container
, những câu lệnh này sẽ được viết trongfile .sh
.
Ví dụ:
# Update ubuntu
RUN apt-get update
# Install nginx
RUN apt-get install -y nginx
# Install mysql server
RUN echo "mysql-server mysql-server/root_password password root" | debconf-set-selections \
&& echo "mysql-server mysql-server/root_password_again password root" | debconf-set-selections \
&& apt-get install -y mysql-server
Trong khi cài nginx, sẽ có câu hỏi xuất hiện và bạn cần trả lời yes/no, khi đó tùy chọn -y
trong RUN apt-get install -y nginx
sẽ thể hiện cho sự lựa chọn yes
của bạn.
2.2.3 Cấu hình
-
EXPOSE: Container sẽ lắng nghe trên các cổng mạng được chỉ định khi chạy
-
ADD : Copy file, thư mục, remote file thêm chúng vào filesystem của image.
-
COPY : Copy file, thư mục từ host machine vào image. Có thể sử dụng url cho tập tin cần copy.
-
WORKDIR : Định nghĩa directory cho CMD
-
VOLUME : Mount thư mục từ máy host vào container.
Tạo file .sh
Như ở phần entrypoint đã nói, cho dù chỉ cần một câu lệnh mình vẫn dùng ENTRYPOINT, để sau này dễ dàng tùy biến, phát triển.
Tạo file start.sh như sau
#!/bin/bash
service nginx start
exec $@
Ta có ví dụ ở phần này như sau:
ADD start.sh /venv
WORKDIR /venv
RUN chmod a+x /venv/*
ENTRYPOINT ["/venv/start.sh"]
EXPOSE 80
Tổng hợp lại, ta có một ví dụ cho Dockerfile như sau :
FROM ubuntu:16.04
MAINTAINER HoanKi<hoanki2212@gmail.com>;
RUN DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y nginx
RUN echo "mysql-server mysql-server/root_password password root" | debconf-set-selections \
&& echo "mysql-server mysql-server/root_password_again password root" | debconf-set-selections \
&& apt-get install -y mysql-server
WORKDIR /venv
COPY start.sh /venv
RUN chmod a+x /venv/*
ENTRYPOINT ["/venv/start.sh"]
EXPOSE 80
- Tạo file
hello.html
trong thư mục webroot:
<h1>Hello word</h1>
-
Mình có push code mẫu lên GitHub: HoanKy/docker_tutorial
-
Còn đây là full document về Dockerfile
2.3 Cách sử dụng Dockerfile
2.3.1 Build docker image từ Dockerfile
Ta sử dụng câu lệnh sau:
sudo docker build -t <image_name> .
Ví dụ:
sudo docker build -t ubuntu-nginx .
Bạn có thể dùng lệnh
docker images
để xem thành quả nhé !
2.3.2 Tạo container từ image.
- Gõ lệnh theo syntax:
sudo docker run -v <forder_in_computer>:<forder_in_container> -p <port_in_computer>:<port_in_container> -it <image_name> /bin/bash
Trong đó:
-
-v : Thể hiện việc mount volume, dữ liệu từ thư mục từ máy thật có thể được truy cập từ thư mục của máy ảo.
-
-p: Cổng mạng từ máy thật để dẫn tới cổng mạng của máy ảo đang chạy.
-
-t: Chạy container và mở terminal bằng /bin/bash
-
Ví dụ vào localhost mặc định của nginx:
sudo docker run -p 9000:80 -it ubuntu-nginx /bin/bash
Kiểm tra log trên Terminal:
Trên trình duyệt:
- Ví dụ vào thư mục dự án ở máy thật:
sudo docker run -v /media/hoanki/PROJECT4/GitRepo/docker_tutorial/webroot:/var/www/html -p 9000:80 -it ubuntu-nginx /bin/bash
Thay thế /media/hoanki/PROJECT4/GitRepo/docker_tutorial/webroot
cho đúng với trên máy bạn nhé !
Kết quả:
3. Docker Hub
Docker-hub: Nơi lưu trữ và chia sẻ các image của Docker, nhưng không chỉ có vậy.
Nãy giờ bạn và tôi đang build image hoàn toàn dưới local, nhưng Docker Hub còn hỗ trợ chúng ta làm việc này trên server nữa.
- Mình tạo mới repo docker-basic trên Github, như này:
- Sau đó mình tạo mới một repo trên Dockerhub.
Vào Create chọn Create Automated Build, chọn Github rồi trỏ tới docker-basic bạn vừa tạo ở GitHub.
Và ta có docker_basic, trông như sau:
-
Dockerhub sẽ hỗ trợ bạn build docker image online, sau đó bạn có thể pull nó về để sử dụng.
-
Vào tab Build Settings,
-
Từ giờ trở đi, mỗi khi bạn push code lên branch nào trên github branch đó bạn đã setting trên DockerHub thì images sẽ tự động được build.
Việc build này sẽ tự động thực hiên trên server Docker Hub nhé, ví dụ mình push code lên branch init_dockerfile
thì Dockerhub tự động build image, kết quả có ở trong tab Build Detail.
Mình tạo pull request, sau khi mình merge nó thì DockerHub cũng sẽ build image tiếp trên branch master.
- Thử đi nhé, đôi khi buid ở local thì pass mà build trên server thì lỗi, cảm giác fix mãi nó mới hiện dòng chữ "Success" nó mới awesome làm sao.
Phần 3: Docker-compose cho dự án Rails
2. Bài toán
- Câu chuyện đặt ra là chúng ta muốn bắt đầu một
dự án mới
vớiDocker
. - Hoặc chúng ta muốn ứng dụng Docker cho một dự án
đang phát triển
rồi.
==> Vậy chúng ta làm như thế nào ?
- Sau khi tìm hiểu hết phần 2, chúng ta hoàn toàn có thể sử dụng
Dockerfile
, cài đặt tất cả những môi trường cần thiết (như mysql, redis, ruby hay php ) rồi chạy project trênduy nhất một container
.
Tuy nhiên:
-
Nếu như bạn muốn dùng kết hợp nhiều image có sẵn trên DockerHub thì sao ?
-
Nếu một cơ sở dữ liệu dùng chung cho nhiều app thì sẽ xử lý thế nào ?
-
Hơn nữa, với tư duy của OOP, 1 class thì không nên cõng nhiều nhiệm vụ.
==> Từ đó sinh ra docker-compose
để kết kết nối các container
riêng biệt với nhau.
- Ý tưởng cơ bản là ta sẽ xây dựng nhiều container, khi nào cần tương tác với database thì gọi tới
container mysql
chẳng hạn, tương tác với redis thì gọi tớicontainer redis
, cần cái gì thì gọi tới container làm nhiệm vụ đó.
- Okie, let go
-
À quên, bài viết sử dụng Rails framework (một framework của Ruby dùng để lập trình web) để ứng dụng Docker, còn với các framework của
PHP (Laravel, Yii, ...)
hayPython (Django, ...)
thì mình sẽ tìm cách làm tương tự nha. -
Quan trọng là mình hiểu cách sử dụng
docker-compose
, các bạn cứ đọc hiểu rồi sẽ làm được cho framwork khác, nếu có điều kiện, mình sẽ tìm hiểu và viết thêm bài hướng dẫn sử dụng Docker trên Laravel.
3. Cài đặt Docker-compose
Tham khảo trên trang chủ nào, trên Linux
thì sẽ như sau:
- Step 1: Run this command to download the latest version of Docker Compose.
sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-(uname−s)−(uname -s)-(uname -m)" -o /usr/local/bin/docker-compose
- Step 2: Apply executable permissions to the binary.
sudo chmod +x /usr/local/bin/docker-compose
- Step 3: Test the installation.
docker-compose --version
Đây là phiên bản đang cài đặt trên máy tính của mình:
docker-compose version 1.23.1, build b02f1306
Xong dồi, có vẻ nhanh gọn nhẹ
4. Xác định các container cần thiết
Ở mức cơ bản nhất, chúng ta sẽ xây dựng 2 container:
-
Thứ nhất là
container
dùng đểkết nối tới cơ sở dữ liệu
.Hiện nay, phần lớn các dự án có lẽ hay sử dụng
mysql
, để gần gũi và quen thuộc với mọi người nên mình sẽ dùng cơ sở dữ liệu mysql luôn. Còn nếu hịn hơn thì bạn có thể tìm hiểu và sử dụngpostgresql
nhé, teachnical leader của dự án mình cũng khuyến khích sài thanh niên này, hiện tại thìmysql:5.7
vẫn còn nhiều điều chưa được hịn hò cho lắm như lưu trữ với kiểu dữ liệu array hay gán giá trị mặc định cho trường với kiểu dữ liệutext
.Quay trở lại vấn đề chính nào, quan sát:
https://hub.docker.com/_/mysql/
Chúng ta sẽ thấy tên organization
/_/
và bên dưới tên image có dòng chữDocker Official Images
Đây chính là những
image chính thức
được Docker cung cấp, chúng ta sẽ yên tâm hơn khi sử dụng, và khuyến cáo luôn là nên sử dụng (Hàng chính hãng, nhập khẩu nguyên đai nguyên kiện )Trên DockerHub còn rất nhiều image khác dành cho mysql, ví dụ bitnami/mysql
Đây là những image do các cá nhân, tổ chức khác xây dựng, có thể sẽ có những cải tiến so với bản official nhưng độ an toàn và chính xác thì khó mà bằng bản chuẩn được.
-
Thứ hai là
container
dùng choweb application
.Có thể có bạn chưa rõ, ta có PHP là tên của một ngôn ngữ lập trình, Laravel là tên của một PHP framework, dùng để lập trình web.
Thì tương tự như vậy, Ruby cũng là một ngôn ngữ lập trình, Rails cũng là một Ruby framework dùng để lập trình web.
Lát nữa chúng ta dùng image ruby, cài cắm thêm một chút để tạo
container
choweb application
.
5. Cấu trúc thư mục của dự án
-
Khá là hay ho khi trên trang chủ
Docker
cũng đã có bài hướng dẫn cách bắt đầu docker cho rails project. -
Nhưng trong thực tế làm dự án, mình thấy vẫn còn một số điểm chưa được tối ưu lắm, nên sau đây chúng ta cùng tìm hiểu cách tối ưu hơn nữa nhé ! Bạn nào thấy có thêm chỗ nào có thể tối ưu hơn nữa thì comment bên dưới nha.
-
Các file thiết lập chính của docker:
Dockerfile
: TừDockerfile
---build--->docker image
----run---->container
.
docker / entrypoint.sh
: Liệt kê những câu lệnh cần chạy sau khi bật container.
docker-compose.yml
: Dùng đểkhai báo
vàđiều phối
hoạt động củatất cả container
trong project.
6. Viết docker-compose
- Chúng ta sẽ viết
docker-compose.yml
trước để có cái nhìn tổng quan về cácservices
trong project ...
- Phiên bản của docker-compose
version: '3.5'
- Liệt kê các services
services:
mysql:
...
...
...
app:
...
...
...
- Cài đặt cho từng services
mysql:
image: mysql:5.7
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- docker/database:/var/lib/mysql
-
image: Chỉ định
image
để khởi độngcontainer
, ở đây ta dùng image có sẵn. -
container_name: Chỉ định tên container tùy chỉnh, thay vì tên mặc định.
-
restart: Giá trị mặc định là
no
, còn nếu bạn đặt làalways
thì container sẽ khởi động lại nếu mã thoát cho biết lỗi không thành công. -
environment: Thêm các biến môi trường
-
volumes: Chia sẻ dữ liệu giữa container và container hoặc giữa container và host (máy thật).
Ví dụ:
- Khi
container mysql
tạo và lưu dữ liệu, data sẽ lưu ở trong thư mụcvar/lib/mysql
của máy ảo. Như vậy nếu máy ảo này bị xóa đi thì chúng ta sẽ bịmất data
, ôi buồn quá ---__----
-
Giải pháp bây giờ là chúng ta sẽ sao lưu dữ liệu đó ra ngoài máy thật, kể cả khi container bị xóa, dữ liệu sẽ vẫn được lưu trữ ở máy thật. Và ở thời điểm bật lại container, dữ liệu lại được mount từ host vào container.
-
Thư mục lưu trữ data ở ngoài máy host sẽ không được
commit
vào git, ta đưa nó vàogitignore
.# Ignore data backup /docker/database
-
Ở một số hướng dẫn có lưu dữ liệu backup vào trong thư mục
/tmp
, đã đượcgitignore
sẵn củaRails
hoặc lưu ở thư mục ngoài dự án thì không cầngitignore
nó nữa.
- Khi
app:
container_name: app
build: .
volumes:
- .:/my_app
ports:
- "3000:3000"
environment:
DATABASE_HOST: mysql
DATABASE_USER_NAME: root
DATABASE_PASSWORD: root
-
build: Sử dụng khi chúng ta tự xây dựng docker image.
- Nếu
Dockerfile
nằm cùng thư mục vớidocker-compose.yml
thì chỉ cần
build: .
- Nếu bạn muốn đặt
Dockerfile
trong thư mụcdocker
để cùng vớientrypoint.sh
cho gọn thì sửa thành
build: context: ./ dockerfile: docker/Dockerfile
- Nếu
-
ports: Cấu hình cổng kết nối
Có thể chỉ định cả 2 cổng (HOST:CONTAINER) tức là (cổng ở máy thật: cổng ở máy ảo) hoặc chỉ định mình cổng cho máy ảo thôi.
Ví dụ:
"2222:3333"
Khi bạn truy cập vào cổng2222
ở máy thật thì sẽ được trỏ tới truy cập ở cổng3333
của máy ảo. -
environment: Bổ sung các biến môi trường.
Lưu ý rằng
DATABASE_HOST
chính là tên của service mysql.Mình đã push code lên Github.
7. Viết Dockerfile
- Bây giờ ta sẽ viết
Dockerfile
cho containerapp
trên kia nhé, chỗ màbuild .
ấy.
-> Image cơ sở
FROM ruby:2.5.1
-> Đánh dấu lãnh thổ chút
LABEL author.name="HoanKy" \
author.email=""
-> Cặt đặt các phần mềm cần thiết cho máy ảo
RUN apt-get update && \
apt-get install -y nodejs nano vim
-> Set timezone cho máy ảo (Optional)
ENV TZ=Asia/Ho_Chi_Minh
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
-> Cấu hình thư mục mặc định (Optional)
ENV APP_PATH /my_app
WORKDIR $APP_PATH
-> Cài đặt thư viện cần thiết cho dự án
Dưới đây là cách cài đặt trên Rails framwork.
COPY Gemfile Gemfile.lock $APP_PATH/
RUN bundle install --without production --retry 2 \
--jobs `expr $(cat /proc/cpuinfo | grep -c "cpu cores") - 1`
-> Copy tất cả dữ liệu tự máy host vào trong container
COPY . $APP_PATH
-> Cấu hình file entrypoint.sh
COPY docker/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
-> Thiết lập câu lệnh mặc định sẽ chạy khi khởi động container
CMD ["rails", "server", "-b", "0.0.0.0"]
Mình có push code mẫu lên Github
8. Viết entrypoint.sh
-> Khởi chạy sh
với bash chứ ko phải là sh hay zsh
#!/bin/bash
set -e
-> Xóa tiến trình cũ
rm -f /my_app/tmp/pids/server.pid
Mỗi khi chạy máy chủ rails
sẽ có một mã id
được lưu vào file để đánh dấu rằng đã tồn tại tiến trình đang chạy.
Khi bạn tắt máy chủ thì rails sẽ xóa nội dung file này trước, tuy nhiên trong trường hợp bị kill
các tiến trình thì rails sẽ chưa kịp xóa file này và dừng lại.
Như vậy, ta xóa thủ công nó đi để đảm bảo không gặp lỗi:
exec "$@"
Mình có push code mẫu lên Github
9. Sử dụng docker-compose
9.1 Trường hợp tạo dự án mới
--> Như giải pháp ở trên bạn gõ:
docker-compose run app rails new . --force --no-deps --database=mysql
-
Cụ thể thì đầu tiên, compose sẽ build các image cần thiết cho container app.
-
Sau đó, bật container đó lên và chạy câu lệnh
rails new ...
để setup project mới. -
Việc này sẽ mấy chút thời gian, trong quá trình chờ đợi thì bạn nên theo dõi log ở Terminal để xem các bước thực hiện như thế nào nhé !
-
Có thể bạn sẽ biết, docker chạy với quyền
root
nên những file, folder nó tạo ra cũng ở quyền root.
- Vậy nên khi bạn dùng editor để lập trình sẽ đòi quyền sudo khi save, bala bala, thế thì đổi luôn quyền đi cho nhanh gọn
sudo chown -R $USER:$USER .
-
Cấu hình để kết nối tới cở sở dữ liệu
File
config/database.yml
đang để mặc định, bây giờ sửa lại setting cho nó nhé !Sửa từ
default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: host: localhost
thành
default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch("DATABASE_USER_NAME") || "root" %> password: <%= ENV.fetch("DATABASE_PASSWORD") || "root" %> host: <%= ENV.fetch("DATABASE_HOST") || "mysql" %>
-
Xong xuôi thì bạn chuyển qua mục 10.2 được rồi.
10.2 Trường hợp cho dự án đang phát triển
-
Chỉnh sửa các config cho phù hợp (config/database.yml ...)
-
Build các image cần thiết:
docker-compose build
Có thể sẽ gặp lỗi này
IOError: Can not read file in context: /home/nguyenvanhoan/GitRepo/docker_tutorial/docker/database/ca-key.pem
Do một số file trong thư mục back_up database cần quyền root
để truy cập, hãy đổi thành
sudo docker-compose build
- Khởi chạy container:
sudo docker-compose up
Creating network "docker_tutorial_default" with the default driver
Creating app ... done
Creating mysql ... done
Attaching to mysql, app
Òa, log bắn ra ầm ầm, kệ nó đi, bạn vào địa chỉ http://localhost:3000
và tận hưởng thành quả nào:
Unknown database 'sample_app_development'
Vâng, bug đỏ lòm đập vào mặt, lỗi này là do chúng ta chưa tạo cơ sở dữ liệu.
-
Tạo cơ sở dữ liệu
Với mỗi framework sẽ có cách khác nhau để tạo cơ sở dữ liệu.
Còn đối với rails, nếu ở máy thật, bạn cần gõ 2 câu lệnh sau để tạo database:
# Tạo các bảng và quan hệ giữa chúng rake db:migrate:reset # Tạo dữ liệu mẫu rake db:seed
Còn bây giờ, chúng ta hãy truy cập vào máy ảo để chạy câu lệnh này, bằng cách
sudo docker-compose run + tên container + Câu lệnh muốn chạy
Và ở đây, ta cần:
sudo docker-compose run app rake db:migrate:reset sudo docker-compose run app rake db:seed
Truy cập vào
http://localhost:3000
nàoNote:
- Nếu vừa rồi bạn ấn
Ctrl + C
để dừngdocker-compose up
thì khi chạy câu lệnh tạo cơ sở dữ liệu sẽ gặp lỗi
Mysql2::Error::ConnectionError: Unknown MySQL server host 'mysql' (-2)
Vì sao ?
Nhìn vào log trên ta sẽ thấy
^CGracefully stopping... (press Ctrl+C again to force) Stopping mysql ... done Stopping app ... done
Tức là
service mysql
đã bị dừng lại, vậy nên app của chúng ta không thể kết nối tớimysql service
.Để giải quyết điều này thì có nhiều cách:
-
Đơn giản nhất là bạn mở thêm tab Terminal.
-
Dùng option
-d
docker-compose up -d
-
Thay đổi cách khởi động các
container
Bài cũng đã dài, mình sẽ viết ở phần 4.
Cơ bản là cũng đủ kiến thức cơ bản về docker-compose rồi, nếu bạn gặp lỗi hoặc bị vướng ở đoạn nào chưa hiểu thì hãy để lại bình luận bên dưới, mình sẽ support nếu có thể nhé !
- Nếu vừa rồi bạn ấn
Tài liệu tham khảo:
(Hoàn Kỳ/viblo)
Có thể bạn quan tâm:
Microservices địa ngục kiến trúc một khối
20 Open Source Ecommerce Platforms
Open source: vì sao chúng ta phải quan tâm tới cách quản lí project ...
Bài toán các vị tướng Byzantine và ứng dụng trong Blockchain ...
- 5 ứng dụng gửi thiệp chúc mừng trong iPhone
- Tài khoản mặc định của các loại Modem internet
- Vì sao nên chọn MySQL 5.7?
- tắt VinaphoneWifi trong modem wifi của bạn
- Kinh tế chia sẻ và tiềm năng cho Việt Nam
- Cách xem số điện thoại
- Tổng quan về React Native
- Notification là gì?
- Vai trò và tố chất cần có của một Test Manager
- Cách tạo email công ty miễn phí theo tên miền với Zoho mail
- Hướng dẫn sử dụng phần mềm subversion (svn) toàn tập
- Lập trình: cũng chỉ là viết?
DVMS chuyên:
- Tư vấn, xây dựng, chuyển giao công nghệ Blockchain, mạng xã hội,...
- Tư vấn ứng dụng cho smartphone và máy tính bảng, tư vấn ứng dụng vận tải thông minh, thực tế ảo, game mobile,...
- Tư vấn các hệ thống theo mô hình kinh tế chia sẻ như Uber, Grab, ứng dụng giúp việc,...
- Xây dựng các giải pháp quản lý vận tải, quản lý xe công vụ, quản lý xe doanh nghiệp, phần mềm và ứng dụng logistics, kho vận, vé xe điện tử,...
- Tư vấn và xây dựng mạng xã hội, tư vấn giải pháp CNTT cho doanh nghiệp, startup,...
Vì sao chọn DVMS?
- DVMS nắm vững nhiều công nghệ phần mềm, mạng và viễn thông. Như Payment gateway, SMS gateway, GIS, VOIP, iOS, Android, Blackberry, Windows Phone, cloud computing,…
- DVMS có kinh nghiệm triển khai các hệ thống trên các nền tảng điện toán đám mây nổi tiếng như Google, Amazon, Microsoft,…
- DVMS có kinh nghiệm thực tế tư vấn, xây dựng, triển khai, chuyển giao, gia công các giải pháp phần mềm cho khách hàng Việt Nam, USA, Singapore, Germany, France, các tập đoàn của nước ngoài tại Việt Nam,…
Quý khách xem Hồ sơ năng lực của DVMS tại đây >>
Quý khách gửi yêu cầu tư vấn và báo giá tại đây >>