Docker 学习教程【面试+工作】
我们之前是如何将项目发布到Linux服务器的?
大致步骤如下:
1、 安装jdk
2、 安装tomcat
3、 将项目war包上传到tomcat的webapps下
4、 修改配置文件
5、 启动tomcat
这样看似没问题,其实我们想想,发一台机器还好,这几步就完成了,如果我们要将这个项目发布到N多台机器,那么我们是否需要在每个机器上都进行相同的步骤,并且要进行环境兼容性的测试。
再来看一个例子,我们现在想部署使用一个成熟的产品,这个产品是用go语言开发的,我该如何部署?go语言运行的环境怎么装?这个项目又该如何部署?
还有,一台linux机器上装了很多软件,部署了很多项目,相互之间有干扰怎么办?
如果有一项技术,可以解决以上问题或者是更多的问题,是不是很爽? 那就是Docker(容器)技术。
官网:https://www.docker.com/ (国内打开比较慢)
虚拟化:
docker:
docker的优势在于可以直接使用主机操作系统的资源进行虚拟化。
Docker daemon(Docker进程):
Docker进程是部署在linux操作系统上,负责支撑Docker Container的运行以及本地Image的管理。
Docker client:
用户不直接操作Docker daemon,用户通过Docker client访问Docker,Docker client提供pull、run等操作命令。
Docker Image:
Docker 镜像就是一个只读的模板。
例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。
镜像可以用来创建 Docker 容器。
Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
Docker Container:
Docker 利用容器来运行应用。容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
Docker Registry:
仓库分为公开仓库(Public)和私有仓库(Private)两种形式
最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。
用户也可以在本地网络内创建一个私有仓库。
当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
我们可以在Centos或者Ubuntu下安装docker,要注意的是,centos6对docker支持的不好,使用docker建议升级到centos7。
docker官方建议使用Ubuntu系统,兼容性更好一些。所以,我们使用Ubuntu系统来学习docker。
Ubuntu系统的安装参考《VMware Workstation 中安装 Ubuntu16.04 虚拟机.docx》
在课前资料中已经提供了“Ubuntu16-64-镜像”,我们直接导入即可学习,该镜像中包含安装了lrzsz、jdk1.8、docker 1.12并且将所有的应用升级到最新。
直接通过yum安装即可:
yum install -y docker
rpm -ivh http://dl.Fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum install -y docker-io
service docker start
apt install docker.io -y
获取镜像通过命令,docker pull 完成:
案例:获取Redis 3.0.0的镜像。
第一步,需要到远程的仓库进行搜索:
https://hub.docker.com/
点击查看详情,查看tag:
找到我们想要的3.0.0,最新的tag可以用latest标识:
执行命令:
docker pull redis:3.0
通过docker images查看镜像:
在国内通过docker官方的仓库进行下载镜像是比较慢,这个时候就需要使用加速器了。
在国内,阿里云、163都提供了docker仓库,但是阿里云还提供了加速功能。所以,我们选用阿里云的加速。 163的仓库地址:https://c.163.com/hub#/m/home/
使用阿里云器,需要到阿里云进行注册,获取到自己专属的加速地址,当然也可以使用我的加速地址。(使用加速是无需登录的,所以可以公用)
第一步,打开阿里云网站,点击控制台:
https://www.aliyun.com/
第二步,进行登录,如果没有账号就先注册个账号,登录成功后会跳转到控制台页面,找到容器服务:
第三步,点击“镜像”:
就可以看到有很多的镜像了:
第四步,点击右上角的“镜像仓库控制台”,进入后然后点击“Docker Hub 镜像站点”:
就可以看到你的专属加速地址了:
下面是使用加速地址的方法:
我们采用第2种方法:
再获取镜像时发现快多了。
搜素镜像:
https://dev.aliyun.com/search.html
下载rabbitmq的镜像:
docker pull rabbitmq:3.6.12
下载完成。
使用docker images 可以看到本地的镜像列表:
删除镜像通过命令docker rmi 镜像id完成,需要注意的是,删除镜像前,要删除所有使用到该镜像的容器。
-f参数是强制删除,如果有正在运行的容器使用了该镜像,那么该镜像是不会真正的删除的。
刚刚我们是通过网页进行搜索,其实用过docker的命令也可以搜索,具体如下:
通过docker ps命令查看正在运行的容器列表,需要查询所有的容器需要加-a参数:
docker ps
docker ps -a
通过docker create 命令可以创建一个容器,这仅仅是创建,并没有启动容器。
用法:
案例:创建Redis的容器。
docker create -p 16379:6379 --name redis redis:3.0
查看容器列表:
启动容器:
docker start 6e #指定容器的id,只要输入前几位即可
通过客户端进行测试:
至此,第一个docker容器就创建并且已经启动可用了。
上面通过docker create创建了容器,然后通过docker start来启动容器,其实这种做法并不常用。
更常用的是docker run命令,这个命令的意思是创建并且启动容器。
用法:
创建并且运行一个redis容器,它的端口是16380。
docker run -p 16380:6379 --name redis2 redis:3.0
发现,这个容器已经创建并且运行,但是,它并没有在后台运行,当按下 control + c时,该容器将停止。
为了让容器在后台运行,需要添加参数 -d。
docker run -p 16380:6379 -d --name redis2 redis:3.0
报错,说redis2这个名字的容器已经存在,需要我们删除906的容器或者给新容器重命名。我们重命名试试。
docker run -p 16380:6379 -d --name redis3 redis:3.0
已经创建成功。
进行测试:
测试结果显示,该容器可用。
接下来,我看下当前运行的容器:
可以看到,有3个redis的容器,并且名为redis2的容器已经退出,并没有运行。
那么问题来了,redis2这个容器我不想要了,怎么删除?
用法:docker start 容器名或容器id
停止容器有2种方式:
1、 docker stop 容器名或容器id
2、 docker kill 容器名或容器id
通过命令docker rm 删除容器,删除正在运行的容器添加 -f 参数。
root@itcast:~# docker rm --help
Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
Remove one or more containers
Options:
-f, --force Force the removal of a running container (uses SIGKILL)
--help Print usage
-l, --link Remove the specified link
-v, --volumes Remove the volumes associated with the container
案例:
docker rm redis2
删除名为redis2的容器。
有些时候我们需要进入容器内,做一些操作,比如,修改配置文件等。
进入容器,通过命令 docker exec 完成。
案例:进入redis容器,。
docker exec -it redis /bin/bash
control + d 退出容器。
通过命令docker logs -f 容器名或id
阿里云既提供了加速功能,也提供了仓库功能,也就是我们可以将自己的镜像上传到阿里云仓库。
https://cr.console.aliyun.com/#/imageList
创建命名空间:
创建镜像:
创建完成后就可以上传镜像到该仓库了。
第一步,在阿里云仓库创建redis镜像库:
第二步,在docker中进行登录:
第三步,给镜像打tag:
docker tag redis:3.0 registry.cn-hangzhou.aliyuncs.com/itcast/redis:3.0
第四步,推送镜像到阿里云:
docker push registry.cn-hangzhou.aliyuncs.com/itcast/redis:3.0
第五步,在阿里云查看:
接下来,将本地仓库中的redis镜像删除,从阿里云拉取镜像到本地。
内网私服地址:http://192.168.50.33:8081/ 或 https://192.168.50.33:8443/
账户:itcast / 123456
仓库地址:https://192.168.50.33:8443/repository/itcast/ 需要注意的是,仓库的端口是18443,而不是8443,在创建仓库时指定。
docker进行推送镜像时只能使用https协议,所以,我们需要将证书导入到系统。
上传证书到/tmp下面
cp /tmp/nexus.crt /usr/local/share/ca-certificates
sudo update-ca-certificates
service docker restart
接下来,进行测试:
#使用docker登录到私服
docker login 192.168.50.33:18443
#打tag
docker tag percona:5.6 192.168.50.33:18443/percona:5.6
#推送镜像到私服
docker push 192.168.50.33:18443/percona:5.6
容器在运行项目时会产生数据,比如运行的mysql容器,那么一定会有数据的产生,那么问题来了,数据是保存在容器内部还是保存在外部?
如果将数据保存在内部,那么也就意味着我们改变了原有镜像,这种做法是不可取的,因为在后期的镜像升级将变得不可能了。
也就是说,运行的镜像,最好不要改变,如果必须改变的(比如说,修改配置文件等),在改变后记得commit提交打成一个新的镜像。
显然,数据是应该保存在容器的外部,也就是说保存在主机上。那么问题又来了,数据保存在主机上,那么容器该如何读取主机中的数据呢?
在create或者run容器时,可以通过-v参数指定主机的目录,挂在到容器中的某一个目录上,这样,容器就在这个目录读写数据了。从而实现了容器和数据的分离。
第一步,下载mysql的镜像:
地址:https://hub.docker.com/_/percona/
docker pull percona:5.6
第二步,创建容器:
解释:
第三步,启动容器:
docker start percona
第四步,进行测试:
查看主机的/data/mysql-data:
前面我们的学习都是直接从仓库中拉取镜像,然后创建容器,最后启动容器来使用的。
在实际开发过程中,仓库中的容器可能不能完全满足我们的需求,比如说,我们项目的部署到docker容器,就不能从仓库中直接拉取镜像,就需要自己构建镜像了。
构建镜像通过编写Dockerfile配置文件完成。
Dockerfile是一个文本文件,里面编写多条命令,这些命令描述了一个镜像构建的细节。
先来看个示例:
DockerFile分为四部分组成:基础镜像信、维护者信息、镜像操作指令和容器启动时执行的指令。
编写Dockerfile如下:
构建命令:
构建完成:
创建容器:
启动容器:
测试:
将该镜像上传到阿里云:
由于项目会经历不同的环境,有开发环境、测试环境、生产环境,每个环境的地址是不同的,所以,需要在每个环境中编写不同的配置文件,比如:端口、Eureka服务地址等。
Spring Boot项目的配置文件提供的多种方式指定不同环境配置项的方法,这里介绍一种通过运行参数或者是JVM参数来指定。
在配置文件中这样配置:
server:
port: ${port:6778} #服务端口
说明:
${} -- 指定这是一个动态的配置文件项,不是固定的内容
port --指运行参数或者JVM参数来替换的变量值
:6778 -- 指如果运行环境中没有改配置项,就采用该内容
类似的配置如下:
设置方式:--参数名=参数值 --参数名=参数值 ……
设置方式:-D参数名=参数值 --D参数名=参数值 ……
由于我们是测试阶段,所以先只发布到一台机器,在多个容器中运行,一个项目运行一个容器。
项目 |
容器名称 |
IP |
容器内部端口 |
主机端口 |
备注 |
itcast-microservice-eureka |
eureka-server |
172.16.55.138 |
6868 |
6868 |
注册中心 |
itcast-microservice-config-server |
config-server |
172.16.55.138 |
6869 |
6869 |
配置服务 |
RabbitMQ |
RabbitMQ |
172.16.55.138 |
5672/15672 |
5672/15672 |
RabbitMQ服务 |
itcast-microservice-item-1 |
item-server-1 |
172.16.55.138 |
6870 |
6870 |
商品服务1 |
itcast-microservice-item-2 |
item-server-2 |
172.16.55.138 |
6871 |
6871 |
商品服务2 |
itcast-microservice-order-1 |
order-server-1 |
172.16.55.138 |
6872 |
6872 |
订单服务1 |
itcast-microservice-api-gateway-1 |
api-gateway-1 |
172.16.55.138 |
6873 |
6873 |
网关服务1 |
server:
port: 6868 #服务端口
spring:
application:
name: itcast-microservice-eureka #指定服务名
eureka:
client:
registerWithEureka: false #是否将自己注册到Eureka服务中,本身就是所有无需注册
fetchRegistry: false #是否从Eureka中获取注册信息
server:
enable-self-preservation: true #禁用自我保护模式
security:
basic:
enable: true #开启基于HTTP basic的认证
user: #配置用户的账号信息
name: itcast
password: itcast123
打包完成:
docker pull java:8
首先将itcast-microservice-eureka.jar文件上传到linux系统中的/tmp/itcast-microservice-eureka目录。
编写Dockerfile文件:
app-entrypoint.sh文件:
构建:
docker build -t itcast-microservice-eureka:1.0.0 .
不设置变量:
同样也是使用容器来运行RabbitMQ。
测试:
使用guest/guest进行登录:
RabbitMQ安装完成。
server:
port: ${port:6869} #服务端口
spring:
application:
name: itcasst-microservice-config-server #指定服务名
cloud:
config:
server:
git: #配置git仓库地址
uri: ${gitUrl:http://172.16.55.138:10080/zhangzhijun/itcast-config-server.git}
#username: zhangzhijun
#password: 123456
rabbitmq: #RabbitMQ相关的配置
host: ${rabbitMQHost:127.0.0.1}
port: ${rabbitMQPort:5672}
username: ${rabbitMQUsername:guest}
password: ${rabbitMQPassword:guest}
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,默认为true
fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: ${eurekaServerUrl:http://itcast:[email protected]:6868/eureka/}
instance:
prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
ipAddress: ${ipAddress:127.0.0.1}
management:
security:
enabled: false #是否开启actuator安全认证
首先将itcast-microservice-config.jar文件上传到linux系统中的/tmp/itcast-microservice-config目录。
编写Dockerfile文件:
app-entrypoint.sh文件:
构建:
格式化下看的清楚些:
docker create --name config-server -t -p 6869:6869 -e PORT=6869 -e GIT_URL=https://gitee.com/zhijun.zhang/itcast-config-server.git -e RABBITMQ_HOST=172.16.55.138 -e RABBITMQ_PORT=5672 -e RABBITMQ_USERNAME=guest -e RABBITMQ_PASSWORD=guest -e EUREKA_SERVER_URL=http://itcast:[email protected]:6868/eureka/ -e IP_ADDRESS=172.16.55.138 itcast-microservice-config:1.0.0
docker start config-server && docker logs -f config-server
bootstrap.yml:
eureka:
client:
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: ${eurekaServerUrl:http://itcast:[email protected]:6868/eureka/}
spring:
cloud:
config:
name: microservice #对应的配置服务中的应用名称
#uri: http://127.0.0.1:6869/
profile: dev #对应配置服务中的{profile}
label: master #对应的分支
discovery:
enabled: true #启用发现服务功能
service-id: itcasst-microservice-config-server #指定服务名称
rabbitmq: #RabbitMQ相关的配置
host: ${rabbitMQHost:127.0.0.1}
port: ${rabbitMQPort:5672}
username: ${rabbitMQUsername:guest}
password: ${rabbitMQPassword:guest}
application.yml:
server:
port: ${port:6870} #服务端口
spring:
application:
name: itcasst-microservice-item #指定服务名
logging:
level:
org.springframework: INFO
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,默认为true
fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: ${eurekaServerUrl:http://itcast:[email protected]:6868/eureka/}
instance:
prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
ip-address: ${ipAddress:127.0.0.1}
management:
security:
enabled: false #是否开启actuator安全认证
首先将itcast-microservice-item.jar文件上传到linux系统中的/tmp/itcast-microservice-item目录。
编写Dockerfile文件:
app-entrypoint.sh文件:
构建:
docker build -t itcast-microservice-item:1.0.0 .
docker create --name item-server-1 -t -p 6870:6870 -e PORT=6870 -e RABBITMQ_HOST=172.16.55.138 -e RABBITMQ_PORT=5672 -e RABBITMQ_USERNAME=guest -e RABBITMQ_PASSWORD=guest -e EUREKA_SERVER_URL=http://itcast:[email protected]:6868/eureka/ -e IP_ADDRESS=172.16.55.138 itcast-microservice-item:1.0.0
docker start item-server-1 && docker logs -f item-server-1
docker create --name item-server-2 -t -p 6871:6871 -e PORT=6871 -e RABBITMQ_HOST=172.16.55.138 -e RABBITMQ_PORT=5672 -e RABBITMQ_USERNAME=guest -e RABBITMQ_PASSWORD=guest -e EUREKA_SERVER_URL=http://itcast:[email protected]:6868/eureka/ -e IP_ADDRESS=172.16.55.138 itcast-microservice-item:1.0.0
docker start item-server-2 && docker logs -f item-server-2
server:
port: ${port:8082} #服务端口
itcast:
item:
url: http://127.0.0.1:8081/item/
spring:
application:
name: itcasst-microservice-order #指定服务名
eureka:
client:
registerWithEureka: false #是否将自己注册到Eureka服务中,默认为true
fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: ${eurekaServerUrl:http://itcast:[email protected]:6868/eureka/}
itcasst-microservice-item:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
首先将itcast-microservice-order.jar文件上传到linux系统中的/tmp/itcast-microservice-order目录。
编写Dockerfile文件:
app-entrypoint.sh文件:
构建:
docker build -t itcast-microservice-order:1.0.0 .
docker create --name order-server-1 -t -p 6872:6872 -e PORT=6872 -e EUREKA_SERVER_URL=http://itcast:[email protected]:6868/eureka/ itcast-microservice-order:1.0.0
docker start order-server-1 && docker logs -f order-server-1
server:
port: ${port:6873} #服务端口
spring:
application:
name: itcasst-microservice-api-gateway #指定服务名
zuul:
routes:
item-service: #item-service这个名字是任意写的
path: /item-service/** #配置请求URL的请求规则
#url: http://127.0.0.1:8081 #真正的微服务地址
serviceId: itcasst-microservice-item #指定Eureka注册中心中的服务id
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,默认为true
fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: ${eurekaServerUrl:http://itcast:[email protected]:6868/eureka/}
instance:
prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
ip-address: ${ipAddress:127.0.0.1}
首先将itcast-microservice-api-gateway.jar文件上传到linux系统中的/tmp/ itcast-microservice-api-gateway目录。
编写Dockerfile文件:
app-entrypoint.sh文件:
构建:
docker build -t itcast-microservice-api-gateway:1.0.0 .
docker create --name api-gateway-1 -t -p 6873:6873 -e PORT=6873 -e IP_ADDRESS=172.16.55.138 -e EUREKA_SERVER_URL=http://itcast:[email protected]:6868/eureka/ itcast-microservice-api-gateway:1.0.0
docker start api-gateway-1 && docker logs -f api-gateway-1
阅读原文即可在线观看教程及下载教程