目前已经更新完《Java并发编程》,《Docker教程》和《JVM性能优化》,欢迎关注【后端精进之路】,轻松阅读全部文章。

Java并发编程:

Docker教程:

JVM性能优化:

上一篇文章介绍了docker镜像的制作与发布,本文主要介绍实际docker工程部署中经常用到的docker-compose工具,以及docker的网络配置和负载均衡。

Docker-compose介绍

实际开发过程中,在一个项目中,我们常将不同的模块放在单独的docker中,方便维护和扩展。比如我们一个项目可能有MySQL镜像、Nginx镜像、Spring Boot后端镜像,我们在实际部署中可以采用上篇文章介绍的方法,分别打包,分别启动;但是这样太费精力,而且还容易出错。

因此Docker-compose工具应运而生,就是为了解决工程部署中的多个Docker镜像的管理问题。

docker-compose.yaml 文件

类似于build镜像需要Dockerfile一样,使用docker-compose时也需要类似的配置文件,叫做docker-compose.yaml。

下面是一个Docker-file的例子:

一般docker-compose文件中需要注意如下几点:

  • version: '3': 表示使用第三代语法,每代的语法稍有不同,我们选择最新的就好。
  • services: 表示compose需要启动的服务,一般一个docker镜像就可以作为一个单独的service。
  • container_name: 容器名称
  • environment: 容器环境变量,可以使用这个参数往容器传递一些变量,这个在我们切换不同环境配置时非常有用,不用每次去改变代码中的配置
  • ports: 对外开放的端口
  • restart: always表示如果服务启动不成功一直尝试。
  • volumes: 加载本地目录到容器目标路径,也就是将本地路径共享给容器,方便进行数据交互,也可以利用这个功能,将docker的log输出到本机指定的位置。
  • depends_on:依赖服务,先启动 depends_on 服务。
  • command: mvn clean spring-boot:run : 表示以这个命令来启动项目

上面提到了depends_on,通常用于需要顺序启动不同镜像,比如后台需要等待数据库初始化完毕以后才启动,但是这个depends_on并不能保证前序容器完全初始化,意思是只要前序容器启动了,就会尝试启动当前容器。这样还是会造成前序容器未初始化完成,后续容器启动后出现连接失败等错误。

因此最好的方式是官方(https://docs.docker.com/compose/startup-order/)比较推荐的wait脚本,脚本的详细使用可以看这里 https://github.com/vishnubob/wait-for-it,

wait-for-it.sh host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes

一般也可以在制作镜像的时候指定等待一定时间,在下面的例子中,在运行test.jar之前,会一直等到elasticsearch初始化完成。

FROM openjdk:8
ADD ["target/test-1.0.0.jar", "test.jar"]
ADD ["wait-for-it.sh", "wait-for-it.sh"]
RUN ["chmod", "+x", "wait-for-it.sh"]
EXPOSE 1234
ENTRYPOINT ["./wait-for-it.sh", "elastic:9200", "--", "java", "-jar", "/test.jar"]

关于更多docker-compose文件的详细介绍,可以参考官方的文档 https://docs.docker.com/compose/gettingstarted/。

docker-compose的启动/停止

docker-compose的启动与停止非常简单,直接使用docker-compose up启动,docker-compose down关闭工程,同时会删除所有容器。

Docker的网络通信

docker的网络方面是相对较弱的,新手如果不清楚,经常会出现为什么容器A访问不到容器B的问题。

容器间的通信

有个很常见的场景,我们需要在本机同时调试前端和后端程序,通常我们会在localhost某个端口启动前端,比如8080;同时在local的另一端口比如1234启动后端。如果不用容器,前端直接在代码里访问localhost:1234的所有接口都是可以的,没有任何问题。

但是如果前端和后端都封装在不同的容器中,这个时候前端直接访问localhost:1234,会报错,无法访问。原因就是两个容器之间是独立的,无法直接localhost访问。

官方推荐的解决办法就是,先新建一个网络,然后启动前后端容器的时候,分别指定在该网络中运行。

docker network create mynet
docker run --network mynet --name frontend ...
docker run --network mynet --name backend ...

现在前端就可以通过 http://backend:1234 访问后端的接口了。

注意:有些博客指出,可以通过docker inspect [container_name]来获取后端容器的ip,然后直接访问ip加端口就可以了。这个在Linux上也许可行,但是mac下由于容器的实现原理不同,无法直接通过ip访问。

docker-compose下的网络环境

默认情况下,当你利用docker-compose启动多个容器时,docker-compose会自动帮你创建一个网络,并将多个service在这个网络中运行。因此不同容器之间,直接利用容器名+端口就可以访问了。

Docker-compose实现负载均衡

实际生产环境中,肯定会启动多个后端service,同时进行负载均衡以保证服务质量。利用docker-compose我们可以方便的实现这种功能。

下面是一个很简单的docker-compose文件,启动之后可以在本地打开localhost:5000,来访问后端的service;在front容器内部,我们也可以通过backend:5000来访问backend service。

version: "3"

services:
front:
image: front:latest
backend:
image: "backend:latest"
ports:
- "5000:5000"

为了启动多个后端程序以实现负载均衡,docker-compose已经为我们提供--scale参数,利用这个参数可以轻松实现同时启动多个service。

下面是该参数的使用说明。

--scale SERVICE=NUM        Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.

在这里,我们直接在启动的时候,指定生成3个后端的service,

docker-compose up --scale backend=3

但是这样会报错,因为本机上的5000端口,只能分配给一个service,如果你想同时在本机上调试,可以将上面的ports改为5000,修改后的docker-compose文件如下:

version: "3"

services:
front:
image: front:latest
backend:
image: "backend:latest"
ports:
- "5000"

这样按照上面同样的指令启动之后,你你可以看到如下的输出结果,有3个不同的本机端口绑定到容器的5000端口,

      Name                      Command                  State                Ports
--------------------------------------------------------------------------------------------
example_backend_1 /usr/bin/dumb-init -- /sbi ... Up (healthy) 0.0.0.0:32776->5000/tcp
example_backend_2 /usr/bin/dumb-init -- /sbi ... Up (healthy) 0.0.0.0:32775->5000/tcp
example_backend_3 /usr/bin/dumb-init -- /sbi ... Up (healthy) 0.0.0.0:32777->5000/tcp

当然,如果你只想从容器内部访问后端的5000端口,你可以去掉port配置,改成如下的配置:

version: "3"

services:
front:
image: front:latest
backend:
image: "backend:latest"

这样docker-compose up --scale backend=3启动后,我们就只能在容器内部访问http:\\backend:5000来访问后端service,因为我们启动了三个,前端的请求会随机的分配到后端的三个service上,保证了整体的服务质量。

参考链接:


本文由『后端精进之路』原创,首发于博客 http://teckee.github.io/ , 转载请注明出处

搜索『后端精进之路』关注公众号,立刻获取最新文章和价值2000元的BATJ精品面试课程

Docker系列-(3) Docker-compose使用与负载均衡的更多相关文章

  1. Docker系列(十三):Kubernetes Service的负载均衡和网络路由的秘密

    Kubernetes Service设计分析 什么是单体程序?所有的模块都在一个进程中 微服务,每一个服务是一个进程的模式 kubernetes中的service其实只是一个概念,是一组相同lable ...

  2. Docker系列03—Docker 基础入门

    本文收录在容器技术学习系列文章总目录 1.概念介绍 1.1 容器 1.1.1 介绍 容纳其它物品的工具,可以部分或完全封闭,被用于容纳.储存.运输物品.物体可以被放置在容器中,而容器则可以保护内容物. ...

  3. Docker系列05—Docker 存储卷详解

    本文收录在容器技术学习系列文章总目录 1.存储卷介绍 1.1 背景 (1)docker 的 AFUS 分层文件系统 docker镜像由多个只读层叠加面成,启动容器时,docker会加载只读镜像层并在镜 ...

  4. 使用Docker快速创建.Net Core2.0 Nginx负载均衡节点

    本文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws 一.Self-Host Kestrel 1. 在vs2017中新建dotnet core2. ...

  5. Docker系列之Docker镜像(读书笔记)

    一.基本概念 Docker包括三个基本概念镜像.容器.仓库. Docker镜像:就是一个只读的模板.例如:一个镜像可以包含一个完整的ubuntu操作系统环境,里面仅安装了Apache或其他应用程序.用 ...

  6. docker 系列之 docker安装

    Docker支持以下的CentOS版本 CentOS 7 (64-bit) CentOS 6.5 (64-bit) 或更高的版本 前提条件 目前,CentOS 仅发行版本中的内核支持 Docker. ...

  7. Docker系列二: docker常用命令总结

    https://docs.docker.com/reference/  官方命令总结地址 容器生命周期管理 1.docker run 创建一个新的容器并运行一个命令 docker run [optio ...

  8. Docker系列一: docker简介及基本环境安装

    Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Li ...

  9. Docker系列03—Docker 存储卷

    一.存储卷介绍 1.1 背景 Docker 的 AFUS 分层文件系统 docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在镜像栈顶部加一个读写层: 如果运行的容器修改了 ...

  10. Docker系列01—Docker 基础入门

    一.初识Docker和容器 1.1 什么是docker 容纳其他物品的工具,可以部分或完全封闭,被用于容纳.存储.运输物品.物体可以被放置在容器中,而容器则可以保护内容物. 容器? 容器就是在隔离的环 ...

随机推荐

  1. MySQL每个分类的前几条记录

    MySQL 获取所有分类和每个分类的前几条记录 比如有文章表 Article(Id,Category,InsertDate) 现在要用SQL找出每种类型中时间最新的前N个数据组成的集合 SELECT ...

  2. 不止面试—jvm类加载面试题详解

    面试题 带着问题学习是最高效的,本次我们将尝试回答以下问题: 什么是类的加载? 哪些情况会触发类的加载? 讲一下JVM加载一个类的过程 什么时候会为变量分配内存? JVM的类加载机制是什么? 双亲委派 ...

  3. JenKins结合cppcheck及cpplint进行代码风格及静态代码检测

    JenKins结合cppcheck及cpplint 最近公司需要在Jenkins上安装cppcheck及cpplint进行代码风格及静态代码检测,这里记录下过程. 前提条件 安装了Jenkins 步骤 ...

  4. SQL的四种连接(左外连接、右外连接、内连接、全连接)

    1.内联接(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接.     内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行.例如,检索 stude ...

  5. 2018年航空概论课后作业(PS:部分答案不正确, 综合得分:83.6)

    1 [单选题]航空是指载人或不载人的飞行器在地球____的航行活动. • A.高空• B.大气层内• C.宇宙• D.大气层外我的答案:B 得分: 33.3分 2 [多选题]军用飞机可分为____两大 ...

  6. 领扣(LeetCode)删除链表中的节点 个人题解

    请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点. 现有一个链表 -- head = [4,5,1,9],它可以表示为: 4 -> 5 -> 1 - ...

  7. django_2:模板

    使用模板变量: 在html文件中,{{title}}即为模板变量, 在view.py文件中,render函数,增加第三个参数,以字典形式给值. def index(req): return rende ...

  8. 神奇的 SQL 之 MySQL 性能分析神器 → EXPLAIN,SQL 起飞的基石!

    前言 开心一刻 某人养了一头猪,烦了想放生,可是猪认识回家的路,放生几次它都自己回来了.一日,这个人想了个狠办法,开车带着猪转了好多路进山区放生,放生后又各种打转,然后掏出电话给家里人打了个电话,问道 ...

  9. ES6的基础知识(一)

    1.ECMAScript 6.0(以下简称ES6). 2.ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的其中一种实现. 3.对ES6支持的浏览器:超过 90% ...

  10. 记一个vue-resource请求的低级错误

    对于初学的小菜鸡,经常会犯一些低级错误. 现在记录一下我在使用vue-resource发送post请求时的一个低级错误: window.BaseURL = '127.0.0.1:8888'; 8888 ...