Docker相关学习

8/4/2022 Docker技术部署容器

8月8日更新

# Docker介绍

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

  • 依赖关系复杂,容易出现兼容性问题
  • 开发、测试、生产环境有差异

Docker如何解决依赖的兼容问题的?

  • 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
  • 将每个应用放到一个隔离容器去运行,避免互相干扰

注意:仅限于同一个操作系统,这是因为docker是在操作系统的基础空间上运行的。

# Docker如何解决不同的操作系统

内核与硬件交互,提供操作硬件的指令

系统应用封装内核指令为函数,便于程序员调用

用户程序基于系统函数库实现功能

image-20220804141738976

为什么应用需要在同一个操作系统中?

这是因为虽然都是基于Linux内核,但是系统应用不同,提供的函数库有差异。例如CentOS中没有Ubuntu中的某些函数库。

函数库是写死的,是执行时调用的方法函数。所以Docker会将依赖和需要的函数库一起打包。这样,就不会管系统应用是什么了,可以直接操作内核。

Docker如何解决不同系统环境的问题?

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

Docker如何解决大型项目依赖关系复杂,不同组件依赖的兼容性问题?

  • Docker允许开发中将应用、依赖、函数库、配置一起打包,形成可移植镜像
  • Docker应用运行在容器中,使用沙箱机制,相互隔离

Docker如何解决开发、测试、生产环境有差异的问题

  • Docker镜像中包含完整运行环境,包括系统函数库,仅依赖系统的Linux内核,因此可以在任意Linux操作系统上运行

# Docker与虚拟机

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

image-20220804142955096

Docker与虚拟机的对比:

image-20220804143123275

Docker和虚拟机的差异:

  • docker是一个系统进程;虚拟机是在操作系统中的操作系统
  • docker体积小、启动速度快、性能好;虚拟机体积大、启动速度慢、性能一般

# Docker镜像和容器

镜像(Image):Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像。

容器(Container):镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器做隔离,对外不可见。

通过Linux的隔离手段,一个容器会以为自己是当前计算机系统上的唯一进程,从而做到了隔离效果。

# 关于数据读取

容器是不可以把数据写入镜像文件中的,因为会对镜像进行污染。所以镜像只读不写。若要写数据,则拷贝一份文件到容器自己的独立文件系统里。

# Docker和DockerHub

  • DockerHub:DockerHub是一个Docker镜像的托管平台。这样的平台称为Docker Registry。
  • 国内也有类似于DockerHub 的公开服务,比如 网易云镜像服务、阿里云镜像库等。

# Docker架构

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

  • 服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等
  • 客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。

image-20220804144307242

# Docker架构小结

镜像:

  • 将应用程序及其依赖、环境、配置打包在一起

容器:

  • 镜像运行起来就是容器,一个镜像可以运行多个容器

Docker结构:

  • 服务端:接收命令或远程请求,操作镜像或容器
  • 客户端:发送命令或者请求到Docker服务端

DockerHub:

  • 一个镜像托管的服务器,类似的还有阿里云镜像服务,统称为DockerRegistry

# 安装Docker

# 操作系统版本

Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10, CentOS 7 满足最低内核的要求,所以我们在CentOS 7安装Docker。

# 官网

https://www.docker.com (opens new window)

# 1.1.卸载(可选)

如果之前安装过旧版本的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
1
2
3
4
5
6
7
8
9
10
11

# 1.2.安装docker

首先需要大家虚拟机联网,安装yum工具

yum install -y yum-utils \
           device-mapper-persistent-data \
           lvm2 --skip-broken
1
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
1
2
3
4
5
6
7
8

然后输入命令:

yum install -y docker-ce
1

docker-ce为社区免费版本。稍等片刻,docker即可安装成功。

# 1.3.启动docker

Docker应用需要用到各种端口,逐一去修改防火墙设置。非常麻烦,因此建议大家直接关闭防火墙!

启动docker前,关闭防火墙(一般不用关闭)

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

通过命令启动docker:

systemctl start docker  # 启动docker服务

systemctl stop docker  # 停止docker服务

systemctl restart docker  # 重启docker服务
1
2
3
4
5

然后输入命令,可以查看docker版本:

docker -v
1

# 方式二安装

# 1.yum包更新到最新
yum update
# 2.安装需要的软件包,yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
yum install -y yum-utils device-mapper-persistent-data lvm2
# 3.设置yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 4.安装docker,出现输入的界面都按 y
yum install -y docker-ce
# 5.查看docker版本,验证是否成功
docker -v
1
2
3
4
5
6
7
8
9
10

# 配置镜像加速器

一这里使用的是阿里云的镜像加速器,地址:

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors (opens new window)

以下为阿里云提供的操作文档:

针对Docker客户端版本大于 1.10.0 的用户

您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

# 创建了一个文件
sudo mkdir -p /etc/docker
# 将阿里云的镜像文件配置写入文件内
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://4p32toi3.mirror.aliyuncs.com"]
}
EOF
# 重载
sudo systemctl daemon-reload
# 重启docker
sudo systemctl restart docker
1
2
3
4
5
6
7
8
9
10
11
12

# Docker基本操作

# 镜像相关命令

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

image-20220804151958681

# 镜像操作命令

image-20220804152904359

# 从DockerHub拉取一个镜像

DockerHub官网:

https://hub.docker.com (opens new window)

搜索镜像名称,例如Nginx:

image-20220804153737520

镜像详情页会有所有版本已经介绍,在右侧会有pull命令:

image-20220804153910891

在控制面板输入命令,等待安装即可:

[root@VM-8-14-centos ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete 
a9edb18cadd1: Pull complete 
589b7251471a: Pull complete 
186b1aaa4aa6: Pull complete 
b4df32aa5a72: Pull complete 
a0bcbecc962e: Pull complete 
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
1
2
3
4
5
6
7
8
9
10
11
12

通过输入docker images命令可以查看目前已经pull下来的镜像:

[root@VM-8-14-centos ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
nginx         latest    605c77e624dd   7 months ago    141MB
hello-world   latest    feb5d9fea6a5   10 months ago   13.3kB
1
2
3
4

# 利用docker save导出镜像到磁盘,load加载回来

步骤一:利用docker xx --help命令查看docker save和docker load的语法

docker save

[root@VM-8-14-centos ~]# docker save --help

Usage:  docker save [OPTIONS] IMAGE [IMAGE...]
# 保存一个或多个镜像到tar文件中
Save one or more images to a tar archive (streamed to STDOUT by default)

Options:
  -o, --output string   Write to a file, instead of STDOUT
1
2
3
4
5
6
7
8

docker load

-i:打印日志

-q:安静的,不会打印日志

[root@VM-8-14-centos ~]# docker load --help

Usage:  docker load [OPTIONS]

Load an image from a tar archive or STDIN

Options:
  -i, --input string   Read from tar archive file, instead of STDIN
  -q, --quiet          Suppress the load output
1
2
3
4
5
6
7
8
9

步骤二:使用docker save导出镜像到磁盘

使用docker save -o [保存到哪一个文件] [镜像名称:tag]导出

可以看到,导出了镜像文件到nginx.tar中:

[root@VM-8-14-centos ~]# docker save -o nginx.tar nginx:latest
[root@VM-8-14-centos ~]# ll
total 142532
-rw-r--r-- 1 root root      1781 Apr  8  2021 cosfs.sh
-rw-r--r-- 1 root root      1237 Jan 28  2021 dnspod.sh
-rw-r--r-- 1 root root     25166 Jan 14  2022 install_panel.sh
-rw-r--r-- 1 root root      2258 Mar  3  2021 install.sh
-rw------- 1 root root 145905152 Aug  4 15:50 nginx.tar
-rw-r--r-- 1 root root      1219 Feb  5  2021 txcdn.sh
1
2
3
4
5
6
7
8
9

步骤三:使用docker load加载镜像

首先我们将镜像删除:docker rmi [镜像名:tag(或者id)]

[root@VM-8-14-centos ~]# docker rmi nginx:latest
Untagged: nginx:latest
Untagged: nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Deleted: sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
Deleted: sha256:b625d8e29573fa369e799ca7c5df8b7a902126d2b7cbeb390af59e4b9e1210c5
Deleted: sha256:7850d382fb05e393e211067c5ca0aada2111fcbe550a90fed04d1c634bd31a14
Deleted: sha256:02b80ac2055edd757a996c3d554e6a8906fd3521e14d1227440afd5163a5f1c4
Deleted: sha256:b92aa5824592ecb46e6d169f8e694a99150ccef01a2aabea7b9c02356cdabe7c
Deleted: sha256:780238f18c540007376dd5e904f583896a69fe620876cabc06977a3af4ba4fb5
Deleted: sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f
1
2
3
4
5
6
7
8
9
10

然后我们可以通过load命令来加载镜像了。

执行docker load -i [文件名]

[root@VM-8-14-centos ~]# docker load -i nginx.tar
2edcec3590a4: Loading layer [==================================================>]  83.86MB/83.86MB
e379e8aedd4d: Loading layer [==================================================>]     62MB/62MB
b8d6e692a25e: Loading layer [==================================================>]  3.072kB/3.072kB
f1db227348d0: Loading layer [==================================================>]  4.096kB/4.096kB
32ce5f6a5106: Loading layer [==================================================>]  3.584kB/3.584kB
d874fd2bc83b: Loading layer [==================================================>]  7.168kB/7.168kB
Loaded image: nginx:latest

1
2
3
4
5
6
7
8
9

# 容器相关命令

image-20220804161330891

暂停:系统会将容器进程挂起,将容器关联的内存暂存起来,恢复之后,接着被运行。

停止:系统将进程杀死,将内存回收。start之后,会重新创建全新的进程。

# 创建一个容器

步骤一:去docker hub查看Nginx的容器运行命令命令

docker run --name containerName -p 80:80 -d nginx
1

解读:

  • docker run :创建并运行一个容器
  • --name : 给容器起一个名字,比如叫做mn
  • -p :将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口
  • -d:后台运行容器
  • nginx:镜像名称,例如nginx

image-20220804162501382

通过以下命令来创建一个容器:

docker run --name mn -p 80:80 -d nginx
1
[root@VM-8-14-centos ~]# docker run --name mn -p 80:80 -d nginx
9b0adfd41703d6ceec00396bcaf52c8dd9bc6a5371c1e1052d7169fb9069e0e5
docker: Error response from daemon: driver failed programming external connectivity on endpoint mn (e4a71cb76504ad0921984b224a6289bb07d497c490344440d40396182ade2bb7): Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use.
1
2
3

以上是报错信息,因为端口号被占用,使用另外的端口就行了。

[root@VM-8-14-centos ~]# docker run --name mn -p 81:80 -d nginx
15c2c5c87c8d81150a244014beb60e977ae8e8be0b987b109fda82f3f11b8427
1
2

创建成功之后,通过ip加上代理的port端口号便可访问:

image-20220804165610178

可以使用docker logs [容器名称]查看日志

[root@VM-8-14-centos ~]# docker logs mn
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/08/04 08:53:04 [notice] 1#1: using the "epoll" event method
2022/08/04 08:53:04 [notice] 1#1: nginx/1.21.5
2022/08/04 08:53:04 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
2022/08/04 08:53:04 [notice] 1#1: OS: Linux 3.10.0-1160.49.1.el7.x86_64
2022/08/04 08:53:04 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/08/04 08:53:04 [notice] 1#1: start worker processes
2022/08/04 08:53:04 [notice] 1#1: start worker process 32
2022/08/04 08:53:04 [notice] 1#1: start worker process 33
112.94.13.13 - - [04/Aug/2022:08:55:26 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36" "-"
112.94.13.13 - - [04/Aug/2022:08:55:26 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://43.138.140.213:81/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36" "-"
2022/08/04 08:55:26 [error] 33#33: *2 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 112.94.13.13, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "43.138.140.213:81", referrer: "http://43.138.140.213:81/"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

持续的日志输出

因为上述的日志是要自己手动获取的,不太方便于调试。

我们可以执行docker logs -f [容器名]

# 进入容器,修改内容

步骤一:进入容器。进入我们刚刚创建的nginx容器的命令为:

docker exec -it [容器名称] bash
1

命令解读:

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

进入后会发现,前置的编号就是容器的ID:

[root@VM-8-14-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                               NAMES
15c2c5c87c8d   nginx     "/docker-entrypoint.…"   8 minutes ago   Up 8 minutes   0.0.0.0:81->80/tcp, :::81->80/tcp   mn
[root@VM-8-14-centos ~]# docker exec -it mn bash
root@15c2c5c87c8d:/# 

1
2
3
4
5
6

我们试试看执行ls命令,会发现其目录的结构和Linux基本一样:

root@15c2c5c87c8d:/# ls
bin   dev		   docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc			 lib   media  opt  root  sbin  sys  usr
1
2
3

但是,这些文件,只有与nginx有关的才是有意义的。

那么我们怎么知道nginx的文件放在哪一个文件下呢?我们不知道。不过我们可以借助dockerhub官网查看。

Alternatively, a simple Dockerfile can be used to generate a new image that includes the necessary content (which is a much cleaner solution than the bind mount above):

FROM nginx
COPY static-html-directory /usr/share/nginx/html
1
2

我们可以知道,nginx的静态资源存放在了/usr/share/nginx/html下。

我们进入路径下,查看路径文件,可以看到有两个html文件

root@15c2c5c87c8d:/# cd /usr/share/nginx/html
root@15c2c5c87c8d:/usr/share/nginx/html# ls
50x.html  index.html
1
2
3

我们执行以下命令,可以直接修改文件中的内容:

sed -i 's#Welcome to nginx#早睡蛋学docker#g' index.html
sed -i 's#<head>#<head><meta charset="utf-8">#g' index.html
1
2

image-20220805135556391

# 退出容器

# 命令
exit
1
2

# 停止容器

# 命令
docker stop [容器名]
1
2

# 删除容器

# 命令
docker rm [容器名]
1
2

注意,删除前要先停止容器,不然删除不了:

[root@VM-8-14-centos ~]# docker rm mn
Error response from daemon: You cannot remove a running container 15c2c5c87c8d81150a244014beb60e977ae8e8be0b987b109fda82f3f11b8427. Stop the container before attempting removal or force remove
1
2

我们可以使用强制删除命令来删除,这样就不用每次都先停再删了。

docker rm -f [容器名]
1

# Docker运行Redis容器

# 目的

创建并运行一个Redis容器,并且支持数据持久化

# 步骤

  • 步骤一:到DockerHub搜索Redis镜像

    https://hub.docker.com/_/redis (opens new window)

  • 步骤二:查看Redis镜像文档中的帮助信息

    启动redis容器

    $ docker run --name some-redis -d redis
    
    1

    start with persistent storage(持久化开启)

    $ docker run --name some-redis -d redis redis-server --save 60 1 --loglevel warning
    
    1

    There are several different persistence strategies to choose from. This one will save a snapshot of the DB every 60 seconds if at least 1 write operation was performed (it will also lead to more logs, so the loglevel option may be desirable). If persistence is enabled, data is stored in the VOLUME /data, which can be used with --volumes-from some-volume-container or -v /docker/host/dir:/data (see docs.docker volumes (opens new window)).

    For more about Redis Persistence, see http://redis.io/topics/persistence.

    一般我们在run的时候需要指定一下端口,所以命令修改为:

    docker run --name mr -p 6378:6379 -d redis redis-server --save 60 1 --loglevel warning
    
    1
  • 步骤三:利用docker run 命令运行一个Redis容器

# 进入redis容器,并执行redis-cli客户端命令,存入num=666

  • 进入容器
[root@VM-8-14-centos ~]# docker exec -it mr bash
root@6cba24a415a9:/data#
1
2
  • 执行redis-cli客户端命令,查看所有键值对
root@6cba24a415a9:/data# redis-cli
127.0.0.1:6379> keys *
(empty array)
1
2
3
  • 设置数据num=666
127.0.0.1:6379> set num 666
OK
127.0.0.1:6379> keys *
1) "num"
1
2
3
4

以上命令可以一步到位:

docker exec -it [容器名] redis-cli
1

# Docker数据卷

# 容器与数据耦合的问题

image-20220805142941080

# 数据卷

数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的某个目录。

image-20220805143127981

# 操作数据卷

数据卷操作的基本语法如下:

docker volume [COMMAND]
1

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

  • create 创建一个volume
  • inspect 显示一个或多个volume的信息
  • ls 列出所有的volume
  • prune 删除未使用的volume
  • rm 删除一个或多个指定的volume

# 创建一个数据卷,并查看数据卷在宿主机的目录位置

创建数据卷

docker volume create html
1

查看所有数据卷

docker volume ls
1

查看数据卷的详细信息

docker volume inspect html
1
[root@VM-8-14-centos ~]# docker volume inspect html
[
    {
        "CreatedAt": "2022-08-05T14:40:01+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/html/_data",
        "Name": "html",
        "Options": {},
        "Scope": "local"
    }
]
1
2
3
4
5
6
7
8
9
10
11
12

其中,存储目录(挂载点)为:

"Mountpoint": "/var/lib/docker/volumes/html/_data",
# /_data为真实存储的
1
2

# 挂载数据卷

我们在创建容器时,可以通过 -v 参数来挂载一个数据卷到某个容器目录

docker run \
  --name mn \
  -v html:/root/html \
  -p 8080:80
  nginx \
1
2
3
4
5
  • docker run :就是创建并运行容器
  • -- name mn :给容器起个名字叫mn
  • -v html:/root/htm :把html数据卷挂载到容器内的/root/html这个目录中
  • -p 8080:80 :把宿主机的8080端口映射到容器内的80端口
  • nginx :镜像名称

# 挂载案例

需求说明:上个案例中,我们进入nginx容器内部,已经知道nginx的html目录所在位置/usr/share/nginx/html ,我们需要把这个目录挂载到html这个数据卷上,方便操作其中的内容。

提示:运行容器时使用 -v 参数挂载数据卷

步骤:

  • 创建容器并挂载数据卷到容器内的HTML目录
docker run --name mn -p 81:80 -v html:/usr/share/nginx/html -d nginx
1
  • 进入html数据卷所在位置,并修改HTML内容
# 查看html数据卷的位置
docker volume inspect html
# 进入该目录
cd /var/lib/docker/volumes/html/_data
# 修改文件
vi index.html
1
2
3
4
5
6

我们进入数据卷的目录位置,可以看到,也有两个文件,此时并没有进入容器内部,所以说明我们挂载成功。

[root@VM-8-14-centos ~]# cd /var/lib/docker/volumes/html/_data
[root@VM-8-14-centos _data]# ls
50x.html  index.html
1
2
3

我们进入index.html文件内进行内容修改,修改完成后,我们要证明确实在容器内也保存成功,我们可以直接打开浏览器查看,确实是修改成功了。

image-20220805150627188

中文乱码的在head标签内加上meta charset="utf-8"即可

另外

如果我们把数据卷删掉,我们在运行新的容器时,将他挂载到一个不存在的卷时,docker会帮我们自动创建这个数据卷。

# 挂载案例2

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

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

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

实现思路如下:

  • 将mysql.tar文件上传到服务器,通过load命令加载为镜像
docker load -i mysql.tar
1
  • 创建目录/tmp/mysql/data
mkdir -p mysql/data
1
  • 创建目录/tmp/mysql/conf,将hmy.cnf文件上传到/tmp/mysql/conf
mkdir -p mysql/conf
1
  • 去DockerHub查阅资料,创建并运行MySQL容器,要求:

    1.挂载/tmp/mysql/data到mysql容器内数据存储目录

    2.挂载/tmp/mysql/conf/hmy.cnf到mysql容器的配置文件

    3.设置MySQL密码

https://hub.docker.com/_/mysql (opens new window)

-e:环境变量,可以让我们一个命令就设置密码

记得开放对应端口

docker run \
 --name mysql \
 -e MYSQL_ROOT_PASSWORD=123 \
 -p 3307:3306 \
 -v /tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \
 -v /tmp/mysql/data:/var/lib/mysql \
 -d \
 mysql:5.7.25
1
2
3
4
5
6
7
8

关于两个冒号后面的路径,我们查阅官网可知:

conf配置文件在路径:

The default configuration for MySQL can be found in /etc/mysql/my.cnf, which may !includedir additional directories such as /etc/mysql/conf.d or /etc/mysql/mysql.conf.d. Please inspect the relevant files and directories within the mysql image itself for more details.

data文件在路径:

/var/lib/mysql

# 数据挂载的方式对比

image-20220805162556746

docker run的命令中通过 -v 参数挂载文件或目录到容器中:

  1. -v volume名称:容器内目录
  2. -v 宿主机文件:容器内文件
  3. -v 宿主机目录:容器内目录

数据卷挂载与目录直接挂载

  1. 数据卷挂载耦合度低,由docker来管理目录,但是目录较深,不好找
  2. 目录挂载耦合度高,需要我们自己管理目录,不过目录容易寻找查看

# Docker镜像结构

镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。

image-20220805163300868

# 自定义镜像(Dockerfile)

Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。

image-20220805163800476

语法说明,请参考官网文档: https://docs.docker.com/engine/reference/builder (opens new window)

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

实现思路如下:

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

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

  3. 编写Dockerfile文件:

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

    将app.jar拷贝到镜像中

    暴露端口

    编写入口ENTRYPOINT

  4. 使用docker build命令构建镜像

  5. 使用docker run创建容器并运行

Dockerfile文件:

# 指定基础镜像
FROM java:8-alpine

# 拷贝java项目的包
COPY ./docker-demo.jar /tmp/app.jar

# 暴露端口
EXPOSE 8090
# 入口,java项目的启动命令
ENTRYPOINT java -jar /tmp/app.jar
1
2
3
4
5
6
7
8
9
10

使用build命令构建镜像:

[root@VM-8-14-centos docker-demo]# docker build -t javaweb:1.0 .
1

注意:记得要加 . 这个点代表的是dockerfile文件所在的目录。

构建好了之后,我们可以run一下镜像了。

docker run --name web -p 8090:8090 -d javaweb:1.0
1

image-20220805170818923

# DockerCompose

# 什么是DockerCompose

  • Docker Compose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器!
  • Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。
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"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

DockerCompose的详细语法参考官网:https://docs.docker.com/compose/compose-file/ (opens new window)

# 安装DockerCompose

上传到/usr/local/bin/目录。Linux下需要通过命令下载:

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

# 修改文件权限

修改文件权限:

# 修改权限
chmod +x /usr/local/bin/docker-compose
1
2

# Base自动补全命令

# 补全命令
curl -L https://raw.githubusercontent.com/docker/compose/1.29.1/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
1
2

如果这里出现错误,需要修改自己的hosts文件:

echo "199.232.68.133 raw.githubusercontent.com" >> /etc/hosts
1

# DockerCompose部署微服务

实现思路如下:

  • 编写docker-compose文件
  • 修改自己的cloud-demo项目,将数据库、nacos地址都命名为docker-compose中的服务名
  • 使用maven打包工具,将项目中的每个微服务都打包为app.jar
  • 将打包好的app.jar拷贝到cloud-demo中的每一个对应的子目录中
  • 将cloud-demo上传至虚拟机,利用 docker-compose up -d 来部署