Hướng dẫn docker-php-apache mysql

Xin chào các bạn, hôm nay mình sẽ hướng dẫn các bạn chạy container Apache/PHP (xem lại bài 4) kết nối với MySQL container. Mình sẽ ví dụ bằng source code Login đơn giản.

Để chạy container Apache/PHP các bạn sử dụng image webdevops/php-apache-dev, mình đã có hướng dẫn ở bài 4 các bạn có thể tham khảo lại.

Image MySQL mình sử dụng Docker official MySQL image

Tuyệt vời, bây giờ chúng ta hãy chạy một container MySQL cùng với container Apache/PHP và cách liên kết các container này lại với nhau. Như vậy source code của chúng ta có thể dễ dàng kết nối database.

Các bạn download source code trong hướng dẫn tại đây: tải source code

Mời các bạn xem video hướng dẫn:

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

Hướng dẫn docker-php-apache mysql

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

Rất xin lỗi vì sau bài viết trước Docker với lập trình viên web của mình thì mình lại ngắt quãng không thể đi luôn vào phần tìm hiểu tiếp tục kết nối với cơ sở dữ liệu. Hôm nay chúng ta sẽ cùng đi giải quyết vấn đề đó.

Bài toán

  • Mình có một project php tên là selfproject xây dựng dựa trên laravel framework. Project này làm việc với hệ quản trị CSDL là MySql.

  • Vấn đề là bây giờ mình muốn chạy nó với docker! `

Giải quyết

Cách 1

  • Theo như bài tìm hiểu lần trước mình sẽ sử dụng các images đã được chia sẻ bởi các lập trình viên khác trên dockerhub.

  • Mình sẽ sử dụng 2 images đó là tutum/apache-php cho service apache-php và mysql cho mysql server.

  • Đầu tiên mình cần tạo MySQL container trước

      docker run -p 3307:3306 --name mysqlserver -e MYSQL_ROOT_PASSWORD=root -d mysql
    

  • Sau đó tạo web server container

      docker run -tid -p 9000:80 -v ~/www/sites/FrProject/Github/selfproject:/var/www/html --name selfproject-server --link mysqlserver:mysql  tutum/apache-php
    

  • Ở đây mình cần mở rộng hơn trong bài tìm hiểu lần trước, đó là mình có 2 container là mysqlserverselfproject-server, để chúng có thể giao tiếp với nhau cần link web server với mysql thông qua tùy chọn --link :

  • Bây giờ mở trình duyệt và thử kết quả

Lý do?

Mình quên config lại trong file .env

    DB_CONNECTION=mysql

    # host bên ngoài local

    # DB_HOST=127.0.0.1

    # Sửa trong container nên sẽ config lại

    DB_HOST=mysql
    DB_PORT=3306
    DB_DATABASE=selfproject
    DB_USERNAME=root
    DB_PASSWORD=root
  • Kết nối tới database trong container tạo db có tên selfproject. Ở command tạo MYSQL container mình cần expose port ra bên ngoài container là 3307. Do ở máy mình cổng 3306 đã được sử dụng cho ứng dụng khác.

  • Ở đây mình sử dụng công cụ trực quan mysql-workbench để thao tác với mysql, các bạn có thể dụng công cụ khác như php-myadmin...

  • Giờ vào vào trong container để migrate dữ liệu

      docker exec -it containerName/containerId bash
    
      # Với mình
    
      docker exec -it selfproject-server bash
    
  • Và giờ là kết quả

  • Nhưng khi muốn vào đăng ký mình gặp phải

Vấn đề: không thể truy cập được url nào khác ngoài public. Khắc phục: trong container mình cần sửa lại file apache.conf đoạn AllowOverride None thành AllowOverride ALL trong

  • Vào trong container
    docker exec -it containerName/caintainerId bash
  • Sử dụng vim để sửa lại file apache.conf (Do container mình đang dùng không có nano =)) )
    vi /etc/apache2/apache2.conf

        **Sửa như sau**

    
    Options Indexes FollowSymLinks
    AllowOverride ALL
    Require all granted
    
  • Save lại và restart service apache bên trong container.
           service apache2 restart
  • Lúc này thì web server container này của mình sẽ bị terminate (ngắt kết nối) và mình cần start nó lại

Bên ngoài máy chủ của mình

docker start containerName/containerId

Với mình

 docker start selfproject-server

Kết quả thu được

Ngon chạy rồi (hehe). Thử tương tác với db coi sao. Mình thử tạo một bài post và đây là kết quả

Các bạn thử stop cả mysqlserver với web server đi rối start lại xem còn chạy và dữ liệu ok không nhé. Với mình thì tuyệt vời!

Một số câu hỏi và vấn đề mà mình gặp khi mới bắt đầu

  • Vậy dữ liệu hắn lưu ở đâu?

           Vào trong mysql container nhé và trong /var/lib/mysql/
    
  • Nên cẩn thận khi xóa container này nhé. Mình có thể khắc phục được vấn đề này là cũng mount /var/lib/mysql trong container ra một folder nào đó ngoài máy chủ của mình chẳng hạn "mysql-data" do mình tự tạo giống như mình mount folder project (nhớ nên để folder quyền user nhé, tránh để root) làm việc vào trong /var/www/html khi create web server container vậy!

  • Stop tất cả các container đang chạy

          docker stop $(docker ps -a -q)
    
  • Khi mình chỉnh sửa, làm việc với project thì sẽ gặp phải vấn đề permission do khi mount vào trong container thì nó sửa toàn bộ dữ liệu trong folder của mình về owner và group là www-data, chứ không còn là current user của mình hoặc root nữa. Vậy nên mình vào trong container và cấp quyền ghi cho project của mình với user là guest.

      # Vào trong container web server
      # Đi đến folder project mà bạn đã mount
    
          chmod 777 -R .
       
      # Quyền các bạn tùy chọn nói chung là dạng --7 để thằng user không phải owner có thể ghi
    
  • Với laravel 5.3 mình không thể chạy php artisan trong container mặc dù bên ngoài vẫn ok

  • Lý do: laravel 5.3 yêu cầu version của php > 5.6 trong khi image mình đang dùng là tutum/apache-php với version php 5.5.9. Khá đau đầu với ông này mình mới nhìn ra được =))
  • Khắc phục: Tự build image hoặc sử dụng image khác có sẵn mà phiên bản > 5.6. Với mình chọn sử dụng image được chia sẻ bởi cộng đồng docker-hub. Thay vì dùng tutum/apache-php thì dùng webdevops/php-apache (Ông này cũng có vấn đề với bản laravel 5.4 nên nếu có lỗi bạn có thể thử với nimmis/apache-php7 hoặc bất cứ ông nào mà bạn tìm thấy trên docker hub và cảm thấy phù hợp với project của mình)

Cách 2

Take it easy với Docker compose

  • Chẳng lẽ mỗi lần code lại start từng con server một, nếu có 3 hay nhiều hơn nữa thì mệt quá, phải nhớ container name vì id là bất khả thi rồi =)). Rồi lại cần nhớ thứ tự start nữa.

    • Như việc link Mysql với Apache thì cần start server MySql trước sau đó start Apache container
  • Điều đó dẫn đến việc mình bắt đầu thử sử dụng Docker compose

What is Docker composer

  • Docker compose là một công cụ cho việc định nghĩa và khởi chạy nhiều container với docker. Với compose mình sẽ khai báo nhiều container trong cùng một file và chỉ việc chạy một dòng lệnh là nó sẽ làm mọi việc start container cho mình.

  • Bạn có thể tham khảo tại đây

Sử dụng docker compose cho ứng dụng của mình

  • Cài đặt docker-compose thì các bạn cài đặt theo hướng dẫn tại trang chủ docker nhé.

  • Tạo docker compose file với tên docker-compose.yml

  • Khai báo mysql server và web server trong compose file này

      # docker-compose.yml
    
      version: "2"
    
      services:
    
          selfproject:
              image: tutum/apache-php
              links:
                  - mysql
              ports:
                  - "8888:80"
              networks:
                  - back-tier
              volumes:
                  - .:/var/www/html/selproject
              environment:
                  - ALLOW_OVERRIDE=true
              hostname: selfproject
              cpu_shares: 512             # 0.5 CPU
              mem_limit: 536870912        # 512 MB RAM
    
          mysql:
              image: mysql
              ports:
                  - "3307:3306"
              networks:
                  - back-tier
              volumes:
                  - ./mysql-data/:/var/lib/mysql/
              environment:
                  - MYSQL_ROOT_PASSWORD=root
                  - MYSQL_DATABASE=selfproject
              hostname: mysql
              cpu_shares: 512             # 0.5 CPU
              mem_limit: 536870912        # 512 MB RAM
    
      networks:
          back-tier:
    
  • Về các options trong compose file mình sẽ không nói nhiều vì nó được mô tả khá chi tiết tại Composefile reference trên trang chủ của docker

  • Giải thích chút về nội dung file compose của mình

    • Trước tiên là về version sử dụng đối với docker file là version '2'. Bạn có thể tìm hiểu thêm trên trang chủ docker. Version '1' là 'legacy format', version hiện tại là '2.1' và '2' là version được khuyến khích sử dụng có một số thay đổi về options so với version '1'.
    • Với service mysql:
      • image sử dụng là mysql
      • ports ở đây như mình đã nói với phần sử dụng command. 3306 là port được sử dụng bên trong container, 3307 được export ra bên ngoài để mình có thể xem và thao tác với dữ liệu.
      • networks sử dụng là back-tier
      • volumes ở đây chính là mount folder bên ngoài với bên trong container như phần sử dụng command. './mysql-data' là folder mình muốn lưu trữ dữ liệu ở bên ngoài, bạn có thể link bất kỳ tới đâu bạn muốn.
      • hostname: mysql
    • Với web service
      • image mình sử dụ là tutum/apache-php. Lưu ý là với laravel 5.2 trở về trước nhé, hay là với project mình không yêu cầu version php > 5.6
      • links tới mysql container
      • networks: cũng phải sử dụng là back-tier cùng với mysql cho toàn bộ service trong compose file để các container có thể giao tiếp với nhau
      • volumes: Do docker-compose.yml file này của mình đặt ngày trong folder selfproject của mình nên đường dẫn đến project bên ngoài máy chủ là "." thư mục hiện tại và mount vào "/var/www/html/selproject" trong container
      • environment:
          - ALLOW_OVERRIDE=true
        
      • Như vấn đề với Override mà mình đã nói bên trên và đoạn config này giải quyết vấn đề đó.
  • OK việc cần làm là start nó

      # Đi đến thư mục chứa compose file
    
          docker-compose up
    
      # Khi làm việc xong
    
          docker-compose down
    
  • Nhớ lưu ý tới việc quyền hạn và config nhá

Kết luận

  • 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.

  • Hiện tại trong tài liệu chính thức của docker compose không khuyến nghị sử dụng cho production, chỉ nên sử dụng ở môi trường development, staging, continous integration