目录
a)技术选型:SpringCloud 2021.0.1 、SpringCloud Alibaba 2021.0.1.0、SpringBoot 2.6.3、Docker & DockerCompose、JDK 17.
b)软件环境:MySQL、Nacos.
c)服务拆分:blog、user、gateway.
d)其他模块:common(公共模块)、OpenFeign.
e)父项目 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>
<groupId>com.cyk</groupId>
<artifactId>cloud_blog</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>user</module>
<module>blog</module>
<module>openfeign</module>
<module>common</module>
<module>gateway</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>17</java.version>
<mybatis-spring-boot.version>2.3.1</mybatis-spring-boot.version>
<mysql.version>5.1.49</mysql.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
</properties>
<!--维护依赖-->
<dependencyManagement>
<dependencies>
<!-- spring-cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring-cloud-alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--spring-boot-test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-test-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>${mybatis-spring-boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Ps:麻雀虽小,五脏俱全~? ?如果还有其他中间件(RabbitMQ、ES......)需要部署,如果人不是小傻瓜,都能配出来~
a)当我们把项目部署到云服务上之后,数据库可能是空的,因此强烈建议提前编写好 SQL 文件,之后就可以通过 docker-compose.yml 的?volumes 映射 docker 的 mysql 初始化脚本文件,完成初始化操作.
b)db.sql 文件如下
create database if not exists demo;
use demo;
drop table if exists user;
create table user (
id bigint primary key auto_increment comment '自增主键id',
username varchar(20) not null unique comment '用户名',
password varchar(20) not null comment '密码',
create_time datetime default now() comment '创建时间',
update_time datetime default now() comment '修改时间'
);
drop table if exists blog;
create table blog (
id bigint primary key auto_increment comment '自增主键',
userId bigint not null comment '用户id',
title varchar(32) not null comment '标题',
content varchar(256) not null comment '正文',
read_count bigint default 0 comment '阅读量',
create_time datetime default now() comment '创建时间',
update_time datetime default now() comment '修改时间'
);
insert into user(username, password) values('cyk', '1111');
insert into blog(userId ,title, content) values(1, '今天真开心', '今天真开行啊,我要好好学习,然后晚上出去玩!');
c)docker 根据别名创建目录默认在 /var/lib/docker/volumes/ 中,因此可以在此目录创建一个 mysql-init 文件夹(将来 docker-compose 文件需要挂载的宿主机数据卷),在将 db.sql 文件放入该文件夹中即可.
? mysql-init pwd
/var/lib/docker/volumes/mysql-init
? mysql-init ll
总用量 4.0K
-rw-r--r--. 1 root root 1.1K 1月 13 22:23 db.sql
? mysql-init cat db.sql
create database if not exists demo;
use demo;
drop table if exists user;
create table user (
id bigint primary key auto_increment comment '自增主键id',
username varchar(20) not null unique comment '用户名',
password varchar(20) not null comment '密码',
create_time datetime default now() comment '创建时间',
update_time datetime default now() comment '修改时间'
);
drop table if exists blog;
create table blog (
id bigint primary key auto_increment comment '自增主键',
userId bigint not null comment '用户id',
title varchar(32) not null comment '标题',
content varchar(256) not null comment '正文',
read_count bigint default 0 comment '阅读量',
create_time datetime default now() comment '创建时间',
update_time datetime default now() comment '修改时间'
);
insert into user(username, password) values('cyk', '1111');
insert into blog(userId ,title, content) values(1, '今天真开心', '今天真开行啊,我要好好学习,然后晚上出去玩!');
所有需要运行的微服务都需要有这个插件(父工程不需要任何插件),否则找不到程序入口,没法编译运行(如下图).
插件如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
强烈建议,先把需要运行的微服务的 jar 包,都在本地通过 java -jar 运行一下,检查是否能运行成功,这是一个好习惯~
a)user 微服务
FROM openjdk:17
# 指定容器工作目录为 apps
WORKDIR /apps
EXPOSE 9090
# 将宿主机上的 ./user-1.0-SNAPSHOT.jar 文件拷贝到容器的工作目录下,并改名为 user.jar
COPY ./user-1.0-SNAPSHOT.jar ./user.jar
# --spring.profiles.active=prod 表示按照 application-prod.yml 配置文件加载
ENTRYPOINT ["java", "-jar", "user.jar", "--spring.profiles.active=prod"]
b)blog 微服务
FROM openjdk:17
# 指定容器工作目录为 apps
WORKDIR /apps
# 将宿主机上的 ./blog-1.0-SNAPSHOT.jar 文件拷贝到容器的工作目录下,并改名为 blog.jar
COPY blog-1.0-SNAPSHOT.jar blog.jar
EXPOSE 9091
# --spring.profiles.active=prod 表示按照 application-prod.yml 配置文件加载
ENTRYPOINT ["java", "-jar", "/apps/blog.jar", "--spring.profiles.active=prod"]
c)gateway 微服务
FROM openjdk:17
# 指定容器工作目录为 apps
WORKDIR /apps
# 将宿主机上的 ./gateway-1.0-SNAPSHOT.jar 文件拷贝到容器的工作目录下,并改名为 gateway.jar
COPY ./gateway-1.0-SNAPSHOT.jar ./gateway.jar
EXPOSE 10010
# --spring.profiles.active=prod 表示按照 application-prod.yml 配置文件加载
ENTRYPOINT ["java", "-jar", "gateway.jar", "--spring.profiles.active=prod"]
a)强烈建议:学过 DockerCompose 的朋友可能都知道有个配置叫做 "depends_on",可以指定容器的启动顺序,但是并不能指定谁先启动完成!!!?是不稳定的!!!因此强烈建议编写两个 DockerCompose?文件,一个是 docker-compose.env.yml(运行必备环境),另一个是 docker-compose.service.yml(微服务),部署的时候只需要启动 env,完成后再启动 service 即可.
b)docker-compose.env.yml 文件如下:
version: "3"
networks:
blog_net:
volumes:
data:
init:
services:
nacos:
image: nacos/nacos-server:1.4.2
ports:
- "8848:8848"
environment:
- "MODE=standalone"
restart: always
networks:
- blog_net
mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
- "MYSQL_ROOT_PASSWORD=1111"
volumes:
- /root/cyk/cloud_blog/mysql/data:/var/lib/mysql # 映射数据,防止容器重启丢失数据
- /root/cyk/cloud_blog/mysql/init:/docker-entrypoint-initdb.d
restart: always
networks:
- blog_net
Ps:docker-retrypoint-initdb.d 是 Docker 官方 MySQL 镜像的目录,用于初始化数据库和表,因此通过映射我们配置好的初始化文件 mysql-init,就可以实现自定义初始化数据库和表.
如果需要执行多个脚本文件(sql 文件)来初始化数据库,可以使用以下方法:
- 将 sql 文件以数字开头命名,例如 001_create_table.sql、002_insert_data.sql.
- 数字小的优先执行.
c)docker-compose.service.yml 文件如下:
version: "3"
networks:
blog_net:
services:
gateway: # 网关
build:
context: ./gateway
dockerfile: Dockerfile
ports:
- "10010:10010"
networks:
- blog_net
blog: # 博客服务
build:
context: ./blog
dockerfile: Dockerfile
ports:
- "9091:9091"
networks:
- blog_net
user: # 用户服务
build:
context: ./user
dockerfile: Dockerfile
ports:
- "9090:9090"
networks:
- blog_net
a)强烈建议:提供两个配置文件,一个处理开发环境,另一个处理生产环境(线上环境). 这样本地测试和线上测试就不用老去修改配置文件,关键不小心还容易改错~
b)例如 user 微服务,当前项目需要修改的就是 nacos 和 mysql 连接地址,都修改为 docker-compose 文件中配置的服务Id 名称即可(前提是配置了 networks 在同一网络下):
开发环境如下
server:
port: 9090
spring:
application:
name: user-server
cloud:
nacos:
server-addr: localhost:8848
datasource:
url: jdbc:mysql://localhost:3306/demo?characterEncoding=utf8&useSSL=false
username: root
password: 1111
driver-class-name: com.mysql.jdbc.Driver
# 时间处理
jackson:
date-format: yyyy-MM-dd
time-zone: GMT+8
# mybatis xml save path
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
pattern:
dateformat: HH:mm:ss
level:
com:
cyk: debug
生产环境如下
server:
port: 9090
spring:
application:
name: user-server
cloud:
nacos:
server-addr: nacos:8848
datasource:
url: jdbc:mysql://mysql:3306/demo?characterEncoding=utf8&useSSL=false
username: root
password: 1111
driver-class-name: com.mysql.jdbc.Driver
# 时间处理
jackson:
date-format: yyyy-MM-dd
time-zone: GMT+8
# mybatis xml save path
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
pattern:
dateformat: HH:mm:ss
level:
com:
cyk: debug
a)强烈建议:打包前先 clean,避免一些不必要的缓存 class 干扰.
b)打包
b)上传时,建议按服务名称分包,因为每个 Dockerfile 构建成镜像时会把所有工作目录下的所有 Dockerfile 文件都加载一遍,因此不要都放一个目录下,而是分开放.
a)先启动 env 环境容器.
? cloud_blog docker-compose -f docker-compose.env.yml up -d
[+] Running 24/24
? mysql Pulled 57.7s
? 72a69066d2fe Pull complete 31.9s
? 93619dbc5b36 Pull complete 31.9s
? 99da31dd6142 Pull complete 32.1s
? 626033c43d70 Pull complete 32.2s
? 37d5d7efb64e Pull complete 32.2s
? ac563158d721 Pull complete 36.7s
? d2ba16033dad Pull complete 36.7s
? 0ceb82207cd7 Pull complete 36.7s
? 37f2405cae96 Pull complete 56.7s
? e2482e017e53 Pull complete 56.7s
? 70deed891d42 Pull complete 56.7s
? nacos Pulled 64.8s
? 5ad559c5ae16 Pull complete 23.7s
? aa9bf71274b4 Pull complete 23.7s
? 039d8b3d6a90 Pull complete 62.4s
? c96722e52477 Pull complete 62.8s
? 93185cc2628e Pull complete 63.6s
? 6ddaf1829637 Pull complete 63.8s
? af68d9507f36 Pull complete 63.9s
? 2684f86bd7ff Pull complete 63.9s
? b3c841104577 Pull complete 63.9s
? a0643cc92b59 Pull complete 63.9s
? a6a1256662e3 Pull complete 63.9s
[+] Running 5/5
? Network cloud_blog_blog_net Created 0.1s
? Volume "cloud_blog_mysqlData" Created 0.0s
? Volume "cloud_blog_mysql-init" Created 0.0s
? Container cloud_blog-mysql-1 Started 1.3s
? Container cloud_blog-nacos-1 Started 1.2s
b)启动 service 服务容器
? cloud_blog docker-compose -f docker-compose.service.yml up -d
[+] Building 44.8s (18/18) FINISHED
=> [cloud_blog_user internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [cloud_blog_blog internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [cloud_blog_gateway internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 511B 0.0s
=> [cloud_blog_gateway internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [cloud_blog_user internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 491B 0.0s
=> [cloud_blog_blog internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 499B 0.0s
=> [cloud_blog_blog internal] load metadata for docker.io/library/openjdk:17 16.3s
=> [cloud_blog_blog 1/3] FROM docker.io/library/openjdk:17@sha256:74bad65c9e59d6410bdd67d71a14e14175ddd33d654419ecfabf03ddbe70fff4 27.6s
=> => resolve docker.io/library/openjdk:17@sha256:74bad65c9e59d6410bdd67d71a14e14175ddd33d654419ecfabf03ddbe70fff4 0.0s
=> => sha256:74bad65c9e59d6410bdd67d71a14e14175ddd33d654419ecfabf03ddbe70fff4 1.29kB / 1.29kB 0.0s
=> => sha256:ab43cabb2140ecf2fc1b32b4981ead56960a59e5b64f742ad30ada7e47bb8870 954B / 954B 0.0s
=> => sha256:5f94f53bbced4225dbe770cd98834716ed540315bf131b38a648378c418a6012 4.45kB / 4.45kB 0.0s
=> => sha256:155aced2666332ddff5a741b0236f360820e7aa3fc3dde2224fc17a91fc48db6 42.11MB / 42.11MB 15.0s
=> => sha256:ac5901c58ecb29b61159b5e3a63dfbb0fb520b2de1d33c9fb038d9b697e3fcd4 13.52MB / 13.52MB 7.6s
=> => sha256:6b1076e441ffb58eee60f1bab40db6ca69a01e33346eff212eac1191e6b754bd 187.17MB / 187.17MB 23.7s
=> => extracting sha256:155aced2666332ddff5a741b0236f360820e7aa3fc3dde2224fc17a91fc48db6 2.4s
=> => extracting sha256:ac5901c58ecb29b61159b5e3a63dfbb0fb520b2de1d33c9fb038d9b697e3fcd4 0.6s
=> => extracting sha256:6b1076e441ffb58eee60f1bab40db6ca69a01e33346eff212eac1191e6b754bd 3.9s
=> [cloud_blog_gateway internal] load build context 1.0s
=> => transferring context: 37.22MB 1.0s
=> [cloud_blog_blog internal] load build context 1.1s
=> => transferring context: 42.58MB 1.1s
=> [cloud_blog_user internal] load build context 0.9s
=> => transferring context: 42.58MB 0.9s
=> [cloud_blog_gateway 2/3] WORKDIR /apps 0.2s
=> [cloud_blog_blog 3/3] COPY blog-1.0-SNAPSHOT.jar blog.jar 0.5s
=> [cloud_blog_gateway 3/3] COPY ./gateway-1.0-SNAPSHOT.jar ./gateway.jar 0.5s
=> [cloud_blog_user 3/3] COPY ./user-1.0-SNAPSHOT.jar ./user.jar 0.5s
=> [cloud_blog_user] exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:c339d5ec9b3dc9cb81d033b31eafab456e534527923f5df7c479e4e383d19c28 0.0s
=> => naming to docker.io/library/cloud_blog_user 0.0s
=> [cloud_blog_gateway] exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:b06ecc27be3690c5d345bd042143ca7d72cf1e55f165e46678f92ea2bc39914b 0.0s
=> => naming to docker.io/library/cloud_blog_gateway 0.0s
=> [cloud_blog_blog] exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:75d36043551d0200ab71694078530806f3b5846e03551f06042771597bb07179 0.0s
=> => naming to docker.io/library/cloud_blog_blog 0.0s
WARN[0044] Found orphan containers ([cloud_blog-nacos-1 cloud_blog-mysql-1]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
[+] Running 3/3
? Container cloud_blog-blog-1 Started 0.9s
? Container cloud_blog-user-1 Started 0.8s
? Container cloud_blog-gateway-1 Started 0.8s
? cloud_blog docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
af78c01da9fd cloud_blog_user "java -jar user.jar …" 50 seconds ago Up 48 seconds 0.0.0.0:9090->9090/tcp, :::9090->9090/tcp cloud_blog-user-1
9b1e12367d13 cloud_blog_gateway "java -jar gateway.j…" 50 seconds ago Up 48 seconds 0.0.0.0:10010->10010/tcp, :::10010->10010/tcp cloud_blog-gateway-1
74a33d6ecd62 cloud_blog_blog "java -jar /apps/blo…" 50 seconds ago Up 48 seconds 0.0.0.0:9091->9091/tcp, :::9091->9091/tcp cloud_blog-blog-1
32c9be5f7372 nacos/nacos-server:1.4.2 "bin/docker-startup.…" About a minute ago Up About a minute 0.0.0.0:8848->8848/tcp, :::8848->8848/tcp cloud_blog-nacos-1
74830ac95115 mysql:5.7 "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp cloud_blog-mysql-1
c)注意:如果在此过程中,操作失误了,例如上传了错误的 jar 包,并且还运行过了,但你知道他是错误的,接着你重新上传 jar 包.
此时!!!一定要执行一次 build 命令重新构建!!!否则执行的还是旧的 jar 包(docker 会把执行执行过的容器的镜像保存下载,下次执行会直接通过之前运行过的镜像来运行)
例如是 service 容器中的 jar 重新上传了,那么就执行以下指令重新构建,之后再运行即可.
docker-compose -f docker-compose.service.yml build
通过网关访问以下: