Docker部署java项目(Dockerfile方式)
原文链接:https://blog.csdn.net/IT_faquir/article/details/84977619
一、前言
Docker一个是一个应用容器引擎,帮助我们减少大量的运维成本,它可以:
- web应用的自动化打包和发布;
- 自动化测试和持续集成、发布;
- 在服务型环境中部署和调整数据库或其他的后台应用;
- 从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。思想:集装箱、标准化(运输方式、存储方式、API接口)、隔离
…
Docker的具体介绍就不在多说了,官网、百度百科等有非常多的介绍.
接下来我将从SpringCloud的服务部署带你走进Docker》》》
最终要达到的目的
搭建好Docker环境,准备好ServerA(服务层)、ServerB(客服端层)、EurekaServer(注册中)以及在Mysql、Mongodb、redis等等涉及到的应用
最终要实现的一个容器关系图(画的很搓,欢迎吐槽).
二、准备Docker
在进入正题之前先了解下几个名词:
- Docker服务端 和Docker客户端:其中docker服务端是一个服务进程,管理着所有的容器。docker客户端则扮演着docker服务端的远程控制器,可以用来控制docker的服务端进程。大部分情况下,docker服务端和客户端运行在一台机器上;
- Docker容器:可以理解为在沙盒中运行的进程。这个沙盒包含了该进程运行所必须的资源,包括文件系统、系统类库、shell 环境等等。但这个沙盒默认是不会运行任何程序的。你需要在沙盒中运行一个进程来启动某一个容器。这个进程是该容器的唯一进程,所以当该进程结束的时候,容器也会完全的停止;
- Docker镜像:相当于安装包,每一个应用程序都是在一个隔离的容器中运行,因此每一个应用程序当作一个容器;
- Docker仓库:存放镜像用。
安装Docker,菜鸟教程有详细的安装过程,涵盖了centos、macos、ubunte、window操作系统的安装过程,这里不细讲了,具体如下几条命令(centos7)。
#确保 yum 包更新到最新
sudo yum update
安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
设置yum源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装docker
sudo yum install docker-ce
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
需要注意一下系统环境(uname -r
)
docker环境要求:
- 需要Linux3.8以上内核;
- 64位CPU架构的计算机;
- 内核至少支持其中一种存储驱动:Device Manager(默认); AUFS; vfs; btrfs;
- 内核必须支持并开启cgroup和namespace功能
关于docker服务的一些命令:
- 启动docker: systemctl start docker
- 守护进程重启:sudo systemctl daemon-reload
- 重启docker服务:systemctl restart docker
- 重启docker服务: sudo service docker restart
- 关闭docker: service docker stop
- 关闭docker: systemctl stop docker
三、Docker安装Mysql、Redis、Mongo
1.安装Mysql
1.1 通过search搜索镜像:
语法: docker search [OPTIONS] TERM
搜索mysql镜像:
docker search mysql
- 1
通常第一个就是我们想要的镜像.
1.2 通过pull拉起镜像
找到了想要的镜像,那么可以通过pull将镜像下载到本地仓库
语法: docker pull [OPTIONS] NAME[:TAG|@DIGEST]
拉取mysql镜像:
docker pull mysql
- 1
等待下载完成即可,在没有指定版本号情况下,docker默认拉起docker远程仓库中版本最新的镜像.
1.3 通过images查看镜像
语法: docker images [OPTIONS] [REPOSITORY[:TAG]]
显示所有本地镜像:
docker images
- 1
可以看到本地所有已有的镜像,随着镜像越来越多,可以通过docker images mysql
来精确搜索本地是否有mysql镜像.
1.4 通过run启动镜像
语法: docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
其中有非常多的参数,可以通过docker run --help来查看具体参数说明
启动mysql镜像:
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=asd123asd --name mysql -d mysql
- 1
在执行完后,该镜像便在一个隔离的容器中执行,docker会为每一个容器分配一个ID,该ID作为唯一标志.
上面语法中-p
用来做端口映射,-e
用来做参数配置,--name
为容器其一个别名,-d
让应用在后台运行
1.5 通过ps查看docker中的进程
语法:docker ps [OPTIONS]
显示所有运行中的容器:
docker ps
- 1
当前显示的是正在运行中的容器,我们也可以通过在后面加一个-a参数查看所有容器
1.6 通过start/stop/restart来对容器进行启动、停止、重启
语法: docker start|stop|restart [OPTIONS] CONTAINER [CONTAINER…]
docker启动|停止|重启mysql容器:
docker start|stop|restart mysql (或者容器ID)
- 1
1.7 远程连接
启动好mysql容器,使用Navicate客服端连接刚才我们启动的mysql试试,如果是本地直接连接,如果是远程,请使用可访问服务器的IP进行访问。
连接的时候你会发现如下错误:
Authentication plugin ‘caching_sha2_password’ cannot be loaded: dlopen(/usr/local/mysql/lib/plugin/caching_sha2_password.so, 2): image not found
大概意思: 授权插件‘caching_sha2_password’不能被加载,也就是不能对身份验证.
MySQL8.0采用了新的更安全的验证方式,用客户端连接比如navicate,会提示客户端连接caching-sha2-password,是由于客户端不支持这种插件,可以通过如下方式进行修改:
首先我们可以在docker中通过以下命令进行连接
docker exec -it mysql mysql -uroot -pasd123asd
- 1
或者
先进入容器(每个容器相当于系统环境,你可要在上面使用linux的基础命令)
docker exec -ti xxx(容器id) /bin/bash
- 1
容器内,连接数据库
mysql -u root -pasd123asd
- 1
查看用户信息
select host,user,plugin,authentication_string from mysql.user;
- 1
备注:host为 % 表示不限制ip localhost表示本机使用 plugin非mysql_native_password 则需要修改密码
重新设置一下密码
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'asd123asd'
- 1
此时再重新连接就OK了
1.8 删库跑路
你想删库吗,你想跑路吗?那么可以使用rm
命令删除容器以及rmi
删除镜像
删除容器:
语法: docker rm [OPTIONS] CONTAINER [CONTAINER…]
在删除容器之前首先先停止运行的容器,否则会出现如下错误
Error response from daemon: You cannot remove a running container 77d983b1b76987b045ba96258f05865591db5c472772213c59ddff2f9597f3b7. Stop the container before attempting removal or force remove
删除mysql容器:
docker rm mysql(或容器ID)
- 1
删除镜像:
语法: docker rmi [OPTIONS] IMAGE [IMAGE…]
删除镜像也一样需要先删除相关的容器再删除镜像
删除mysql镜像:
docker rmi mysql(或镜像ID)
- 1
2.安装Redis/Mongo
具体不再细说了,基本上和Mysql安装过程差不多
两步搞定(redis):
docker pull redis
docker run -p 6379:6379 --name redis -d redis
两步搞定(mongo):
docker pull mongo
docker run -p 27017:27017 --name mongo -d mongo
四、将Jar包制作成镜像
第一部分讲述了镜像的搜索到最终在容器中运行镜像,通常镜像仓库中不会有我们自己开发应用,因此我们需要将运行的应用制作成镜像,再将其运行于容器中.
我们可以通过Dockerfile构建镜像,也可以手工制作Docker镜像,但过于烦锁,效率低,这里不再赘述.
1.Dockerfile
在开始制作镜像之前需要先了解一下Dockerfile文件.
Dockerfile
是一个对镜像进行描述的文本文件,其内容包含四个部分: 基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令.
简单的说就是告诉Docker,在制作镜像过程中需要怎么做,比如需要java环境,需要制作的应用在哪,应用的启动命令是怎样的等等信息。
一些Dockerfile的部分指令:
基础镜像信息: FROM
维护者信息:MAINTAINER
镜像操作指令: RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME等
容器启动时执行指令:CMD、ENTRYPOINT
具体内容详见官方文档:https://docs.docker.com/engine/reference/builder/
2.为Eureka_server编写Dockerfile文件
准备好要制作成镜像的应用,这里以本人在项目开发过程中的一个Eureka服务为例子,应用包名为:eureka_server.jar
创建一个Dockerfile(touch Dockerfile)文件与eureka_server.jar放在同一个文件夹下,如下所示:
编辑Dockerfile(vim Dockerfile)
FROM java:alpine
ADD eureka_server.jar eureka_server.jar
EXPOSE 9990
ENTRYPOINT ["java","-jar","/eureka_server.jar","--spring.profiles.active=prod"]
- 1
- 2
- 3
- 4
大概描述了这样一件事:以java:alpine
为镜像基础,将eureka_server.jar文件复制到容器中的eureka_server.jar文件,并在容器内部使用端口9990
运行程序,并在容器启动时以java -jar /eureka_server.jar --spring.profiles.active=prod
的命令启动应用.
这简短的语法,可以很好的描述该镜像.
3.通过build命令制作镜像
语法: docker build [OPTIONS] PATH | URL | -
eureka应用制作成镜像:
docker build -t eureka .
- 1
-t
给镜像命名为eureka,.
代表将当前目录下所有文件构建到镜像中.
我们通过images查看下制作好的镜像,并运行看看.
docker run -p 9990:9990 --name eureka eureka
- 1
上面启动命令没有-d
命令意味着你会在控制台中看到eureka服务的启动过程,和我们在Idea中打印的启动日志一致.等待启动完成即可.
看看效果http://xxxx:9990 看到如下eureka的页面,意味着大功告成.
五、解决容器之间通信问题
以同样的方式,我们启动了ServerA和ServerB. 你会发现如一些问题
问题一: 注册中心中没有看到ServerA和ServerB
问题二: 注册中心都有ServerA和ServerB,可就是调不通
问题三: 互相之间都调通了,可数据库有连不上了.
等等问题,其实这些问题都归结于容器间通信问题,要知道docker中容器之间是相互隔离的
接下来给出一些解决方案和一些注意点.
当你的服务配置eureka使用本地的ip时,虽然注册中心注册成功了,却无法两个应用正常通信.
将会出现Caused by: java.net.UnknownHostException: 0b1659dd7e1d 异常.
解决办法:
使用--link
来连接两个容器
下面以上层服务lsgclient(ServerB)和下层服务lsgbase(ServerA)为例子.
首先我们将作为eureka客服端的lsgclient和lsgbase的yaml配置
文件中eureka的地址进行修改
eureka:
client:
serviceUrl:
defaultZone: http://eureka-server:9990/eureka/
- 1
- 2
- 3
- 4
其中eureka-server为的eureka服务容器名.
启动lsgbase服务(该服务需要连接redis、mariadb、eureka-server),那么可以通过–link连接其它容器
启动服务:
docker run --name lsgbase -p 8010:8010 -p 8888:8888 --link redis --link mariadb:mysql --link eureka-server lsgbase
- 1
看日志打印是否成功
Eureka是否注册成功
紧接着我们打开另一个窗口,或者上面在启动是加个-d 参数进行后台启动.
启动lsgclient服务(该服务需要连接lsgbase、eureka-server)
docker run --name lsgclient -p 80:80 -p 8889:8889 --link redis --link eureka-server --link lsgbase -d lsgclient
- 1
看日志打印是否成功
再看下Eureka看看情况,最后访问下服务,一切ok并且日志不要没有出现UnknownHostException异常,好得很。
注意:这里除了需要link eureka-server外,还需要link lsgbase否则依然报UnknownHostException错误.
好了基本上大功告成了.
六、痛点总结
对以上部署过程的痛点整理:
痛点1:当项目有所改动,每次都要打包上传、还得构建镜像,真是太麻烦了.
痛点2: 在运行进行时如果你的client层所连接的服务有几十个其它服务,那得一个一个link过去吧,那太痛苦了
针对以上痛点,将在下篇文章进行分享