微服务day06-Docker

Docker

大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题:

  • 依赖关系复杂,容易出现兼容性问题

  • 开发、测试、生产环境有差异

1.什么是Docker?

大型项目组件很多,运行环境复杂,部署时会遇到各种问题,各个应用依赖各不相同,版本不同等,linux系统不同等…部署时非常复杂,效率很低。
Docker如何解决依赖兼容的问题?

  • 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包

  • 将每个应用放到一个隔离容器去运行,避免互相干扰

虽然解决了不同应用的兼容问题,但是开发、测试等环境会存在差异,操作系统版本也会有差异,怎么解决这些问题呢?

linux系统的原理
分为3层,系统应用层(ubuntu/centos等),linux内核(所有Linux系统使用的都是linux系统内核),计算机硬件;
内核:内核负责与硬件交互,对上层提供内核指令,用于操作硬件;
系统应用:操作系统本身提供的应用、函数库。这些函数库是对内核指令的封装,使用更加方便;

应用于计算机交互的流程如下:

1)应用调用操作系统应用(函数库),实现各种功能

2)系统函数库是对内核指令集的封装,会调用内核指令

3)内核指令操作计算机硬件

由于系统应用不同,因此ubuntu的一个应用安装到centos系统上可能无法执行(提示找不到函数等),因此Docker提供了解决方案:

  • Docker将用户程序与所需要调用的系统(比如Ubuntu)函数库一起打包
  • Docker运行到不同操作系统时,直接基于打包的函数库,借助于操作系统的Linux内核来运行

2.Docker与虚拟机的区分?

Docker可以让一个应用在任何操作系统中非常方便的运行。而以前我们接触的虚拟机,也能在一个操作系统中,运行另外一个操作系统,保护系统中的任何应用。

虚拟机(virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在 Windows 系统里面运行 Ubuntu 系统,这样就可以运行任意的Ubuntu应用了。

Docker仅仅是封装函数库,并没有模拟完整的操作系统,如图:

二者的性能指标对比:

综上所述,在实际的开发部署中通常Docker>虚拟机。

3.Docker架构

镜像
就是把一个应用在硬盘上的文件、及其运行环境、部分系统函数库文件一起打包形成的文件包。这个文件包是只读的。
容器
镜像中的应用程序运行后形成的进程就是,只不过要隔离起来。因此一个镜像可以启动多次,形成多个容器进程。

开源应用程序非常多,打包这些应用往往是重复的劳动。为了避免这些重复劳动,人们就会将自己打包的应用镜像,例如Redis、MySQL镜像放到网络上,共享使用,就像GitHub的代码共享一样。

  • DockerHub:DockerHub是一个官方的Docker镜像的托管平台。这样的平台称为Docker Registry。

  • 国内也有类似于DockerHub 的公开服务,比如 网易云镜像服务阿里云镜像库等。

我们一方面可以将自己的镜像共享到DockerHub,另一方面也可以从DockerHub拉取镜像:

Docker是一个CS架构的程序,由两部分组成:

  • 服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等

  • 客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。本地直接使用指令即可,远程使用RestApi发送请求。
    在这里插入图片描述

4.Docker的安装

企业部署使用最多的时linux系统(Centos最多)

使用虚拟机安装CentOS7系统(满足了Docker CE对linux内核的最低要求)

1.卸载旧版Docker
如果虚拟机中可能存在旧版Docker,则需要删除旧的docker中相关内容

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine \
                  docker-ce

2.卸载旧版Docker
2.1 虚拟机联网
记得使用NAT

2.2 安装yum工具

yum install -y yum-utils \ 
		   device-mapper-persistent-data \
           lvm2 --skip-broken

2.3 设置docker镜像源

yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
yum makecache fast

2.4 下载以及安装docker-ce(社区免费版)

yum install -y docker-ce

2.5 启动Docker(如果是在虚拟机上为了避免逐个关闭端口号可以直接关闭防火墙,并设置禁用防火墙)

# 关闭
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld

2.6 安装成功之后,查看版本

docker -v 

显示如下内容表名安装成功
在这里插入图片描述
2.7 新安装docker之后如果重启可能导致docker服务没有启动,报错如下,表示docker守护进程未启动:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
此时在root权限下执行

systemctl start docker 

5.镜像的命令

首先来看下镜像的名称组成:

  • 镜名称一般分两部分组成:[repository]:[tag]。
  • 在没有指定tag时,默认是latest,代表最新版本的镜像

比如[mysql]:[8.33];
在这里插入图片描述
常用命令:

  • 从dockerhub中拉取镜像
# 比如拉取nginx1.2.5版本
docker pull nginx:1.25.4
  • 查看本地镜像
docker images
  • 导出镜像到磁盘
# docker save -o [保存的目标文件名称] [镜像名称]
docker save -o nginx.tar nginx:1.25.4

如果只是指定保存文件名称,则会保存到当前目录下,如果想要保存到某个目录下可以直接指定:

docker save -o ./download/nginx.tar nginx:1.25.4
  • 从磁盘中加载镜像
# docker load -i [某个位置的镜像包(如果是在当前目录下直接用镜像名即可]
docker load -i ./download/nginx.tar
  • 删除镜像
docker rmi nginx:1.25.4
  • 构建镜像
docker build -t javaweb:1.0 .
# -t javaweb:1.0 给镜像一个名称
# .  表示dockerfile所在目录

6.容器的命令

基本命令使用
在这里插入图片描述

  • 创建一个并运行一个nginx容器:
docker run --name contrainerName -p 80:8080 -d ngxin:1.24.5
# docker run 创建并运行一个nginx容器
# --name contrainerName  为容器起一个名字
# -p 80:8080 宿主机与容器的端口映射,左侧是宿主机端口,右侧是容器端口
# -d ngxin:1.24.5运行的容器是哪一个(-d是放到后台邮件)

对端口映射的解读:

由于容器是隔离的,所以并不能直接外部主机访问,外部主机可以访问宿主机(你可以将docker容器比作一个寄生虫,计生在宿主体内,外部无法与它直接交流,如果有必要交流,必须通过宿主作为中介,即外部告诉宿主,宿主告诉寄生虫),因此,将宿主机的端口与docker容器的端口作了一个映射之后,外部主机访问宿主机对应端口,宿主机端口再将对应的内容按照端口映射转发给docker容器

创建成功之后会返回该容器的ID:
在这里插入图片描述

  • 查看所有容器的状态:
docker ps 
  • 查看容器的日志
# 普通日志输出
docker logs mv
# 持续跟踪日志输出
docker logs -f mv 
  • 让一个停止的容器再次运行
docker start mv 
  • 停止一个容器的运行
docker stop mv 
  • 暂停(挂起)一个容器
docker pause mv 
  • 将暂停(挂起)的容器拿下来继续运行
docker unpause mv 

nginx容器创建之后,直接访问虚拟机对应的端口号:
在这里插入图片描述
进入容器,修改文件
进入容器。进入我们刚刚创建的nginx容器的命令为:

docker exec -it mn bash 
# docker exec 进入容器内部执行一个命令
# -it 给当前进入的容器一个标准输入,输出终端,允许我们与容器交互
# mn 我们要进入容器的名称
# bash 进入容器之后执行的命令

进入nginx默认页面的目录:

cd /usr/share/nginx/html

由于docker容器是阉割版的"系统",只提供了对应的镜像文件,因此不会提供vi等编辑器,如果要在里边修改内容,需要使用sed替换命令。

# sed命令详解
sed command file
# commond 针对每行的内容进行处理
	# -i 直接修改文件内容,而不是输出到屏幕上
	# -e 直接在命令行模式上进行sed的操作编辑
	# s 替换,将文件原内容替换为新内容。举例:s/old/new/g "/"是分割符号,用来区分新内容与旧内容的,也开始使用别的符号比如:“#”
	# g 表示行内全面替换
# file 要处理的文件,如果忽略该参数,会将标准输入作为对象进行处理

替换内容命令:

sed -i -e 's/传智教育欢迎您/NiHao/g' -e 's#<head>#<head><meta charset="utf-8">#g' index.html

替换之后结果
在这里插入图片描述

7.数据卷

在之前的操作中,容器与数据耦合过高,当需要修改更新等操作时,非常麻烦;因此引入数据卷的概念。
数据卷:一个虚拟目录,指向宿主主机文件系统中的某个目录。
在这里插入图片描述
可以类比映射,数据卷挂载之后,对etc/nginx/conf就相当于对宿主机中的conf目录下进行操作,html目录同理。
当需要修改/更新等操作时修改的实际上是宿主主机文件系统中的目录下的内容,就算将容器删除之后,数据也是存在的,如果想要获取原来的数据,只需要再将数据卷挂载到宿主文件系统中对应的目录就行了。

常用命令

  • docker volume命令是数据卷操作,根据命令后跟随的command来确定下一步的操作:

  • create 创建一个volume

# 创建一个名为html的数据卷
docker volume create html 
  • inspect 显示一个或多个volume的详细信息
docker volum inspect html

在该命令中我们可以查看该数据卷的详细信息,包括数据卷在宿主机中的存储位置:

在这里插入图片描述
可以看到该数据卷在宿主机中的实际位置是"/var/lib/docker/volumes/html/_data".

  • ls 列出所有的volume
docker volume ls 
  • prune 删除未使用的volume

  • rm 删除一个或多个指定的volume

数据卷挂载案例

  • 创建容器并挂载数据卷到容器内的目录
docker run --name mv -v html:/usr/share/nginx/html -p 80:80 -d nginx
# 创建容器的命令与之前相同,-v html:/usr/share/nginx/html 挂载数据卷html到容器内的/usr/share/nginx/html目录上

进入html数据卷所在位置,并修改HTML内容

# 查看html数据卷的位置
docker volume inspect html
# 进入该目录
cd /var/lib/docker/volumes/html/_data
# 修改文件
vi index.html

在宿主机下修改完成之后(或者说是在数据卷下修改之后),容器中的对应的文件也会同步修改。

数据卷挂载案例之二
容器不仅仅可以挂载数据卷,也可以直接挂载到宿主机目录上。关联关系如下:

  • 带数据卷模式:宿主机目录 --> 数据卷 —> 容器内目录
  • 直接挂载模式:宿主机目录 —> 容器内目录

目录挂载与数据卷挂载的语法是类似的:

  • -v [宿主机目录]:[容器内目录]
  • -v [宿主机文件]:[容器内文件]

案例:创建并运行一个MySQL容器,将宿主机目录直接挂载到容器

1.创建目录/tmp/mysql/,以及2个子目录:/tmp/mysql/data , /tmp/mysql/conf

cd /tmp # /tmp已经存在
mkdir /mysql
mkdir /mysql/data
mkdir /mysql/conf

2.以mysql为例,首先拉取8.0.33版本的mysql镜像

docker pull docker:8.0.33

3.查看镜像列表是否成功导入

docker images

4.导入mysql的一个额外配置文件hmy.cnf
在这里插入图片描述
5.创建mysql容器

docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123 \
-p 3306:3306 \
-v /tmp/mysql/conf/hmy.conf:/ect/mysql/conf.d/hmy.cnf \
-v /tmp/mysql/data:/var/lib/mysql \
-d \
mysql:8.0.33

运行成功之后,返回mysql容器ID,使用docker ps命令查看
在这里插入图片描述
然后在外部(你的主机)使用mysql客户端连接
在这里插入图片描述
提示连接成功则成功

8.自定义镜像

镜像结构

镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。
我们以MySQL为例,来看看镜像的组成结构:
在这里插入图片描述
镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合,然后编写好启动脚本打包在一起形成的文件。我们要构建镜像,其实就是实现上述打包的过程。

自定义镜像
构建自定义的镜像时,并不需要一个个文件去拷贝,打包。我们只需要告诉Docker,我们的镜像的组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、启动脚本是什么,将来Docker会帮助我们构建镜像。而描述上述信息的文件就是Dockerfile文件

指令说明示例
FROM指定基础镜像FROM centos:7
ENV设置环境变量,后续可以使用环境变量ENV key value
COPY拷贝本地文件到镜像的指定目录COPY ./mysql-5.7.rpm /tmp
RUN执行linux的shell命令,一般是安装过程的命令RUN yum install gcc
EXPOSE指定容器运行时监听的端口,是给镜像使用者用的EXPOSE 8089
ENTRYPOINT镜像中应用的启动命令,容器运行时调用ENTRYPOINT java -jar xx.jar

构建java项目
1.进入/tmp目录,创建一个docker-demo目录。
2.进入创建好的docker-demo目录。
3.上传文件包含实例项目,dockerfile,jdk
在这里插入图片描述
教义中给的是使用ubuntu作为底层镜像,我希望使用CentOS作为底层镜像,因此需要修改一下Dokcerfile。由于Dokcerfile普通用户只读,root用户可写,因此切换为root用户。

使用构建命令:

docker build -t javaweb:1.0 .
# -t javaweb:1.0 给镜像一个名称
# .  表示dockerfile所在目录

构建成功之后得到镜像,创建并启动容器,访问之:
在这里插入图片描述
虽然我们可以基于Ubuntu基础镜像,添加任意自己需要的安装包,构建镜像,但是却比较麻烦。所以大多数情况下,我们都可以在一些安装了部分软件的基础镜像上做改造。

例如,构建java项目的镜像,可以在已经准备了JDK的基础镜像基础上构建。

需求:基于java:8-alpine镜像,将一个Java项目构建为镜像

实现思路如下:

  • ① 新建一个空的目录,然后在目录中新建一个文件,命名为Dockerfile

  • ② 拷贝课前资料提供的docker-demo.jar到这个目录中

  • ③ 编写Dockerfile文件:

    • a )基于java:8-alpine作为基础镜像

    • b )将app.jar拷贝到镜像中

    • c )暴露端口

    • d )编写入口ENTRYPOINT

      内容如下:

      FROM java:8-alpine
      COPY ./app.jar /tmp/app.jar
      EXPOSE 8090
      ENTRYPOINT java -jar /tmp/app.jar
      
  • ④ 使用docker build命令构建镜像

  • ⑤ 使用docker run创建容器并运行

9.使用DockerCompose方式集群部署

Docker Compose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器!
Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。(是n个docker run 命令的集合)

version: "3.8" # 指定指令语法的版本。
 services: # 具体的微服务定义
  mysql:
    image: mysql:5.7.25
    environment:
     MYSQL_ROOT_PASSWORD: 123 
    volumes:
     - "/tmp/mysql/data:/var/lib/mysql"
     - "/tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf"
  web:
    build: .
    ports:
     - "8090:8090"

DockerCompose的安装

# 安装
curl -L https://github.com/docker/compose/releases/download/1.23.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

安装完成后会默认安装到/usr/local/bin目录下,此时该文件并不具有可执行权限,因此需要手动添加:

chmod +x ./docker-compose

添加自动补全命令

curl -L https://raw.githubusercontent.com/docker/compose/1.29.1/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

如果拒绝连接,修改hosts文件

echo "199.232.68.133 raw.githubusercontent.com" >> /etc/hosts
# 这里的IP地址似乎要换成自己的IP地址?

部署微服务集群
对之前的cloud-demo进行集群部署
1.将个人的微服务如:user-service,order-service,gateway等使用Maven打包工具打包。
2.docker-compose文件:(做了一些变更)

version: "3.2"

services:
  nacos:
    image: nacos/nacos-server
    environment:
      MODE: standalone
    ports:
      - "8848:8848"
  mysql:
    image: mysql:8.0.33
    environment:
      MYSQL_ROOT_PASSWORD: 123
    volumes:
      - "$PWD/mysql/data:/var/lib/mysql"
      - "$PWD/mysql/conf:/etc/mysql/conf.d/"
  userservice:
    build: ./user-service
  orderservice:
    build: ./order-service
  gateway:
    build: ./gateway
    ports:
      - "10010:10010"

由于一些配置的原因,现在各个微服务之间采用微服务名称互相访问,这需要修改一些代码中的配置

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黒猫.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值