ZB-049-01docker原理

Docker原理与应⽤

Docker改变了软件世界

Docker出现之前…

  • 软件在操作系统上如何工作的?
  • 如何交付软件?
  • 如何部署软件?

各种环境问题,版本,软件依赖,那个时候我们使用的是虚拟机

每次都是重新安装虚拟机。

  • 它很重,安装很慢。
  • 独立的操作系统,非常吃内存
  • 基本你开几个虚拟机内存就都被虚拟机吃掉了

Docker出现之后

启动一个 ubuntu

1
2
docker run ubuntu
# 真正的秒开

Docker能做什么?

  • 保证开发、测试、交付、部署的环境完全⼀致
  • 保证资源的隔离
  • 启动临时的、⽤完即弃的环境,例如测试
  • 迅速(秒级)超⼤规模部署和扩容

Docker的基本概念

核心有两个 image 和 container

  • 镜像 image
    • ⼀个预先定义好的模板⽂件,Docker引擎可以按照这个模板
      ⽂件启动⽆数个⼀模⼀样,互不⼲扰的容器
  • 容器 container
    • ⼀台虚拟的计算机,拥有独⽴的:
      • ⽹络
      • ⽂件系统
      • 进程
    • 默认和宿主机不发⽣任何交互
      • 意味着数据是没有持久化的!

查看所有的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
> docker images
# 显示出所有的配置清单
REPOSITORY TAG IMAGE ID CREATED SIZE
jenkins/jenkins latest ec2bfee7c206 4 weeks ago 553MB
ubuntu latest 775349758637 3 weeks ago 64.2MB
mysql latest c7109f74d339 5 months ago 443MB
hello-world latest fce289e99eb9 11 months ago 1.84kB

# mysql 就是一个镜像,一份说明书
# 每当你运行这句话的时候
< docker run -d ubuntu
> 7104470ea1e97e7596517da9e9a50b352e3f9e6867647d4789162e8b8dec369b 容器的id
# docker都会安装这个说明书(清单), 帮你组装一个机器,变成一个电脑的实例

启动三个一模一样的mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 如果启动失败使用
docker run -it mysql 来启动一个交互式的命令行 让你知道哪里出了问题

# 你可以连续启动 mysql -e代表指定环境变量
< docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql
> 2b3c2df780ea82cfa28f2a0565fe3f788cb298d8e87a6485f071fd83245beabc

< docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql
> a91be367d2e16b161fc79e486b7ab99a21b6953aabf8876b93080a72ba0b518a

< docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql
> 2a081daaa8628e19bbd55c174712f604a1f85ab511b4581332ea505270db02c5

# 查看你启动的 容器
< docker ps
> # 此时 启动⽆数个⼀模⼀样,互不⼲扰的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2a081daaa862 mysql "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 3306/tcp, 33060/tcp jovial_bell
a91be367d2e1 mysql "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 3306/tcp, 33060/tcp youthful_perlman
2b3c2df780ea mysql "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 3306/tcp, 33060/tcp friendly_ramanujan
docker pull/images
  • 下载⼀个指定的镜像,⽅便随时启动
  • docker pull mysql:5.7.28 下载指定镜像
  • docker images 查看本地已有的镜像

下载指定的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
docker pull mysql:5.7.28

# 比你以前安装软件的方式 非常快
docker pull 镜像的名字:tag

# tag可以不加,意思是下载最新版本
docker pull mysql
# 等价于
docker pull mysql:latest


registry.cn-beijing.aliyuncs.com/dr1/hcsp:0.0.16
镜像仓库 registry.cn-beijing.aliyuncs.com/ 不加就会从 docker的中央仓库下载
镜像名 hcsp
tag 0.0.16

docker run/ps

  • docker run 装载镜像成为⼀个容器
    • 就好像从蛋糕模⼦做出来⼀个蛋糕
    • 在这个容器看来,⾃⼰就是⼀台独⽴的计算机
    • 每个容器有⼀个ID,⽀持缩写
  • docker run -it <镜像名> <镜像中要运⾏的命令和参数>

    • 交互式命令⾏,当前shell中运⾏,Ctrl-C退出
    • 就是在当前的命令行里启动一个容器并和这个容器进行交互(进入这个容器内部)
      1
      2
      3
      4
      5
      docker run -it mysql
      等价于进入 mysql 的命令行

      docker run -it ubuntu echo "hahaha"
      进入 ubuntu 命令行环境并 执行 echo "hahaha"
  • docker run -d <镜像名> <镜像中要运⾏的命令和参数>

    • daemon模式,在后台运⾏
      • 立刻返回,给你给id ,在后台默默的运行,
      • 长期执行的后台进程,如 mysql/redis

删除一个容器

1
2
3
4
5
6
7
8
# 这个id就是 容器id 可以缩写
docker rm id
# 有时候会提示 你的容器还在运行不能直接删除,此时你应该 先停止这个容器 然后在删除
docker stop id
docker rm id

# 当然你还可以这样 强制删除
docker rm -f id

docker run

  • --name 为容器指定⼀个「名字」
  • --restart=always 遇到错误⾃动重启
  • -v <本地⽂件>:<容器⽂件>
  • -p <本地端⼝>:<容器端⼝>
  • -e NAME=VALUE

给容器起一个名字 --name

  • 注意区分docker参数 和容器参数,他们有强烈的区分
    1
    2
    3
    4
    docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=xdml -p 3306:3306 -d mysql

    -d mysql 之前是 docker的参数
    -d mysql 之后是 给 mysql的参数
1
2
3
4
5
6
7
8
9
10
docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw  -d mysql
# 此时你通过 镜像(清单) mysql 启动了一个容器
# 这个容器名字为 my-mysql
# 指定它的环境变量参数 MYSQL_ROOT_PASSWORD=my-secret-pw

此时你可以通过这个 名字来对 容器进行操作了 ,也可以用它的id
docker run -it my-mysql
docker run -it id

docker rm -f my-mysql

通过-v 与宿主机产生联系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 进入shell 
# 当前路径 ~/Desktop
# 我在 ~/Desktop上新建文件 1.txt 内容 aaaaaa
# cat 1.txt >> aaaaaa
# 把宿主机上的文件 映射给 容器上的某个文件
< docker run -it -v `pwd`/1.txt:/1126/aaa.txt ubuntu
# 进入 docker启动的容器 ubuntu命令行环境
< cat /1126/aaa.txt
> 得到 aaaaaa
# 修改 /1126/aaa.txt的内容
< echo "hahaha" > /1126/aaa.txt

# 退出 ubuntu 命令行
> exit
# 此时回回到 宿主机 shell的命令行环境 也就是 ~/Desktop
< cat 1.txt
> hahaha # 内容被成功修改了

文件读写权限也会映射吗?

不会,取决于你的dockerfile怎么定义的

-p 端口映射

1
2
3
4
5
6
7
8
# 这样会在docker里启动一个 mysql 默默的运行在后台
docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql

# 你是无法访问它的 ,因为它运行在 docker的 3306端口上,跟宿主机是隔离的

# 你只能通过 -p 的端口映射来访问它
docker run -v "$PWD/data":/var/lib/mysql --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=xdml -p 3306:3306 -d mysql
# 将 宿主机的 3306端口 映射到 docker 容器内的 3306端口上

这样你就可以实现分布式部署

1
2
3
4
你的spring01应用
8080:8081
你的spring02应用
8080:8082

-e 传递环境变量

1
2
3
< docker run -e AAA=BBB -it ubuntu
< echo AAA
> BBB

一般用来传递参数,如mysql,传递初始化参数

1
docker run -v "$PWD/data":/var/lib/mysql --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=xdml -p 3306:3306 -d mysql

docker start/stop

  • 启动/停⽌⼀个容器
  • 可以想象为开关机

docker rm

  • 删除⼀个容器
  • 想象成将电脑丢掉

docker exec

指定⽬标容器,进⼊容器执⾏命令

  • docker run -it <⽬标容器ID> <⽬标命令(通常为bash)>
  • 可以「想象」成ssh
  • 调试、解决问题必备命令
1
2
3
4
假设你mysql 做目录映射来持久化数据的时候 目录写错了,但是你自己不知道

# 你就只能通过这样来操作了
docker exec -it my-mysql bash

盗梦空间可能吗?

一层一层的梦

1
docker in docker 有可能的 但是非常不推荐

docker logs

通过id去看一个容器的日志

  • docker logs <容器ID或容器名>
  • 查看⽬标容器的输出
  • docker logs -f <容器ID或容器名>

docker inspect

  • ⾼级命令,可以⽆视
  • 查看容器的详细状态

删除镜像

1
docker rmi 镜像id

dockerfile和镜像仓库

分层的镜像

  • 为了复用
    1
    2
    假如你有两个应用 A 和 B 他们都基于 ubuntu
    这样他们就可以都共用一个镜像

Dockerfile

  • 指定镜像如何⽣成
  • 编写第⼀个Dockerfile
  • docker build .
  • 每个镜像会有⼀个唯⼀的ID

编写一个简单的 dockerfile

1
2
3
mkdir my-dockerfile
cd my-dockerfile
vi Dockerfile

Dockerfile 内容如下

1
2
3
4
5
6
7
8
# 指定基础镜像 如果没有就去下载
FROM ubuntu:16.04
# 按照 nginx
RUN apt-get update && apt-get install -y nginx

RUN echo "HHHH" > /usr/share/nginx/html/index.html
# 暴露80端口
EXPOSE 80
  • 运行docker build . 构建你的镜像 (通过装机清单构建我们的镜像)
  • 我们的镜像没有起名字 所以只能通过 id 启动
    1
    2
    3
    4
    5
    # 启动你的镜像
    docker run -p 8080:80 -d 你的id

    # 启动并进入镜像内部
    docker run -p 8080:80 -it 你的id

Docker的镜像仓库与tag

  • 可以任意对镜像进⾏tag操作
  • 决定了未来这个镜像会被push到哪⾥
  • 决定了未来从哪⾥下载镜像
  • 可以⽅便的创建镜像仓库的私服
  • --registry-mirror
  • --insecure-registry

给你的镜像起个名字

1
2
3
4
5
6
docker tag 镜像id  镜像名字:镜像tag

docker tag 77 hahaha:123

注意这个名字 不是随便起的,它决定了未来这个库 push 从哪进行
指明了 未来 push的地址 可以是中央仓库 可以是 私服

Docker与K8s

Docker 与 Kubernetes

  • Kubernetes 可以做到一个应用启动 n 个同一镜像,
  • 还可以实现应用版本的更新(滚动更新)
    • 应用从 0.0.1 –》 0.0.2的更新
    • 假设你的应用有100个 他会杀掉几个 更新成最新版本,依次迭代到所有的版本都更新了

没法继续扩展了,基本只有大公司用的到

小公司达不到这个量级。小公司撑死启两个容器就不错了

参考链接

实战一下本地部署 spring-boot

  • 参考文章
    • 注意它的docker run -t hxy -p 8081:8081 是有问题的
    • 你要 先 -p 8080:8080 -d 你的id 形如 docker run -p 8081:8081 -d 镜像id
  • 参考Dockerfile为这个安装更快
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    FROM java:openjdk-8u111-alpine

    RUN mkdir /app

    WORKDIR /app

    COPY target/gs-spring-boot-0.1.0.jar /app

    EXPOSE 8080

    CMD [ "java", "-jar", "gs-spring-boot-0.1.0.jar" ]

01 直接拉代码spring_issue_api

02 idea打开运行 mvn package

03 根目录新建 Dockerfile文件

1
2
3
4
5
6
7
8
9
10
11
FROM java:openjdk-8u111-alpine

RUN mkdir /app

WORKDIR /app

COPY target/gs-spring-boot-0.1.0.jar /app

EXPOSE 8080

CMD [ "java", "-jar", "gs-spring-boot-0.1.0.jar" ]

04 运行docker build -t hjx .

  • -t 代表 tag 就是你可以用这个名字来启动它

05 docker run -p 8080:8080 -d hjx