+1

Tìm hiểu cơ bản về docker qua ví dụ

Trong bài viết này mình sẽ giới thiệu cho các bạn về docker, cùng tìm hiểu các khái niệm và một số lệnh chính.

Khái niệm

Đầu tiên, chúng ta phải hiểu được khái niệm docker là gì, dùng để làm gì??? Docker là một platform giúp chúng ta develop, deploy and run application trong các container.
Lợi thế của docker là giúp chúng ta triển khai ứng dụng mà không phải phụ thuộc vào môi trường, bới vì đơn giản, môi trường mà chúng ta triển khai nó nằm trong các container, được dựng lên bởi các image, nhờ có các image đó mà chúng ta có thể tạo ra được bất kỳ container nào có setup môi trường như ý muốn tại bất cứ đâu.
Vậy container và image trong docker là gì? tại sao nó lại làm được như vậy? HIểu đơn giản thì container là một runtime instance của image, image là một executeable package bao gồm mọi thứ chúng ta cần để run một application như code, runtime, các thư viện, các biến môi trường, và cả các file config. Ví dụ chúng ta có 1 image môi trường ubuntu thì sẽ khởi tạo ra một container ubuntu, 1 môi trường mysql thì sẽ khởi tạo ra được container môi trường mysql...
Khi nói về docker thì ta thường so sánh với máy ảo, vậy chúng có gì khác nhau? Cùng tìm hiểu thông qua bức ảnh sau:


Một container được run, nó sẽ chỉ bao gồm các cấu hình của ứng dụng, thư viện, ... và được chia sẻ nhân với máy chủ hiện tại cùng với các container khác, nó được chạy bởi các process riêng rẽ, không tốn nhiều bộ nhớ và rất nhẹ.
Khác với container, máy ảo khi khởi chạy sẽ chạy một hệ điều hành guest với quyền truy cập ảo vào tài nguyên máy chủ thông qua một trình ảo hóa, và nó sẽ cung cấp một môi trường gồm nhiều tài nguyên hơn một ứng dụng cần.
Thôi, không lan man nữa, nói tóm lại chúng ta hiểu docker cho phép chúng ta chạy ứng dụng trên các môi trường được chỉ định sẵn ở bất cứ đâu bên trong các container, image có nhiệm vụ tạo ra các container đó.

Cài đặt

Có thể cài đặt docker trên nhiều môi trường như: linux, macOS, Windows... các bạn tham khảo cách cài đặt trên trang chủ của docker

Một số lệnh cơ bản

Sau khi cài đặt docker thành công chúng ta có thể check version:

~$ docker -v
Docker version 18.09.7, build 2d0083

Lưu ý, thao tác với docker yêu cầu quyền root, bạn có thể add user với quyền root docker hoặc gõ lệnh sudo -s để thao tác với user root.
Cùng tìm hiểu một số lệnh cơ bản:

  • List các image đang có: docker image ls
  • Pull image từ Docker Hub về local: docker pull <image name>
  • Xóa một image: docker image rm <image name>
  • List các container: docker container ls -a hoặc docker ps -a
  • List các container đang running: docker container ls hoặc docker ps
  • Stop 1 container: docker stop <container name>
  • Start 1 container: docker start <container name>
  • Xóa 1 container: docker rm <container name>

Để trực quan hơn, chúng ta cùng thao tác các lệnh cơ bản thông qua ví dụ:
Pull một image tên là hello-world từ Docker Hub:

~# docker pull hello-world

Using default tag: latest
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3124764528bcc1d20f
Status: Downloaded newer image for hello-world:latest

Tiếp theo, cùng kiểm tra các image đang có:

~# docker image ls

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        7 months ago        1.84kB

Run image hello-world vừa được pull về với container tên là my-example:

:~# docker run --name my-example hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Kiểm tra các container đang có, ta sẽ thấy một container có tên my-example từ image hello-world:

~# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                          PORTS                               NAMES
802073ed319a        hello-world         "/hello"                 About a minute ago   Exited (0) About a minute ago                                       my-example

Xóa container vừa được tạo ra:

~# docker container rm my-example 
my-example

Kiểm tra lại container ta sẽ thấy container có tên my-example đã được xóa:

~# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES

Sử dụng Dockerfile để deploy ứng dụng Java Spring-boot

Phần tiếp theo chúng ta cùng tìm hiểu cách sử dụng Dockerfile để deploy ứng dụng Java Spring-boot. Đầu tiên, chúng ta cùng tạo một ứng dụng Java Sring-boot cơ bản với 1 API để test:
Trước hết cùng tìm hiểu khái niệm về Dockerfile: Dockerfile chứa tập hợp các lệnh để docker có thể đọc hiểu và thực hiện để đóng gói thành một image theo yêu cầu người dùng.
Trong ví dụ này chúng ta sẽ xây dựng ứng dụng Java Spring-boot và deploy ứng dụng trên môi trường Java-8.
Cấu trúc thư mục:

demo/
├── src/
|   └── main/
|       ├── java
|       |   └── demo
|       |       ├── controller
|       |       |   └── TestController.java
|       |       └── DemoApplication.java
|       └── resources
|           └── application.properties
├── Dockerfile
└── pom.xml

File pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>demo</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

File TestController.java mô tả API test: GET - http://localhost:8080/test

package demo.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class TestController {
    @GetMapping("/test")
    public ResponseEntity<?> test() {
        return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK);
    }
}

File DemoApplication.java

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

File Dockerfile

FROM openjdk:8-jre

EXPOSE 8080

ADD ./target/demo-0.0.1-SNAPSHOT.jar /demo.jar

ENTRYPOINT ["java", "-jar", "demo.jar"]

Giải thích về file Dockerfile:

  • FROM openjdk:8-jre: base của image được tạo ra lấy từ image có tên openjdk:8-jre, nếu trên local của bạn không có image này thì docker sẽ tìm kiếm và pull image đó từ Docker Hub. Sau khi tìm kiếm thành công, docker sẽ pull image có môi trường jdk8 - jre về local và sẵn sàng xây dựng container với môi trường đó.
  • EXPOSE 8080: Container tạo ra sẽ expose ra port 8080.
  • ADD ./target/demo-0.0.1-SNAPSHOT.jar /demo.jar Lệnh copy file demo-0.0.1-SNAPSHOT.jar trong thư mục target sau khi package ứng dụng vào trong container với tên demo.jar.
  • ENTRYPOINT ["java", "-jar", "demo.jar"]: Lệnh thực thi execute file demo.jar được copy ở trong container.

Sau khi tạo cấu trúc project như trên, đầu tiên chúng ta cần package ứng dụng bằng lệnh maven: mvn clean install.
Tiếp theo chúng ta tiến hành build image từ Dockerfile tại folder chứa Dockerfile:

# docker build -t demo-app:v1 -f Dockerfile .

Sending build context to Docker daemon  16.99MB
Step 1/4 : FROM openjdk:8-jre
 ---> a61f05af7983
Step 2/4 : EXPOSE 8080
 ---> Running in c63458a5f732
Removing intermediate container c63458a5f732
 ---> af6aca65f50f
Step 3/4 : ADD ./target/demo-0.0.1-SNAPSHOT.jar /demo.jar
 ---> 9c496d3410eb
Step 4/4 : ENTRYPOINT ["java", "-jar", "demo.jar"]
 ---> Running in 7a0c9921a4c8
Removing intermediate container 7a0c9921a4c8
 ---> 19dd6e96cf7b
Successfully built 19dd6e96cf7b
Successfully tagged demo-app:v1

Như vậy chúng ra vừa xây dựng xong 1 image có tên demo-app và tag name là v1. Chúng ta có thể kiểm tra lại image vừa build:

# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
demo-app            v1                  19dd6e96cf7b        2 minutes ago       263MB

Nhắc lại, image này được khởi tạo từ image gốc là openjdk:8-jre có môi trường java và chúng ta với copy gói jar vào trong đó. Khi run image, docker sẽ tạo ra container có môi trường openjdk:8-jre và có gói jar demo.jar được copy vào thư mục gốc của container, sau đó sẽ tiến hành run gói demo.jar bằng lệnh java -jar demo.jar.
Run image bằng lệnh sau:

docker run --name demo-container -it -p 8080:8080 demo-app:v1 

Lệnh trên có ý nghĩa: Run image demo-app:v1 bằng container có tên demo-container, mapping port 8080 trong container với port 8080 trên local.
Sau khi run app thành công chúng ta có thể thoát cửa sổ terminal mà không stop container bằng cách nhấn phím ctrl + P + Q
Cùng kiểm tra các container đang chạy, ta sẽ thấy container có tên demo-container đang ở trạng thái status=Up:

# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
c419c09241fc        demo-app:v1         "java -jar demo.jar"     3 minutes ago       Up 3 minutes        0.0.0.0:8080->8080/tcp              demo-container

Do chúng ta đã mapping port 8080 trên máy local vào port 8080 trên container nên có thể dễ dàng check được API được run trong container:

~# curl -X GET http://localhost:8080/test
true

Stop container đang chạy:

~# docker stop demo-container 
demo-container

Kiểm tra lại các container ta sẽ thấy container demo-container vẫn tồn tại nhưng có status là Exited, tức là container đó đã bị stop:

~#docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS                               NAMES
c419c09241fc        demo-app:v1         "java -jar demo.jar"     5 minutes ago       Exited (143) 5 seconds ago                                       demo-container

Start lại container bằng cách:

~# docker start demo-container 
demo-container

Để xóa container trên, bạn cần stop container và sử dụng lệnh docker container rm demo-container

~# docker stop demo-container 
demo-container
~# docker container rm demo-container 
demo-container

Xóa image đã build bằng lệnh:

~# docker image rm demo-app:v1 
Untagged: demo-app:v1
Deleted: sha256:19dd6e96cf7bf98aab3041188942fb5ff287994a3b765c65565772ee7a92bfc6
Deleted: sha256:9c496d3410ebf649e6eb456e0df2517e13565f947c2eb30c564319fd122231f3
Deleted: sha256:edff43eb4defd8e60ae3b89091fb997da19876ba89eaddb91754e9c3e10f2021
Deleted: sha256:af6aca65f50f5b1e5d56ca43d0019e6f789bda6fa18b285980c7012e4d0e3ece

Kết luận

Như vậy, qua bài viết mình đã giới thiệu về docker và một số lệnh cơ bản để sử dụng docker để deploy một ứng dụng đơn giản. Hy vọng bài viết giúp được các bạn hiểu về docker, cách sử dụng cơ bản và phần nào giúp ích các bạn trong học tập cũng như trong công việc. Cảm ơn các bạn theo dõi!!!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.