利用 Docker Compose 搭建 SpringBoot 運行環境(超詳細步驟和分析)

0、前言

相信點進來看這篇文章的同窗們已經對 Docker Dompose 有必定的瞭解了,下面,咱們拿最簡單的例子來介紹如何使用 Docker Compose 來管理項目。
本文例子:
一個應用服務( Spring Boot 的 jar 包)、 Mysql 服務和 Redis 服務。在每次啓動,咱們要先將 Mysql 容器和 Redis 容器啓動起來,再將應用容器運行起來,這其中還不要忘了在建立應用容器時將容器網絡鏈接到 MySQL 容器和 Redis 容器上,以便應用鏈接上它們並進行數據交換。html

一、項目結構

爲了方便進行管理和遷移,咱們建議將 Docker Compose 項目與搭建一個軟件開發項目同樣,將項目的內容彙集到一個文件目錄中,下面是一個比較通用的項目結構:java

└─ project
   ├─ app
   ├─ compose
   │  └─ docker-compose.yml
   ├─ mysql
   │  └─ my.cnf
   ├─ redis
      └─ redis.conf

在這個目錄結構中,區分了 5 個頂層目錄:mysql

  • app :用於存放程序工程,即代碼、編譯結果以及相關的庫、工具等;
  • compose :用於定義 Docker Compose 項目;
  • mysql :與 MySQL 相關配置等內容;
  • redis :與 Redis 相關配置等內容;

二、準備程序配置

爲了更方便在開發過程當中對 MySQL、Redis 程序自己管理,因此咱們會將它們的核心配置放置到項目裏,再經過掛載的方式映射到容器中。
這樣一來,咱們就能夠直接在咱們宿主操做系統裏直接修改這些配置,無須再進入到容器中了。
基於此,咱們在完成目錄的設計以後,首要解決的問題就是準備好這些程序中會常常變更的配置,並把它們放置在程序對應的目錄之中。git

咱們經常使用下列幾種方式來得到程序的配置文件:github

  • 藉助配置文檔直接編寫
  • 下載程序源代碼中的配置樣例
  • 經過容器中的默認配置得到
1)藉助配置文檔直接編寫一個 MySQL 的配置文件:

咱們先找到 MySQL 文檔中關於配置文件的參考,也就是下面這個地址:
https://dev.mysql.com/doc/refman/5.7/en/server-options.html
咱們根據這些內容,選取跟咱們程序運行有影響的幾項須要修改的參數,編寫成 MySQL 的配置文件。web

# ./mysql/my.cnf

[mysqld_safe]
pid-file = /var/run/mysqld/mysqld.pid
socket   = /var/run/mysqld/mysqld.sock
nice     = 0

[mysqld]
skip-host-cache
skip-name-resolve
explicit_defaults_for_timestamp

bind-address = 0.0.0.0
port         = 3306

user      = mysql
pid-file  = /var/run/mysqld/mysqld.pid
socket    = /var/run/mysqld/mysqld.sock
log-error = /var/log/mysql/error.log
basedir   = /usr
datadir   = /var/lib/mysql
tmpdir    = /tmp
sql_mode  = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

lc-messages-dir = /usr/share/mysql

symbolic-links = 0
2)下載Redis源代碼中的配置樣例:

在 Redis 源代碼中,就包含了一份默認的配置文件,咱們能夠基於上面作修改:
github上面的連接:https://github.com/antirez/redis/blob/3.2/redis.conf
其中我修改了最主要的密碼:redis

# ./redis/redis.conf
##...
################################## SECURITY ###################################

# Require clients to issue AUTH <PASSWORD> before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
# 鏈接Redis須要的密碼
requirepass Redis123
##...

三、上傳應用jar包到app文件夾,並編寫Dockerfile文件

這個是基於java:8鏡像提交的webapp鏡像,你們可參考上一篇文章:https://blog.csdn.net/Howinfun/article/details/102514099spring

四、編寫Docker Compose項目的定義文件

docker-compose.yml 文件在compose文件夾下,下面是我本身根據需求編寫的:sql

version: "3"

services:

  redis:
    image: redis:3.2
    container_name: app_redis
    volumes:
      - ../redis/redis.conf:/etc/redis/redis.conf:ro
      - ../redis/data:/data
    command:
      - redis-server
      - /etc/redis/redis.conf
    ports:
     - 6379:6379

  mysql:
    image: mysql:5.7
    container_name: app_mysql
    volumes:
      - ../mysql/my.cnf:/etc/mysql/my.cnf:ro
      - ../mysql/data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    ports:
      - 3306:3306
   
  webapp:
    build: ../app
    container_name: app_web
    depends_on:
        - mysql
        - redis
    ports:
        - "8888:8888"

稍微講解一下:
version:版本號,最新爲3
services:Compose項目的服務配置
redis:docker

  • image:基於redis:3.2鏡像
  • container_name:容器名
  • volumes:第一個是將項目中的寫好的配置文件經過掛載的方式映射到容器中,並且ro指定了文件爲只讀;第二個是將Redis 容器中的 /data 目錄經過掛載的方式綁定到了宿主機上的目錄中
  • command:建立容器時執行的命令,這裏是啓動redis服務的命令
  • ports:對外開放的訪問端口號

mysql

  • image:基於mysql:5.7鏡像
  • container_name:容器名
  • volumes:第一個是將項目中的寫好的配置文件經過掛載的方式映射到容器中,並且ro指定了文件爲只讀;第二個是將MySQL 容器中的 /var/lib/mysql 目錄經過掛載的方式綁定到了宿主機上的目錄中
  • environment:爲 MySQL 設置了初始密碼
  • ports:對外開放的訪問端口號

webapp:

  • build:經過Dockerfile構建鏡像,這裏是指定Dockerfile文件的路徑
  • container_name:容器名
  • depends_on:依賴於mysql和redis容器(在 Docker Compose 爲咱們啓動項目的時候,會檢查全部依賴,造成正確的啓動順序並按這個順序來依次啓動容器。)
  • ports:對外開放的訪問端口號

在這個項目裏,我將 Redis 和 MySQL 的數據存儲目錄,也就是 Redis 容器中的 /data 目錄和 MySQL 容器中的 /var/lib/mysql 目錄經過掛載的方式綁定到了宿主機上的目錄中。 這麼作的目的是爲了讓 Redis 和 MySQL 的數據可以持久化存儲,避免咱們在建立和移除容器時形成數據的流失。
同時,這種將數據掛載出來的方法,能夠直接方便咱們打包數據並傳送給其餘開發者,方便開發過程當中進行聯調。

五、啓動Compose項目

docker-compose up 命令相似於 Docker Engine 中的 docker run,它會根據 docker-compose.yml 中配置的內容,建立全部的容器、網絡、數據卷等等內容,並將它們啓動。與 docker run 同樣,默認狀況下 docker-compose up 會在「前臺」運行,咱們能夠用 -d 選項使其「後臺」運行。事實上,咱們大多數狀況都會加上 -d 選項。

docker-compose -p appweb -f ./compose/docker-compose.yml up -d

命令參數:

  • -p:項目名稱
  • -f:指定docker-compose.yml文件路徑
  • -d:後臺啓動
[root@izwz90lvzs7171wgdhul8az project2]# docker-compose -p appweb -f ./compose/docker-compose.yml up -d
Building webapp
Step 1/5 : FROM java:8
 ---> d23bdf5b1b1b
Step 2/5 : MAINTAINER Howinfun
 ---> Using cache
 ---> f72d0468f1ff
Step 3/5 : VOLUME /tmp
 ---> Using cache
 ---> 902b3df17b06
Step 4/5 : ADD  app.jar /root/docker_test/app.jar
 ---> 511f44917a82
Step 5/5 : ENTRYPOINT ["nohup","java","-jar","/root/docker_test/app.jar",">","/root/docker_test/app.log","&"]
 ---> Running in 4825ec9daf24
Removing intermediate container 4825ec9daf24
 ---> 5e009b2fc6ae
Successfully built 5e009b2fc6ae
Successfully tagged appweb_webapp:latest
WARNING: Image for service webapp was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating app_mysql ... done
Creating app_redis ... done
Creating app_web   ... done

查看建立的鏡像:

[root@izwz90lvzs7171wgdhul8az project2]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
appweb_webapp       latest              5e009b2fc6ae        45 seconds ago      686MB
mysql               5.7                 383867b75fd2        4 weeks ago         373MB
redis               3.2                 87856cc39862        12 months ago       76MB

查看正在啓動的容器:

[root@izwz90lvzs7171wgdhul8az project2]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                               NAMES
ccaa96d508d1        appweb_webapp       "nohup java -jar /ro??   About a minute ago   Up About a minute   0.0.0.0:8888->8888/tcp              app_web
790629b5e7d0        mysql:5.7           "docker-entrypoint.s??   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, 33060/tcp   app_mysql
610d0b89c267        redis:3.2           "docker-entrypoint.s??   About a minute ago   Up About a minute   0.0.0.0:6379->6379/tcp              app_redis

六、訪問接口

容器啓動後,咱們嘗試使用postman或者其餘http工具去訪問部署在容器中的應用接口。

七、網絡配置

咱們都知道,使用 Docker 打包鏡像,咱們能夠在任意的環境下部署和運行項目,Docker 的容器可以很輕鬆的運行在開發者本地的電腦,數據中心的物理機或虛擬機,雲服務商提供的雲服務器,甚至是混合環境中。
可是,這裏的每個環境的IP地址但是不同,並且,應用服務連接的Mysql數據庫,或者Redis緩存那一定是要和部署環境的IP地址一一對應的,那麼難道咱們還須要每次都去修改配置文件的IP嗎?
答案是:不用的!
在 Docker Compose 裏,咱們能夠爲整個應用系統設置一個或多個網絡。要使用網絡,咱們必須先聲明網絡。聲明網絡的配置一樣獨立於 services 存在,是位於根配置下的 networks 配置。
下面咱們嘗試在docker-compose.yml中添加網絡配置。

version: "3"

services:

  redis:
    image: redis:3.2
    container_name: app_redis
    volumes:
      - ../redis/redis.conf:/etc/redis/redis.conf:ro
      - ../redis/data:/data
    command:
      - redis-server
      - /etc/redis/redis.conf
    ports:
      - 6379:6379
    networks:
      - appnet

  mysql:
    image: mysql:5.7
    container_name: app_mysql
    volumes:
      - ../mysql/my.cnf:/etc/mysql/my.cnf:ro
      - ../mysql/data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    ports:
      - 3306:3306
    networks:
      - appnet
   
  webapp:
    build: ../app
    container_name: app_web
    depends_on:
      - mysql
      - redis
    ports:
      - "8888:8888"
    networks:
      - appnet

networks:
  appnet:
    driver: bridge

能夠看到,咱們在docker-compose.yml文件的最下面添加了關於網絡的配置。網絡名爲appnet,網絡驅動爲 Bridge
Bridge 網絡是 Docker 容器的默認網絡驅動,簡而言之其就是經過網橋來實現網絡通信。
而後在每一個服務的下面都配置上服務所在的網格,就是上面的 appnet 了。
接下來,修改 application.properties 中的IP,改成容器名或者服務名做爲網絡地址。
例如個人配置文件要將 MySql 和 Redis 的IP,改成各自服務的容器名:

#Mysql
spring.datasource.url=jdbc\:mysql\://app_mysql\:3306/test?useUnicode\=true&characterEncoding\=utf-8&allowMultiQueries=true&&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

#Redis
spring.redis.host=app_redis
spring.redis.password=Redis123..
spring.redis.database=1

八、中止項目

docker-compose up 相反,docker-compose down 命令用於中止全部的容器,並將它們刪除,同時消除網絡等配置內容,也就是幾乎將這個 Docker Compose 項目的全部影響從 Docker 中清除。

docker-compose -p appweb -f ./compose/docker-compose.yml down --rmi all

命令參數:

  • -p:項目名稱(up的時候有的,down必定也要帶上,否則找不到network)
  • -f:docker-compose.yml路徑
  • down:中止容器,並刪除容器
  • --rmi all:刪除項目的全部鏡像
[root@izwz90lvzs7171wgdhul8az project2]# docker-compose -p appweb -f ./compose/docker-compose.yml down --rmi all
Stopping app_web   ... done
Stopping app_mysql ... done
Stopping app_redis ... done
Removing app_web   ... done
Removing app_mysql ... done
Removing app_redis ... done
Removing network appweb_default
Removing image redis:3.2
Removing image mysql:5.7
Removing image appweb_webapp

注意:若是在使用 up 命令時指定了項目名,而在 down 命令時沒有指定項目名會報錯

[root@izwz90lvzs7171wgdhul8az project2]# docker-compose -f ./compose/docker-compose.yml down
Removing network compose_default
WARNING: Network compose_default not found.

九、從新利用up命令啓動項目

docker-compose -p appweb -f ./compose/docker-compose.yml up -d

命令參數:

  • -p:項目名稱
  • -f:指定docker-compose.yml文件路徑
  • -d:後臺啓動
[root@izwz90lvzs7171wgdhul8az project2]# docker-compose -p appweb -f ./compose/docker-compose.yml up -d
Creating network "appweb_appnet" with driver "bridge"
Pulling redis (redis:3.2)...
3.2: Pulling from library/redis
f17d81b4b692: Pull complete
b32474098757: Pull complete
8980cabe8bc2: Pull complete
58af19693e78: Pull complete
a977782cf22d: Pull complete
9c1e268980b7: Pull complete
Digest: sha256:7b0a40301bc1567205e6461c5bf94c38e1e1ad0169709e49132cafc47f6b51f3
Status: Downloaded newer image for redis:3.2
Pulling mysql (mysql:5.7)...
5.7: Pulling from library/mysql
8f91359f1fff: Pull complete
6bbb1c853362: Pull complete
e6e554c0af6f: Pull complete
f391c1a77330: Pull complete
414a8a88eabc: Pull complete
fee78658f4dd: Pull complete
9568f6bff01b: Pull complete
76041efb6f83: Pull complete
ea54dbd83183: Pull complete
566857d8f022: Pull complete
01c09495c6e7: Pull complete
Digest: sha256:f7985e36c668bb862a0e506f4ef9acdd1254cdf690469816f99633898895f7fa
Status: Downloaded newer image for mysql:5.7
Building webapp
Step 1/5 : FROM java:8
 ---> d23bdf5b1b1b
Step 2/5 : MAINTAINER Howinfun
 ---> Using cache
 ---> f72d0468f1ff
Step 3/5 : VOLUME /tmp
 ---> Using cache
 ---> 902b3df17b06
Step 4/5 : ADD  app.jar /root/docker_test/app.jar
 ---> 674b9e9f9766
Step 5/5 : ENTRYPOINT ["nohup","java","-jar","/root/docker_test/app.jar",">","/root/docker_test/app.log","&"]
 ---> Running in 428e426ccede
Removing intermediate container 428e426ccede
 ---> f0f5e8bf51cb
Successfully built f0f5e8bf51cb
Successfully tagged appweb_webapp:latest
WARNING: Image for service webapp was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating app_mysql ... done
Creating app_redis ... done
Creating app_web   ... done
[root@izwz90lvzs7171wgdhul8az project2]#

上面咱們能夠很清楚的看到,啓動項目時第一件事情就是建立項目配置的網絡 appnet 了。
最後咱們再嘗試測試一下接口,能夠發現是沒有問題的。那麼就是說,如今這個項目打包到哪裏均可以運行了,而不用理會不一樣環境下的不一樣網絡。

十、結束

到這裏,利用 Docker Compose 搭建 Spring Boot 運行環境已經所有完成。其實只要掌握了這個搭建方法,之後不論是搭建 Spring Cloud 微服務,甚至是其餘語言,例如 Python、Go等,方法都是同樣的,最主要的是服務的配置和之間的依賴,即編寫 Docker Compose 的定義文件 docker-compose.yml。

相關文章
相關標籤/搜索