Chào mọi người!

Hôm nay sẽ tiếp tục loạt bài "Mình biết thì mình chia sẻ" của mình mong tiếp tục nhận được sự ủng hộ từ anh em (hehe)

Mục đích chính của bài viết này là chúng ta sẽ có được cái nhìn tổng quan về Docker và làm sao chạy một ứng dụng web với PHP Mysql mà không cần cài Apache, Mysql trực tiếp vào máy thông qua việc chúng ta sẽ sử dụng những gì mình tìm hiểu được về Docker để làm việc đó.

Cái tên Docker có lẽ các bạn cũng như mình đã từng nghe tuy nhiên chưa làm việc với nó và cũng chưa tìm hiểu nhiều về nó nên mình nghĩ bài viết này của mình sẽ khá hữu ích đối với new new newbie Docker như mình

Tuần trước mình có có một project về web với ngôn ngữ PHP và sử dụng Mysql server. Do đó trên máy mình có cài Apache2, PHP7 và Mysql 5.7 và mình đang dùng trên hệ điều hàng Linux với phiên bản Ubuntu 16.04 LTS. Mình có một thằng bạn nó khuyên mình là dùng Docker đi không cần cài từng cái như vậy. Mình chỉ cần tìm các image cài đặt và làm theo các hướng dẫn của nó là có thể start server apache và mysql khi nào mình muốn và chạy ứng dụng web trên máy của mình.

Nghe lời nó mình đã thử tìm hiểu về Docker xem có gì hay và mình đã bắt đầu thực sự thích tên này

Mình mất khá ít thời gian để setup một môi trường đầy đủ cho việc chạy một ứng dụng web mà mình đang phát triển. Quả thật Docker theo các nhân mình đánh giá là khá tốt về khả năng vượt qua các vấn đề liên quan đến cài đặt ứng dụng trên Ubuntu, các việc cần thiết mà phải như đối với việc mình cài đặt từng phần như đã nói ở trên. Start khi muốn sử dụng và stop khi không cần đến, dễ dàng bảo trì thay đổi phiên bản, gỡ bỏ cài đặt dễ dàng

Thôi không lan man nữa chúng ta hãy cùng đi vào nội dung chính của bài chia sẻ này

Ok. Let's make it awesome =))

DOCKER là gì?

Là một công cụ tạo môi trường được "đóng gói" (còn gọi là Container) trên máy tính mà không làm tác động tới môi trường hiện tại của máy. Một số developer thường tạo sẵn các môi trường này, và upload lên mạng để mọi người lấy về dùng, và mấy cái này gọi là các Images

  • Nó giống như virtual machine, chỉ là tiện dụng hơn, dễ dàng sử dụng hơn và độc lập với hệ điều hành máy chủ chúng ta đang sử dụng

  • Cùng nhìn qua kiến trúc để thấy sự khác biệt:

vm.jpg

docker.jpeg Docker Container

  • Khi sử dụng môi trường Vitualization thì chúng ta cần cài các hệ điều hành cùng các tool cần thiết để chạy một ứng dụng có sẵn, nhưng với docker việc đó trở nên đơn giản với việc mình tìm và sử dụng lại các images (tại đây các cài đặt cần thiết để cho việc khởi chạy là có sẵn). Sau đó đóng gói vào trong các Container và chạy thôi. Cài đặt và khởi chạy, các khái niệm mình sẽ trình bày bên dưới

Tại sao chúng ta nên sử dụng docker?

  • Immutability: Tính không thay đổi

    • Một Immutablity image chứa mọi thứ để chạy một ứng dụng bao gồm cả source code của mình
  • Repeatability: Tính lặp lại, có thể tái sử dụng dễ dàng

  • Shared enviroment: Mình có thể chia sẻ cho bất cứ ai, bạn bè mà muốn chạy ứng dụng của mình, chỉ cần sử dụng các image có sẵn mà mình đang sử dụng vậy là chúng ta đã có một same enviroment.

    • Ok giờ mấy đứa bạn mình đang phát triển web với Ruby, đơn giản nó muốn nhờ mình test hộ nó trên máy của mình mà ứng dụng chưa được đẩy lên host nghĩa là vẫn local. Tuy nhiên mình thì chưa bao giờ lập trình với Ruby nên các tool cần thiết để chạy ứng dụng của nó trên máy mình không có.
    • Vậy chẳng lẽ chỉ cần test hay contribute một số thứ đơn giản cho nó mà lại phải cài một đống thứ vào máy à? Vấn đề đã được giải quyết với docker. Mình hỏi thằng bạn cần cài đặt những ứng dụng nào để chạy app của nó và các câu lệnh cần thực hiện trước khi start ứng dụng là gì. Sau đó lên google tìm các image cần thiết để chứa môi trường khởi chạy ứng dụng mình cần và chạy thôi.
  • Versioning: Về phiên bản của các ứng dụng cần thiết ví dụ như Apache, Mysql, mình có thể dễ dàng lựa chọn các phiên bản cần thiết vì hầu hết được cộng đồng lập trình viên docker update khá nhanh chóng.

    • Việc chuyển đổi giữa các phiên bản dễ dàng. Bạn có các image với các version khác nhau của mysql chẳng hạn, sử dụng bất cứ version nào bạn muốn phù hợp với ứng dụng của mình
  • Automation: Tính tự động, khác dễ dàng đễ start server chỉ thông qua vài dòng lệnh trên terminal

  • Isolate: Tính độc lập.

    • Mình không cài trực tiếp các ứng dụng server cần thiết cho app của mình lên máy một các locally mà các cài đặt cần thiết được build trong các gói (image)

Các khái niệm cần biết

Image

"Docker images are OS boxes that contain some pre-installed and configured software"

Hiểu đơn giản nó sẽ chứa các cài đặt sẵn để cho chúng ta sử dụng. Nó như cái hộp bọc lấy phần setup của mình

  • Ví dụ trên máy mình cài Apache2 thì mình sẽ chạy câu lệnh cần thiết để cài đặt nó, tuy nhiên nếu mình sử dụng docker mình chỉ cần lên mạng tìm lấy image nào chứa thằng Apache2 này mà dùng thôi, mọi gói và setup cần thiết đã được đặt trong image.

  • Để xem trên máy mình có những image nào mình dùng lệnh sau

    • $ docker images

      dk-image.png

      Repository là tên của image mà mình pull về Tag: Là version tương ứng

Container

04-malcolm-env-opt.jpg

"Docker containers are separate instances that we create from images"

  • Qua hình các bạn rất dễ để hình dung ra container là gì rồi đúng không?

  • Nó chính là các instance của các image mà mình có. Chúng ta có các image về service cần thiết rồi, việc cần làm là run các thằng image đó vào trong các container và dùng thằng nào thì start thằng đó

  • Docker container còn được gọi là Linux Container (LXC).

  • Để xem trên máy có những container nào sử dụng

    • $docker ps -a

dk-container.png

  • Nếu muốn xem những container nào đang được start thì mình sẽ dùng

    • $docker ps

Volume

Volume là cách dễ dàng để chia sẻ vùng nhớ giữa máy chủ của mình và container. Nó được tạo ra trong suốt quá trình container được chạy và luôn được đồng bộ

Ví dụ mình muốn mount /var/www/html trong container tới đường dẫn local trên máy chủ của mình ~/docker-project/lara-new

  docker run -v <local dir>:<container dir>

Expose port

Cổng của ứng dụng

  • Ví dụ mình dùng mysql container, bên ngoài mình cài mysql-workbench để làm việc, mặc định bên trong container sẽ setup cổng đối với mysql là 3306 đúng không, nhưng nếu mà bên ngoài máy local của mình đã sử dụng port 3306 cho mục đích nào đó => Conflict. Và mình sẽ không thể dùng workbench tạo connection tới port 3306 được.
  • Làm việc với docker mình có thể export cổng bên trong container ra cổng bên ngoài tương ứng. Ví dụ trong conatainer port 3306 của mysql thì mình sẽ export nó ra bên ngoài là 3307 chẳng hạn => Vấn đề được giải quyết

Một số lệnh cơ bản làm việc với docker

  • Bạn có image Mysql, bạn muốn start server mysql để làm việc với cơ sở dữ liệu, chỉ cần chạy

        $ docker run image
    
  • Khi đó một container tương ứng với image sẽ được tạo ra. image ở đây chính là tên của image trong cột Repository mà mình nhắc tới trong phần khái niệm image

  • Mình muốn export cổng 3306 trong container ra máy local là 3307

    $$docker run --port 3307:3306 image

  • Mình muốn đặt tên cho container của mình khi nó đượct tạo ra

    $$ocker run --name containerName image

  • Mình muốn mount giữa folder làm việc bên ngoài với thằng trong container tương ứng

    $$ocker run --volume pathOnMyComputer:intheContainer image

  • Đó bây giờ mình muốn nhiều tùy chọn vừa đặt tên, export cổng, vừa mount thư mục thì gộp các lênh bên trên lại

    $$docker run --port 3307:3306 --name MySql .... mysql

Giả sử image name của mình là mysql chẳng hạn

Khi đó $ docker ps sẽ cho mình thấy thằng container nào đã được tạo ra và đang chạy

Start/stop một cách đơn giản thông qua

  $ docker start/stop containerId

Khi show ra container mình sẽ biết được Id của từng thằng tương ứng.

Demo

  • Cài đặt docker: install docker

  • Pull image tutum/apache-php về bằng cách chạy

      docker pull tutum/apache-php
    
  • Pull image mysql

      docker pull mysql
    
  • Phiên bản của mysql và apache-php và mysql có thể tùy chọn được, bạn chỉ cần làm theo hướng dẫn trên 2 link mình đưa bên trên

  • Ok giờ bạn kiểm tra 2 images trên của mình đã được pull về hay chưa

      docker images
    

dk-image.png

  • Ok mình có một folder như thế này ~/dokder-project/lara-new. Đây là một project laravel mà mình mới create. Thông thường mình sẽ để nó trong /var/www/html/lara-new để rồi chạy nó đúng không (Giả sử đường dẫn làm việc của apache trên máy mình vẫn để là mặc định).
    • Bây giờ muốn chạy nó với docker mình làm như thế nào?
      • Tương tự như khi bạn làm trực tiếp trên máy chủ của bạn thì trong container bạn cần vứt thằng lara-new này vào trong đường dẫn làm việc của apache trong container. Mình cần tưởng tượng là mọi thứ đang được chạy bên trong container
  • Mount folder trên máy chủ vào trong thư mục làm việc của apache trong containter

      docker run -tid -p 9000:80 -v ~/www/sites:/var/www/html tutum/apache-php
    
  • Ở đây trong www/sites chứa các folder project web của mình. Đây cũng chính là thư mục làm việc của apache mà mình đã đổi từ mặc định /var/www/html sang

docker-run-test.png

  • Giờ sử kiểm tra xem container đã được create và đang chạy chưa

     docker ps
    

docker-ps.png

  • Mở trình duyệt chạy localhost:9000 vì nãy mình export cổng 80 mà mặc định apache sử dụng trong container ra cổng 9000 bên ngoài và kết quả

localhost:9000.png

  • Ok mọi thứ ổn, giờ mình sẽ mở trình duyệt và chạy thử project của mình

Screenshot from 2016-10-23 17-50-32.png

  • Giờ không muốn sử dụng server nữa(?)
    • docker stop containerId
    • Lần sau sử dụng thì mình lại docker start contianerId
  • Bây giờ muốn config file apache config trong site-enable chẳng hạn để tạo virtual host cho đường dẫn đẹp đẹp chẳng hạn thì làm như thế nào?
    • Mình cần chạy vào bên trong container và làm các thao tác tương tự như khi mình đang làm trên máy local mà bình thường mình vẫn làm thôi

    • Để vào container chạy

        docker exec -it containerName bash
      
    • containerName mình dùng docker ps để xem

  • Nếu bạn muốn tự làm mọi việc từ đầu bạn có thể tìm hiểu kỹ hơn với từ khóa dockerfile, tìm hiểu cú pháp trong dockerfile để build một image của riêng mình và chia sẻ cho người khác. Theo mình hiểu đơn giản thì dockerfiles khai báo một loạt những câu lệnh có thứ tự và được chạy khi bạn bắt đầu build một image
    • Ví dụ một Dockerfile đơn giản của mình như sau

        FROM busybox
        ENTRYPOINT sudo apt-get udate && sudo apt-get install -y apache2 && tail /var/log/apache2/error.log
        ENTRYPOINT service apache2 restart
        EXPOSE 80
      
    • Đó là ví dụ đơn giản bạn build một image với cài đặt của bản apache và Expose cổng 80.

    • Cùng tìm hiểu về dockerfiles sau nhé mình thấy nó cũng khá hay. Tạm thời ăn nhanh mình cứ dụng image có sẵn đã (haha)

Chú ý

  • Folder project của bạn nên để quền user, tránh để quyền root vì khi mount folder của mình sẽ bị chuyển sang quyền www-data do apache bên trong container change, dẫn tới lỗi
  • Nếu bạn làm việc với Laravel hay các phiên bản famework nào đó thì có thể lên docker hub để tìm được những image có chứa phiên bản php hay apache mới nhất

Tài liệu tham khảo

Kết luận

  • Mình xin phép được dừng bài tìm hiểu tại đây, có lẽ cũng có kha khá kiến thức cơ bản về docker để mình có thể mày mò với nó rồi
  • Bài sau mình sẽ trình bày về phần kết nối ứng dụng của mình với cơ sở dữ liệu sử dụng docker-compose
  • Cảm ơn các bạn đã dành thời gian đọc bài viết của mình. Thời gian mình tìm hiểu về docker chưa được nhiều nên có thể có nhiều sai xót, rất mong nhận được sự góp ý từ mọi người để sửa đổi nội dung bài viết được tốt hơn.