如何用Docker Compose部署專案?

秦怀杂货店發表於2021-12-21

[TOC]

前言

之前我們用docker部署了springboot,redis,mysql的專案,但是是部署在三個不同的容器裡,還需要先知道redismysqlip地址,手動配置到springboot應用容器裡,我只是想快速在本地進行測試啊,這樣成本太高了,有沒有什麼辦法,把他們集中管理呢?比如把它構建成為一個映象。

辦法總是有的,那就是Docker Compose

之前的專案地址:https://github.com/Damaer/Dem...

Docker Compose

1. Docker Compose是什麼?

Docker Compose其實就是用來定義和執行復雜應用的Docker工具,什麼叫複雜應用,比如前面寫的springboot+redis+mysql,裡面就有三個容器,這種多個容器的,用一個工具來管理,它不香麼?

docker compose 透過配置檔案來管理多個 Docker 容器,在配置檔案中,所有的容器透過service來進行定義,然後使用docker-compose指令碼來啟動、停止、重啟應用以及應用中的服務和所依賴的容器等。

2. Docker Compose 的具體步驟

一般是三個步驟:

  • 使用Dockerfile 來定義應用程式的環境
  • docker-compose.yml 定義構成應用程式的服務,這樣它們可以在隔離環境中一起執行。
  • 執行 docker-compose up 命令來啟動並執行整個應用程式。

我使用的是Mac OS,裝Docker的時候已經把Docker Compose也安裝好了,不需要單獨安裝。

3. 如何在IDEA專案裡面使用Docker Compose

首先pom.xml檔案中需要注意配置小寫的artifactId:

    <groupId>com.aphysia</groupId>
    <artifactId>dockerdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dockerdemo</name>
    <packaging>jar</packaging>

除此之外還需要配置外掛:

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.0.0</version>
                <!-- 將外掛繫結在某個phase執行 -->
                <executions>
                    <execution>
                        <id>build-image</id>
                        <!-- 使用者只需執行mvn package ,就會自動執行mvn docker:build -->
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build>

除此之外,Dockerfile是必要的,上面的外掛中已經配置了我們dockerFile需要放在<dockerDirectory>src/main/docker</dockerDirectory>這個位置,DockerFile裡面配置如下:

FROM openjdk:8-jdk-alpine
EXPOSE 8081
VOLUME /tmp
# 重寫命名為app.jar
ADD dockerdemo-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

理論上到這個時候,我們使用mvn clean package就會生成對應的jar包:

image-20211128215558740

docker compose最重要的是配置docker-compose.yml,這個檔案我們放在專案的根目錄就可以,和pom.xml平級:

version: "3"

services:
  redis:
    image: redis:latest
    restart: always
    ports:
      - "6389:6379"
    volumes:
      - /tmp/redis.conf:/etc/redis/redis.conf
    command: redis-server /etc/redis/redis.conf

  mysql:
    image: mysql:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MYSQL_USER: 'root'
      MYSQL_PASS: '123456'
    ports:
      - "3306:3306"
    volumes:
      - "./db:/var/lib/mysql"
      - "./conf/my.cnf:/etc/my.cnf"
      - "./init:/docker-entrypoint-initdb.d/"
  # 指定服務名稱
  webapp:
    # 指定服務使用的映象
    image: aphysia/dockerdemo
    # 指定容器名稱
    container_name: dockerdemo
    # 指定服務執行的埠
    ports:
      - 8081:8081
    # 指定容器中需要掛載的檔案
    volumes:
      - /etc/localtime:/etc/localtime
      - /tmp/dockerdemo/logs:/var/logs

值得注意的點:

  1. service裡面就是我們配置的映象,包含了redis,mysql,webappwebapp其實就是我們的應用。
  2. "6389:6379"6389其實是我們主機的埠,也就是我的Mac連線redis容器需要使用6389,而容器之間連線需要使用6379,這是容器的埠。
  3. /tmp/redis.conf:/etc/redis/redis.conf/tmp/redis.conf是主機的目錄,而這個目錄需要在docker裡面配置才可以,要不就會報錯(執行記得加管理員許可權):

    docker ERROR: * start service *: Mounts denied

    image-20211128220527229

  4. mysql 8.0 可能會報錯java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed,這個是因為url連結少了一個引數:allowPublicKeyRetrieval=true

啟動可能出現的坑點

啟動後可能連結不上mysql或者redis,但是看容器執行情況又是正常的:

DockerCompose % docker container ps
CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS         PORTS                                                  NAMES
32fd6ce598ba   aphysia/dockerdemo   "java -jar /app.jar"     7 minutes ago    Up 7 minutes   0.0.0.0:8081->8081/tcp, :::8081->8081/tcp              dockerdemo
585b9b6bd71d   redis:latest         "docker-entrypoint.s…"   10 minutes ago   Up 7 minutes   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp              dockercompose_redis_1
d96ba57941d9   mysql:latest         "docker-entrypoint.s…"   16 minutes ago   Up 7 minutes   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   dockercompose_mysql_1

執行docker-compose up 沒有報錯,請求的時候報錯:

 io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:6379

這是因為容器之間的請求不能用127.0.0.1,必須用mysql,redis代表容器的網路,比如:jdbc:mysql://mysql:3306/test?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true

完整的application.yml:

server:
  port: 8081
spring:
  #資料庫連線配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://mysql:3306/test?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 123456
  redis:
    host: redis     ## redis所在的伺服器IP
    port: 6379
    ##密碼,我這裡沒有設定,所以不填
    password:
    ## 設定最大連線數,0為無限
    pool:
      max-active: 8
      min-idle: 0
      max-idle: 8
      max-wait: -1
#mybatis的相關配置
mybatis:
  #mapper配置檔案
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.aphysia.springdocker.model
  #開啟駝峰命名
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    root: debug

還有一個問題,就是docker-compose.yml裡面配置的映象名字一定要對,要不docker-compose up執行的時候,就會出現:

Pulling xxxx...
ERROR: The image for the service you're trying to recreate has been removed. If you continue, volume data could be lost. Consider backing up your data before continuing.

Continue with the new image? [yN]y
Pulling xxxx...
ERROR: pull access denied for postgresql, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

我還以為是登入的原因,本來是本地映象,應該直接create而不是pull,如果不知道名字,可以透過以下命令檢視,REPOSITORY就是名字:

DockerCompose % docker images
REPOSITORY           TAG            IMAGE ID       CREATED             SIZE
aphysia/dockerdemo   latest         1429aa26790a   54 minutes ago      137MB
<none>               <none>         ceb493583d7c   57 minutes ago      137MB
<none>               <none>         dffcc47602a2   About an hour ago   137MB
<none>               <none>         a695cf2cd2df   About an hour ago   137MB
<none>               <none>         209ce4f96d34   2 hours ago         137MB
redis                latest         40c68ed3a4d2   10 days ago         113MB
mysql                latest         e1d7dc9731da   14 months ago       544MB
openjdk              8-jdk-alpine   a3562aa0b991   2 years ago         105MB

最後啟動命令:

sudo docker-compose up

成功啟動:

image-20211128221753624

啟動之後記得初始化一下資料庫資料表!!!

drop database IF EXISTS test;
CREATE DATABASE test;
use test;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT "",
  `age` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES (1, '李四', 11);
INSERT INTO `user` VALUES (2, '王五', 11);

image-20211128223429280

至此,大功告成,看似簡單的命令,其實還是有不少坑點。

【作者簡介】
秦懷,公眾號【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。個人寫作方向:Java原始碼解析JDBCMybatisSpringredis分散式劍指OfferLeetCode等,認真寫好每一篇文章,不喜歡標題黨,不喜歡花裡胡哨,大多寫系列文章,不能保證我寫的都完全正確,但是我保證所寫的均經過實踐或者查詢資料。遺漏或者錯誤之處,還望指正。

劍指Offer全部題解PDF

2020年我寫了什麼?

開源程式設計筆記

相關文章