# 4. 项目部署 \> 摘录自:https://b11et3un53m.feishu.cn/wiki/MWQIw4Zvhil0I5ktPHwcoqZdnec 好了,我们已经熟悉了Docker的基本用法,接下来可以尝试部署项目了。 在课前资料中已经提供了一个黑马商城项目给大家,如图: 项目说明: - hmall:商城的后端代码 - hmall-portal:商城用户端的前端代码 - hmall-admin:商城管理端的前端代码 部署的容器及端口说明: \| \*\*项目\*\* \| \*\*容器名\*\* \| \*\*端口\*\* \| \*\*备注\*\* \| \| :----------- \| :--------- \| :----------------- \| :------------------ \| \| hmall \| hmall \| 8080 \| 黑马商城后端API入口 \| \| hmall-portal \| nginx \| 18080 \| 黑马商城用户端入口 \| \| hmall-admin \| 18081 \| 黑马商城管理端入口 \| \| \| mysql \| mysql \| 3306 \| 数据库 \| 在正式部署前,我们先删除之前的nginx、dd两个容器: \`\`\`Bash docker rm -f nginx dd \`\`\` ## 1.部署Java项目 \`hmall\`项目是一个maven聚合项目,使用IDEA打开\`hmall\`项目,查看项目结构如图: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=Mjc4MjMzYzZhMGQwNmI3MGZiNzZlNDdjMzM1MWNiODlfUHhJdWpSWTV1OHNCbWI1aUVFS0I1ZEQwUjBRdEQ5clZfVG9rZW46VjdNeWJ1YUhpb2pMT1d4c2xnSGNvS0xVbjVnXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 我们要部署的就是其中的\`hm-service\`,其中的配置文件采用了多环境的方式: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=MGEyMTE5M2Q3YTZiNWY2ZmEwZGFlMDdlYmNmNWY2MDZfbW40VUJyMXV5eTZGUkg2azQ0Q3JKQlF2RzdpZEJyT1BfVG9rZW46Vk5UOGIzNUZQb0xUUkR4VVZDQ2NuYWpJbnFnXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 其中的\`application-dev.yaml\`是部署到开发环境的配置,\`application-local.yaml\`是本地运行时的配置。 查看application.yaml,你会发现其中的JDBC地址并未写死,而是读取变量: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=NTZiZjFjZWU5NmIyMzUzMWQ2ZWFhYjgyMDZjYjNiMGVfbnlhMU4wU2JSRXZlRXlpcXc0TFhMNVZNbmczN3BTMk1fVG9rZW46SXlCZ2JFYWFjb1VmTml4RXlGMWM1anJGbnZiXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 这两个变量在\`application-dev.yaml\`和\`application-local.yaml\`中并不相同: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=NjZhZjBhZTU1OGJiYzRlMDY0Y2YyODU1NGZkZjMzY2RfVEczVFZRY0RaQUNhMDdnUFg3eHd1RjlyZ1M2czVJaUtfVG9rZW46T3RlaGJCQXpXb3FibUx4YTFHM2NIUjBablplXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 在dev开发环境(也就是Docker部署时)采用了mysql作为地址,刚好是我们的mysql容器名,只要两者在一个网络,就一定能互相访问。 我们将项目打包: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=YWQ4YjU3MzQzZTE5ZTc4MGUwYjJlZGRlODY3NzFjZWVfMTBNb21UYVdueVBzR1pYUVd6ZkxXbUtUT1hlN2tNMEFfVG9rZW46THhtS2JLRlFTb2EyTFB4bHpzcGNCVnlsbmVkXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 结果: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=ODMwZDFiOGM2NjMyOWE0NTJiYjQ5NjAyYzUzZGNiODhfWTg2RnI1WEp1YlQybEl3ekpZZEdWdmdKWFk1aE1sWFlfVG9rZW46QVhCRmJZWEJCb0FVcXN4cDBRRWNUckh5bllnXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 将\`hm-service\`目录下的\`Dockerfile\`和\`hm-service/target\`目录下的\`hm-service.jar\`一起上传到虚拟机的\`root\`目录: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=NjFhZDZlMTMyODJlYmQwNWZjNzQ1N2JiZWUwYjlkYmZfckR3M094akJ3N25ETXBLbk9TNXJwSlo0YUVzVE9CUnhfVG9rZW46UGNnTGIzMWZBbzRxb254aTJ3SmNJaTZwbkVjXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 部署项目: \`\`\`Bash # 1.构建项目镜像,不指定tag,则默认为latest docker build -t hmall . # 2.查看镜像 docker images # 结果 REPOSITORY TAG IMAGE ID CREATED SIZE hmall latest 0bb07b2c34b9 43 seconds ago 362MB docker-demo 1.0 49743484da68 24 hours ago 327MB nginx latest 605c77e624dd 16 months ago 141MB mysql latest 3218b38490ce 17 months ago 516MB # 3.创建并运行容器,并通过--network将其加入hmall网络,这样才能通过容器名访问mysql docker run -d --name hmall --network hmall -p 8080:8080 hmall \`\`\` 测试,通过浏览器访问:http://你的虚拟机地址:8080/search/list ## 2.部署前端 \`hmall-portal\`和\`hmall-admin\`是前端代码,需要基于nginx部署。在课前资料中已经给大家提供了nginx的部署目录: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=ZjVlZTEzMDVmMjM3Yjk4NzUzN2MwZmIxNjc4MDM0ODRfNUpMWGxqZG91b3plTnloajBNbDFCY1dRT1R6b3dDQldfVG9rZW46WFRuUGJ5T0RabzdDOER4TXI5Y2N3Qkdnbk9oXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 其中: - \`html\`是静态资源目录,我们需要把\`hmall-portal\`以及\`hmall-admin\`都复制进去 - \`nginx.conf\`是nginx的配置文件,主要是完成对\`html\`下的两个静态资源目录做代理 我们现在要做的就是把整个nginx目录上传到虚拟机的\`/root\`目录下: !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDlmY2M4M2ZjZjA5ZjMxYjIxZWNkY2Q5OWViNzgzZGRfVnVrUm9YS3R0OUs5TGs1UHRIaEoxZHRIV0VWTFZEN2lfVG9rZW46V0dMbmJQSWtKb0hOc2x4NnRuRGN0QXZLbnBmXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) 然后创建nginx容器并完成两个挂载: - 把\`/root/nginx/nginx.conf\`挂载到\`/etc/nginx/nginx.conf\` - 把\`/root/nginx/html\`挂载到\`/usr/share/nginx/html\` 由于需要让nginx同时代理hmall-portal和hmall-admin两套前端资源,因此我们需要暴露两个端口: - 18080:对应hmall-portal - 18081:对应hmall-admin 命令如下: \`\`\`Bash docker run -d \\ --name nginx \\ -p 18080:18080 \\ -p 18081:18081 \\ -v /root/nginx/html:/usr/share/nginx/html \\ -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \\ --network hmall \\ nginx \`\`\` 测试,通过浏览器访问:http://你的虚拟机ip:18080 !\[img\](https://b11et3un53m.feishu.cn/space/api/box/stream/download/asynccode/?code=MzY2MjU0MWI3ZWFjNzdhODg4NDMwZTQxZTBlOGU2ZmRfRlVWaWdLV0FCbW0yTXNsQUlXcmhlMXdXZzhzNkRJRjlfVG9rZW46VG5tU2JlZEZnb2o0SzJ4VVI0UmNma0libm9mXzE3MTAyNDk4Njc6MTcxMDI1MzQ2N19WNA) ## 3.DockerCompose 大家可以看到,我们部署一个简单的java项目,其中包含3个容器: - MySQL - Nginx - Java项目 而稍微复杂的项目,其中还会有各种各样的其它中间件,需要部署的东西远不止3个。如果还像之前那样手动的逐一部署,就太麻烦了。 而Docker Compose就可以帮助我们实现\*\*多个相互关联的Docker容器的快速部署\*\*。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。 ### 3.1.基本语法 docker-compose.yml文件的基本语法可以参考官方文档: https://docs.docker.com/compose/compose-file/compose-file-v3/ docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务(service)。由于service就是在定义某个应用的运行时参数,因此与\`docker run\`参数非常相似。 举例来说,用docker run部署MySQL的命令如下: \`\`\`Bash docker run -d \\ --name mysql \\ -p 3306:3306 \\ -e TZ=Asia/Shanghai \\ -e MYSQL_ROOT_PASSWORD=123 \\ -v ./mysql/data:/var/lib/mysql \\ -v ./mysql/conf:/etc/mysql/conf.d \\ -v ./mysql/init:/docker-entrypoint-initdb.d \\ --network hmall mysql \`\`\` 如果用\`docker-compose.yml\`文件来定义,就是这样: \`\`\`YAML version: "3.8" services: mysql: image: mysql container_name: mysql ports: - "3306:3306" environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: 123 volumes: - "./mysql/conf:/etc/mysql/conf.d" - "./mysql/data:/var/lib/mysql" networks: - new networks: new: name: hmall \`\`\` 对比如下: \| \*\*docker run 参数\*\* \| \*\*docker compose 指令\*\* \| \*\*说明\*\* \| \| :------------------ \| :---------------------- \| :--------- \| \| --name \| container_name \| 容器名称 \| \| -p \| ports \| 端口映射 \| \| -e \| environment \| 环境变量 \| \| -v \| volumes \| 数据卷配置 \| \| --network \| networks \| 网络 \| 明白了其中的对应关系,相信编写\`docker-compose\`文件应该难不倒大家。 黑马商城部署文件: \`\`\`YAML version: "3.8" services: mysql: image: mysql container_name: mysql ports: - "3306:3306" environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: 123 volumes: - "./mysql/conf:/etc/mysql/conf.d" - "./mysql/data:/var/lib/mysql" - "./mysql/init:/docker-entrypoint-initdb.d" networks: - hm-net hmall: build: context: . dockerfile: Dockerfile container_name: hmall ports: - "8080:8080" networks: - hm-net depends_on: - mysql nginx: image: nginx container_name: nginx ports: - "18080:18080" - "18081:18081" volumes: - "./nginx/nginx.conf:/etc/nginx/nginx.conf" - "./nginx/html:/usr/share/nginx/html" depends_on: - hmall networks: - hm-net networks: hm-net: name: hmall \`\`\` ### 3.2.基础命令 编写好docker-compose.yml文件,就可以部署项目了。常见的命令: https://docs.docker.com/compose/reference/ 基本语法如下: \`\`\`Bash docker compose \[OPTIONS\] \[COMMAND\] \`\`\` 其中,OPTIONS和COMMAND都是可选参数,比较常见的有: \| \*\*类型\*\* \| \*\*参数或指令\*\* \| \*\*说明\*\* \| \| :------- \| :----------------------------------------------------------- \| :-------------------------- \| \| Options \| -f \| 指定compose文件的路径和名称 \| \| -p \| 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 \| \| \| Commands \| up \| 创建并启动所有service容器 \| \| down \| 停止并移除所有容器、网络 \| \| \| ps \| 列出所有启动的容器 \| \| \| logs \| 查看指定容器的日志 \| \| \| stop \| 停止容器 \| \| \| start \| 启动容器 \| \| \| restart \| 重启容器 \| \| \| top \| 查看运行的进程 \| \| \| exec \| 在指定的运行中容器中执行命令 \| \| 教学演示: \`\`\`Bash # 1.进入root目录 cd /root # 2.删除旧容器 docker rm -f $(docker ps -qa) # 3.删除hmall镜像 docker rmi hmall # 4.清空MySQL数据 rm -rf mysql/data # 5.启动所有, -d 参数是后台启动 docker compose up -d # 结果: \[+\] Building 15.5s (8/8) FINISHED =\> \[internal\] load build definition from Dockerfile 0.0s =\> =\> transferring dockerfile: 358B 0.0s =\> \[internal\] load .dockerignore 0.0s =\> =\> transferring context: 2B 0.0s =\> \[internal\] load metadata for docker.io/library/openjdk:11.0-jre-buster 15.4s =\> \[1/3\] FROM docker.io/library/openjdk:11.0-jre-buster@sha256:3546a17e6fb4ff4fa681c3 0.0s =\> \[internal\] load build context 0.0s =\> =\> transferring context: 98B 0.0s =\> CACHED \[2/3\] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&\& echo 0.0s =\> CACHED \[3/3\] COPY hm-service.jar /app.jar 0.0s =\> exporting to image 0.0s =\> =\> exporting layers 0.0s =\> =\> writing image sha256:32eebee16acde22550232f2eb80c69d2ce813ed099640e4cfed2193f71 0.0s =\> =\> naming to docker.io/library/root-hmall 0.0s \[+\] Running 4/4 ✔ Network hmall Created 0.2s ✔ Container mysql Started 0.5s ✔ Container hmall Started 0.9s ✔ Container nginx Started 1.5s # 6.查看镜像 docker compose images # 结果 CONTAINER REPOSITORY TAG IMAGE ID SIZE hmall root-hmall latest 32eebee16acd 362MB mysql mysql latest 3218b38490ce 516MB nginx nginx latest 605c77e624dd 141MB # 7.查看容器 docker compose ps # 结果 NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS hmall root-hmall "java -jar /app.jar" hmall 54 seconds ago Up 52 seconds 0.0.0.0:8080-\>8080/tcp, :::8080-\>8080/tcp mysql mysql "docker-entrypoint.s..." mysql 54 seconds ago Up 53 seconds 0.0.0.0:3306-\>3306/tcp, :::3306-\>3306/tcp, 33060/tcp nginx nginx "/docker-entrypoint...." nginx 54 seconds ago Up 52 seconds 80/tcp, 0.0.0.0:18080-18081-\>18080-18081/tcp, :::18080-18081-\>18080-18081/tcp \`\`\` 打开浏览器,访问:http://yourIp:8080