docker入门详细笔记

这个笔记是狂神说的docker基础篇视频的对应的笔记:https://www.bilibili.com/video/BV1og4y1q7M4
进阶视频:https://www.bilibili.com/video/BV1kv411q7Qc
转载链接:Oddfar Note ;有一说一,他们的博客是真滴好看
也可参考:https://www.pdai.tech/md/devops/docker/docker-01-docker-vm.html

Docker安装

我们使用的是 CentOS 7 (64-bit)

Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。

查看自己的内核:

用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型 等)。

uname -r

查看版本信息:

cat /etc/os-release

安装步骤

官网安装参考手册:https://docs.docker.com/engine/install/centos/

  1. yum安装gcc相关环境(需要确保虚拟机可以上外网 )

    yum -y install gcc
    yum -y install gcc-c++
    
  2. 卸载旧版本

    sudo yum remove docker \
                      docker-client \
                      docker-client-latest \
                      docker-common \
                      docker-latest \
                      docker-latest-logrotate \
                      docker-logrotate \
                      docker-engine
    
  3. 安装需要的软件包

    sudo yum install -y yum-utils
    
  4. 设置镜像仓库

    官网(国外):

    sudo yum-config-manager \
        --add-repo \
        https://download.docker.com/linux/centos/docker-ce.repo
    

    阿里云(推荐):

    sudo yum-config-manager \
        --add-repo \
    	http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
  5. 更新yum软件包索引

    yum makecache fast
    
  6. 安装 Docker CE

    yum install docker-ce docker-ce-cli containerd.io
    
  7. 启动 Docker

    systemctl start docker
    

    至此,已经安装完

  • 查看版本

    docker version
    
  • 查看安装的镜像

    docker images
    
  • 测试运行hello

    docker run hello-world
    

卸载docker

systemctl stop docker
yum -y remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker

阿里云镜像加速

介绍:https://www.aliyun.com/product/acr

查看自己的镜像加速器并配置

阿里云镜像加速

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://cbl6xdl3.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

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

image-20210603160745479

测试 HelloWorld

启动hello-world

docker run hello-world

run干了什么?

img_18

Docker - 常用命令

帮助命令

docker version # 显示 Docker 版本信息。
docker info # 显示 Docker 系统信息,包括镜像和容器数。
docker --help # 帮助

镜像命令

docker images

列出本地主机上的镜像

image-20210603161520609

解释:

  • REPOSITORY 镜像的仓库源
  • TAG 镜像的标签
  • IMAGE ID 镜像的ID
  • CREATED 镜像创建时间
  • SIZE 镜像大小

同一个仓库源可以有多个 TAG,代表这个仓库源的不同版本,我们使用 REPOSITORY:TAG 定义不同的镜像,如果你不定义镜像的标签版本,docker将默认使用 latest 镜像!

docker search

搜索镜像:

docker search 某个镜像的名称 对应DockerHub仓库中的镜像

docker search mysql

可选项:

列出收藏数不小于指定值的镜像,例如

docker search mysql --filter=stars=1000

image-20210603161853652

  • NAME: 镜像仓库源的名称
  • DESCRIPTION: 镜像的描述
  • OFFICIAL: 是否 docker 官方发布
  • STARS: 类似 Github 里面的 star,表示点赞、喜欢的意思。
  • AUTOMATED: 自动构建。

也通过Docker Hub 进行查找

比如https://hub.docker.com/search?q=mysql&type=image

docker pull

下载镜像

不写tag,默认是latest

docker pull mysql

指定版本下载

docker pull mysql:5.7

docker rmi

删除镜像

docker rmi -f 镜像id # 删除单个
docker rmi -f 镜像名:tag 镜像名:tag # 删除多个

删除全部

docker rmi -f $(docker images -qa)

容器命令

有镜像才能创建容器,我们这里使用 centos 的镜像来测试,就是虚拟一个 centos !

docker pull centos

容器启动

docker run [OPTIONS] IMAGE [COMMAND][ARG...]

常用参数说明

参数说明
–name=“Name”给容器指定一个名字 之后再对容器操作,可以用这个name,相当于“别名”
-d后台方式运行容器,并返回容器的id!
-i以交互模式运行容器,通过和 -t 一起使用
-t给容器重新分配一个终端,通常和 -i 一起使用
-P随机端口映射(大写)
-p指定端口映射(小写),一般可以有四种写法
-p 指定容器的端口  -p 8080:8080
      -p ip:主机端口:容器端口
      -p 主机端口:容器端口(常用)
      -p 容器端口
      容器端口

查看镜像:

image-20210603162841857

启动一个容器,使用centos进行用交互模式启动容器,在容器内执行/bin/bash命令!

docker run -it centos /bin/bash

image-20210603163129380

退出容器:

image-20210603163202927

容器查看

docker ps [OPTIONS]

常用参数说明

参数说明
-a列出当前所有正在运行的容器 + 历史运行过的容器
-l显示最近创建的容器
-n=?显示最近n个创建的容器
-q静默模式,只显示容器编号。

退出容器

指令说明
exit容器停止退出
ctrl+P+Q容器不停止退出

启动停止容器

指令说明
docker start (容器id or 容器名)启动容器
docker restart (容器id or 容器名)重启容器
docker stop (容器id or 容器名)停止容器
docker kill (容器id or 容器名)强制停止容器

删除容器

指令说明
docker rm 容器id删除指定容器,不能删除正在运行的容器,如果要强制删除使用rm -f
docker rm -f $(docker ps -a -q)删除所有容器
docker ps -a -q | xargs docker rm删除所有容器

容器再启动

docker start id/name

启动之前停止关闭的容器

后台启动容器

docker run -d 容器名

启动centos,使用后台方式启动,例如:

docker run -d centos

问题: 使用docker ps 查看,发现容器已经退出了!

解释:Docker容器后台运行,就必须有一个前台进程,容器运行的命令如果不是那些一直挂起的命令,就会自动退出。

比如,你运行了nginx服务,但是docker前台没有运行应用,这种情况下,容器启动后,会立即自杀,因为他觉得没有程序了,所以最好的情况是,将你的应用使用前台进程的方式运行启动。

清理停止的容器

清理停止的容器:

docker container prune

image-20210604202728156

查看日志

docker logs -f -t --tail 容器id

例子:我们启动 centos,并编写一段脚本来测试玩玩!最后查看日志

docker run -d centos /bin/sh -c "while true;do echo hello;sleep 1;done"

image-20210603174412524

查看日志:

docker logs 容器id
参数说明
-t显示时间戳
-f打印最新的日志
–tail数字显示多少条!
docker logs -tf --tail 10 87f5e5a2954e

image-20210603174510568

  • 停止运行
docker stop 87f5e5a2954e

image-20210603175026851

  • 查看正在运行容器的进程信息
docker top 容器id
  • 查看容器/镜像的元数据
docker inspect 容器id

image-20210603175638262

进入正在运行的容器

命令一:

docker exec -it 容器id bashShell

例如:

[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@VM-0-6-centos ~]# docker run -d centos /bin/sh -c "while true;do echo hello;sleep 1;done"
a9b967bdbc870bb039b69c76ddc3d3ce6aa87d57c51a8040e32224fb45576b28
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
a9b967bdbc87   centos    "/bin/sh -c 'while t…"   8 seconds ago   Up 7 seconds             upbeat_haibt
[root@VM-0-6-centos ~]# docker exec -it a9b967bdbc87 /bin/bash
[root@a9b967bdbc87 /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10:01 ?        00:00:00 /bin/sh -c while true;do echo hello;sleep 1;done
root        37     0  0 10:02 pts/0    00:00:00 /bin/bash
root        59     1  0 10:02 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root        60    37  0 10:02 pts/0    00:00:00 ps -ef

退出容器终端,不会导致容器的停止

[root@a9b967bdbc87 /]# exit
exit
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
a9b967bdbc87   centos    "/bin/sh -c 'while t…"   7 minutes ago   Up 7 minutes             upbeat_haibt

命令二:

docker attach 容器id

测试:

[root@VM-0-6-centos ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    d1165f221234   2 months ago   13.3kB
centos        latest    300e315adb2f   5 months ago   209MB
[root@VM-0-6-centos ~]# docker  run -it -d  centos /bin/bash
7f9ead6f906b3c691d29866236414e1808d194462ed0839c8ee5c947d731ed57
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS         PORTS     NAMES
7f9ead6f906b   centos    "/bin/bash"   10 seconds ago   Up 9 seconds             nervous_mcclintock
[root@VM-0-6-centos ~]# docker attach 7f9ead6f906b
[root@7f9ead6f906b /]# echo "hello"
hello
[root@7f9ead6f906b /]# exit
exit
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@VM-0-6-centos ~]# 

区别 :

  • docker exec 是在容器中打开新的终端,并且可以启动新的进程
  • docker attach 直接进入容器启动命令的终端,不会启动新的进程

推荐大家使用 docker exec 命令

容器内拷贝文件到主机上

docker cp 容器id:容器内路径 目的主机路径

例如:将容器中的f1文件拷贝出到 虚拟机的/home目录

docker cp 7f9ead6f906b:/home/f1 /home

常用命令总结

img_29

命令官方说明解释
attachAttach local standard input, output, and error streams to a running container当前 shell 下 attach 连接指定运行镜像
buildBuild an image from a Dockerfile通过 Dockerfile 定制镜像
commitCreate a new image from a container’s changes提交当前容器为新的镜像
cpCopy files/folders between a container and the local filesystem从容器中拷贝指定文件或者目录到宿主机中
createCreate a new container创建一个新的容器,同 run,但不启动容器
diffInspect changes to files or directories on a container’s filesystem查看 docker 容器变化
eventsGet real time events from the server从 docker 服务获取容 器实时事件
execRun a command in a running container在已存在的容器上运行命令
exportExport a container’s filesystem as a tar archive导出容器的内 容流作为一个 tar 归档文件[对应 import ]
historyShow the history of an image展示一个镜像形成历史
imagesList images列出系统当前镜像
importImport the contents from a tarball to create a filesystem image从 tar包中的内容创建一个新的文件系统映像[对应export]
infoDisplay system-wide information显示系统相关信息
inspectReturn low-level information on Docker objects查看容器详细信息
killKill one or more running containers杀掉 指定 docker 容器
loadLoad an image from a tar archive or STDIN从一个 tar 包中加载一 个镜像[对应 save]
loginLog in to a Docker registry登陆一个 docker 源服务器
logoutLog out from a Docker registry从当前 Docker registry 退出
logsFetch the logs of a container输出当前容器日志信息
pausePause all processes within one or more containers暂停容器
portList port mappings or a specific mapping for the container查看映射端口对应的容器内部源端口
psList containers列出容器列表
pullPull an image or a repository from a registry从docker镜像源服务器拉取指定镜像或者库镜像
pushPush an image or a repository to a registry推送指定镜像或者库镜像至docker源服务器
renameRename a container给一个容器改名
restartRestart one or more containers重启运行的容器
rmRemove one or more containers移除一个或者多个容器
rmiRemove one or more images移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
runRun a command in a new container创建一个新的容器并运行 一个命令
saveSave one or more images to a tar archive (streamed to STDOUT by default)保存一个镜像为一个 tar 包[对应 load]
searchSearch the Docker Hub for images在 docker hub 中搜 索镜像
startStart one or more stopped containers启动容器
statsDisplay a live stream of container(s) resource usage statistics显示容器资源使用统计信息的实时信息
stopStop one or more running containers停止容器
tagCreate a tag TARGET_IMAGE that refers to SOURCE_IMAGE给源中镜像打标签
topDisplay the running processes of a container查看容器中运行的进程信 息
unpauseUnpause all processes within one or more containers取消暂停容器
updateUpdate configuration of one or more containers更新容器配置
versionShow the Docker version information查看 docker 版本号
waitBlock until one or more containers stop, then print their exit codes截取容器停止时的退出状态值

Docker安装练习

练习

安装nginx

拉取镜像:

$ docker pull nginx

pull
启动容器:

-d 后台启动

  • 3500为外网访问地址:注意阿里云开放端口以及开防火墙firewall-cmd --zone=public --add-port=3500/tcp --permanent
  • 重启防火墙firewall-cmd --reload
docker run -d --name mynginx -p 3500:80 nginx

本机测试:curl localhost:3500

curl

进入容器:

[root@VM-0-6-centos ~]# docker exec -it mynginx /bin/bash
# 寻找nginx
root@511741b161de:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@511741b161de:/# cd /usr/share/nginx
root@511741b161de:/usr/share/nginx# ls
html
root@511741b161de:/usr/share/nginx# cd html
root@511741b161de:/usr/share/nginx/html# ls
50x.html  index.html
#可看到之前访问的内容是 index.html
root@511741b161de:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

安装tomcat

在 docker hub 官网搜索 tomcat:https://hub.docker.com/_/tomcat

翻到下面有教程

docker run -it --rm tomcat:9.0   # 仅测试使用:关闭之后使用docker ps 找不到
  • -it :交互模式
  • –rm:容器启动成功并退出以后容器就自动移除,一般只在测试情况下使用!

1、下载tomcat镜像:

docker pull tomcat

2、启动

docker run -d -p 8080:8080 --name tomcat9 tomcat

3、进入tomcat

docker exec -it tomcat9 /bin/bash

进入后发现,webapps 里什么也没有,默认是最小的镜像,所有不必要的剔除。

root@a1801a340333:/usr/local/tomcat# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work
root@a1801a340333:/usr/local/tomcat# cd webapps
root@a1801a340333:/usr/local/tomcat/webapps# ls
root@a1801a340333:/usr/local/tomcat/webapps# 

若部署一个 jsp 网站,需要把文件复制到容器里,非常麻烦。

我们可以通过“数据卷”技术,将容器内文件和我们 Linux 文件进行映射挂载。

部署ElasticSearch

官网:https://hub.docker.com/_/elasticsearch

1、启动:

docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

2、查看状态

  • docker stats 容器id

    查看容器的cpu内存和网络状态

查看下cpu状态 ,发现占用的很大

3、增加上内存限制启动

docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2

启动时,报错:名字已经存在

image-20210604143740445

可通过指令删除

  • docker rm name_of_the_docker_container
docker rm elasticsearch

我们可通过 docker ps -a显示所有容器信息

再次启动后,发现内存变小了

访问成功:

[root@VM-0-6-centos ~]# curl localhost:9200
{
  "name" : "d49fb1463f0a",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "ycGNdXS0TpC2lcOfIFlPkQ",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

关于名字的作用:

以后我们想启动上次配置的 ElasticSearch,用 docker start 容器名字 即可,不需要在重新配置

[root@VM-0-6-centos ~]# docker start elasticsearch
elasticsearch
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED             STATUS         PORTS                                                                                  NAMES
d49fb1463f0a   elasticsearch:7.6.2   "/usr/local/bin/dock…"   About an hour ago   Up 5 seconds   0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp   elasticsearch
[root@VM-0-6-centos ~] # 

如果我们要使用 kibana , 如果配置连接上我们的es呢?网络该如何配置呢?

img_34

可视化

Portainer(Rancher)是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷 的基本操作(包括上传下载镜像,创建容器等操作)、事件日志显示、容器控制台操作、Swarm集群和 服务等集中管理和操作、登录用户管理和控制等功能。功能十分全面,基本能满足中小型单位对容器管理的全部需求。

如果仅有一个docker宿主机,则可使用单机版运行,Portainer单机版运行十分简单,只需要一条语句即可启动容器,来管理该机器上的 docker 镜像、容器等数据。

  • 安装并运行Portainer:
docker run -d -p 8088:9000 
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
  • 访问:

http://IP:8088

首次加载比较慢,且登陆需要注册用户,给admin用户设置密码:

单机版这里选择local即可,选择完毕,点击Connect即可连接到本地docker:

Docker 镜像和仓库

Docker镜像

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含 运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

Docker镜像加载原理

UnionFS (联合文件系统)

UnionFS 是一种分层、轻量级并且高性能的文件系统, 它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

典型的Linux文件系统由bootfsrootfs两部分组成

bootfs(boot file system)主要包含 bootloader 和 kernel , bootloader 主要是引导加载 kernel, Linux 刚启动时会加载bootfs文件系统,在Docker镜像的最底层是 bootfs。这一层与我们典型的 Linux/Unix 系统是 一样的,包含boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs。

rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

img_41

平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?

image-20210604172626563

对于一个精简的系统,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就可以了。由此可见对于不同的 linux 发行版, bootfs 基本是一 致的, rootfs 会有差别, 因此不同的发行版可以公用 bootfs。

分层理解

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!

为什么Docker镜像要采用这种分层的结构呢?

最大的好处,莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

查看镜像分层的方式可以通过 docker image inspect命令!

docker image inspect tomcat:latest

image-20210604174631340

所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

img_46

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了 一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。

img_47

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件 7 是文件 5 的一个更新版本。

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。

Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统 一的文件系统。

Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW。

下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

img_50

特点:

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层!

提交镜像

docker commit 从容器创建一个新的镜像。

  • 语法:

    docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
    

测试

1、从Docker Hub 下载 tomcat 镜像到本地并运行

-it 交互终端 -p 端口映射

docker run -it -p 8080:8080 tomcat

2、访问地址

docker启动官方tomcat镜像的容器,发现404是因为使用了加速器,而加速器里的 tomcat的webapps下没有root等文件!

[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND             CREATED         STATUS         PORTS                                       NAMES
a8b6aff64fa3   tomcat    "catalina.sh run"   8 minutes ago   Up 8 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   silly_feynman
[root@VM-0-6-centos ~]# docker exec -it a8b6aff64fa3 /bin/bash
root@a8b6aff64fa3:/usr/local/tomcat# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work

进入 tomcat 查看 cd 到 webapps 下发现全部空的,反而有个 webapps.dist 里有对应文件

root@a8b6aff64fa3:/usr/local/tomcat# cd webapps.dist
root@a8b6aff64fa3:/usr/local/tomcat/webapps.dist# ls
ROOT  docs  examples  host-manager  manager

我们可以 cp -r 复制文件到webapps下!

root@a8b6aff64fa3:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@a8b6aff64fa3:/usr/local/tomcat# cd webapps
root@a8b6aff64fa3:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager

此时再次访问,则不是404

**3、提交修改后的镜像为 tomcat02 **

下次则可以直接启动这个

注意:commit的时候,容器的名字不能有大写,否则报错:invalid reference format

[root@VM-0-6-centos ~]# docker ps -l
CONTAINER ID   IMAGE     COMMAND             CREATED          STATUS          PORTS                                       NAMES
a8b6aff64fa3   tomcat    "catalina.sh run"   16 minutes ago   Up 16 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   silly_feynman
##提交镜像
[root@VM-0-6-centos ~]# docker commit -a="zhiyuan" -m="new tomcat" a8b6aff64fa3 tomcat02:1.1
sha256:620813976effbc8a7e36398a9b801891d1654dea37a50927b36a950ffe21a63b
[root@VM-0-6-centos ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
tomcat02              1.1       620813976eff   8 seconds ago   672MB

停止后再启动看看,首页可访问

[root@VM-0-6-centos ~]# docker stop a8b6aff64fa3
a8b6aff64fa3
[root@VM-0-6-centos ~]# docker run -it -p 8080:8080 tomcat02:1.1

Docker 仓库

DockerHub

注册dockerhub https://hub.docker.com/signup

1、登录

docker login -u oddfar

2、将镜像发布出去

[root@VM-0-6-centos logs]# docker push hello-world
Using default tag: latest
The push refers to repository [docker.io/library/hello-world]
f22b99068db9: Layer already exists 
errors:
denied: requested access to the resource is denied
unauthorized: authentication required

错误:请求的资源访问被拒绝

问题:本地镜像名无帐号信息,解决加 tag 即可

[root@VM-0-6-centos logs]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED             SIZE
hello-world           latest  	  d1165f221234   3 months ago        13.3kB
[root@VM-0-6-centos logs]# docker tag d1165f221234 oddfar(用户名)/hello-world(镜像名):1.08(标签)	

oddfar 是我的用户名

3、再次push

[root@VM-0-6-centos logs]# docker push oddfar/hello-world:1.0

访问:https://hub.docker.com/ 可看到提交的镜像

阿里云镜像服务

登录阿里云 -> 找到容器镜像服务 -> 创建命名空间 -> 创建镜像仓库

点击进入这个镜像仓库,可以看到所有的信息

image-20210606192542790
指令:

测试:推送 hello-world

[root@VM-0-6-centos ~]# docker login --username=a_zhiyuan registry.cn-hangzhou.aliyuncs.com
[root@VM-0-6-centos ~]# docker tag d1165f221234 registry.cn-hangzhou.aliyuncs.com/zhiyuan/study:1.0
[root@VM-0-6-centos ~]# docker push registry.cn-hangzhou.aliyuncs.com/zhiyuan/study:1.0

提交成功

Docker 数据卷

什么是数据卷

数据卷(Data Volume)

docker的理念回顾:

将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够 持久化的!

就好比,你安装一个MySQL,结果你把容器删了,就相当于删库跑路了,这TM也太扯了吧!

所以我们希望容器之间有可能可以共享数据,Docker容器产生的数据,如果不通过 docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行不通的!

为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除而丢失了!

作用:

卷就是目录或者文件,存在一个或者多个容器中,由 docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性。

卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷。

特点:

  1. 数据卷可在容器之间共享或重用数据
  2. 卷中的更改可以直接生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续到没有容器使用它为止

一句话: 就是容器的持久化,以及容器间的继承和数据共享!

使用数据卷

指令 v 方式

方式一:容器中直接使用命令来添加

在用 docker run 命令的时候,使用 -v 标记来创建一个数据卷并挂载到容器里。

docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名

测试:

docker run -it -v /home/d-test:/home centos /bin/bash

查看数据卷是否挂载成功 docker inspect 容器id

[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
05fa819084c9   centos    "/bin/bash"   20 seconds ago   Up 20 seconds             friendly_keller
[root@VM-0-6-centos ~]#  docker inspect 05fa819084c9

image-20210605090028768

  • 测试容器和宿主机之间数据共享:可以发现,在容器中,创建的会在宿主机中看到!

容器:

[root@05fa819084c9 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  s
[root@05fa819084c9 /]# cd home
[root@05fa819084c9 home]# ls
[root@05fa819084c9 home]# touch test.java

主机:

[root@VM-0-6-centos ~]# cd /home/d-test
[root@VM-0-6-centos d-test]# ls
test.java
  • 测试容器停止退出后,主机修改数据是否会同步!
  1. 停止容器
  2. 在宿主机上修改文件,增加些内容
  3. 启动刚才停止的容器
  4. 然后查看对应的文件,发现数据依旧同步!

主机:

[root@VM-0-6-centos d-test]# ls
test.java
[root@VM-0-6-centos d-test]# touch new.java
[root@VM-0-6-centos d-test]# ls
new.java  test.java

容器:

docker ps -a 查看所有容器

[root@VM-0-6-centos home]# docker start 05fa819084c9
05fa819084c9
[root@VM-0-6-centos home]# docker attach 05fa819084c9
[root@05fa819084c9 /]# cd /home
[root@05fa819084c9 home]# ls
new.java  test.java

安装 mysql 测试

1、安装

docker pull mysql:5.7

2、启动容器 ,-e 为环境变量

mysql 的数据不应该放在容器内,应放主机内!先体验下 -v 挂载卷!

参考官方文档

docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

连接 mysql 并创建一个数据库

[root@VM-0-6-centos data]# mysql -h 127.0.0.1 -P 3310 -u root -p
mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.00 sec)

文件 Docker File 方式

方式二:通过Docker File 来添加

DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。

这里先了解体验一下,后面有详细介绍

1、编写DockerFile文件

我们在宿主机 /home 目录下新建一个 docker-test-volume文件夹

mkdir docker-test-volume

出于可移植和分享的考虑,之前使用的 -v 主机目录:容器目录 这种方式不能够直接在 DockerFile 中实现。

[root@VM-0-6-centos docker-test-volume]# pwd
/home/docker-test-volume
[root@VM-0-6-centos docker-test-volume]# vim dockerfile1
[root@VM-0-6-centos docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "-------end------"
CMD /bin/bash

说明:在编写DockerFile文件中使用 VOLUME 来给镜像添加一个或多个数据卷

2、build生成镜像

build生成镜像,获得一个新镜像 test-centos,注意最后面有个 .

-f 是指定的dockerFile文件位置;-t是生成的镜像名称

docker build -f /home/docker-test-volume/dockerfile1 -t test-centos .

然后启动容器:

docker run -it test-centos /bin/bash

通过上述步骤,容器内的卷目录地址就已经知道了,但是对应的主机目录地址在哪里呢?

3、查看数据目录

我们在数据卷中新建一个文件

[root@93343e21a67b /]# cd dataVolumeContainer1
[root@93343e21a67b dataVolumeContainer1]# touch container.txt

查看下这个容器的信息

docker inspect 93343e21a67b

可以看到挂载的路径

在主机目录里看到之前在容器里创建的文件

[root@VM-0-6-centos ~]# cd /var/lib/docker/volumes/7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788/_data
[root@VM-0-6-centos _data]# ls
container.txt

注意:如果访问出现了 cannot open directory: Permission denied

解决办法:在挂载目录后多加一个 --privileged=true参数即可

匿名和具名挂载

匿名挂载

-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

可通过命令 docker volume ls 查看挂载的列表

[root@VM-0-6-centos ~]# docker volume ls
DRIVER    VOLUME NAME
local     4d0221bc0d8b9e44fb2e878cd3efcacb9b4bd51c8e135d79c549f7a6345f3a24
local     7a1e6924fed1cc5ea6a386d9b2542c0ffc53fada1755bc7d09601274dff6ddd0
local     7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788
local     adaa3053cb2ff95afc7bab51451f4b1167aa1b9056398ed44b0d4cae9580db52

这些没指定名字的都是匿名挂载,我们 -v 只写了容器内路径,并没写容器外路径

挂载目录是: /var/lib /docker/volumes/VOLUME-NAME/_data

匿名挂载的缺点,就是不好维护,不清楚目录挂载的是哪个容器

具名挂载

-v 卷名:/容器内路径

例如取名为 juming 来挂载

[root@VM-0-6-centos ~]# docker run -d -P --name nginx02 -v juming:/etc/nginx nginx
112f36599f077eada56197c22dd3b3a3eaba2e5bb38bf2cb19adc783163991e7 
[root@VM-0-6-centos ~]# docker volume ls
DRIVER    VOLUME NAME
local     4d0221bc0d8b9e44fb2e878cd3efcacb9b4bd51c8e135d79c549f7a6345f3a24
local     7a1e6924fed1cc5ea6a386d9b2542c0ffc53fada1755bc7d09601274dff6ddd0
local     7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788
local     adaa3053cb2ff95afc7bab51451f4b1167aa1b9056398ed44b0d4cae9580db52
local     juming   	#(卷名是juming,目录是/etc/nginx)

查看挂载的目录:docker volume VOLUME-NAME

[root@VM-0-6-centos ~]# docker volume inspect juming
[
    {
        "CreatedAt": "2021-06-05T16:32:10+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming/_data",
        "Name": "juming",
        "Options": null,
        "Scope": "local"
    }
]

挂载操作中,没指定目录名情况下,默认在 /var/lib/docker/volumes/ 目录下

  • 改变文件的读写权限

指定容器对我们挂载出来的内容的读写权限

docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx

ro: readonly 只读

rw: readwrite 可读可写

数据卷容器

之前的是主机和容器之间共享数据,那么如何实现容器和容器之间的共享数据呢?

命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享 --volumes-from,挂载数据卷的容器,称之为数据卷容器(Data Volume Container)

测试容器间传递共享

使用之前的镜像:test-centos 为模板,运行容器 docker01(父容器),docker02,docker03

他们都会具有容器卷 /dataVolumeContainer1/dataVolumeContainer2

1、先启动一个父容器docker01,然后在 dataVolumeContainer2 新增文件

[root@VM-0-6-centos _data]# docker run -it --name docker01 test-centos
[root@cd87cb3eb33b /]# ls -l
total 56
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Jun  5 08:56 dataVolumeContainer1
drwxr-xr-x   2 root root 4096 Jun  5 08:56 dataVolumeContainer2
............
[root@cd87cb3eb33b /]# cd dataVolumeContainer2
[root@cd87cb3eb33b dataVolumeContainer2]# touch docker01.txt

退出且不停止容器运行:ctrl+P+Q

2、创建docker02,docker03 让他们继承docker01

可以看到 docker01 创建的文件存在

[root@VM-0-6-centos _data]# docker run -it --name docker02 --volumes-from docker01 test-centos
[root@f81238516f65 /]#  cd dataVolumeContainer2
[root@f81238516f65 dataVolumeContainer2]# ls
docker01.txt
[root@f81238516f65 dataVolumeContainer2]# touch docker02.txt

[root@VM-0-6-centos _data]# docker run -it --name docker03 --volumes-from docker01 test-centos
[root@c8c41a2a0831 /]# ls
bin  dataVolumeContainer1  dataVolumeContainer2  dev  etc  home  lib  lib64  lost+found  media	mnt  opt  proc	root  run  sbin  srv  sys  tmp	usr  var
[root@c8c41a2a0831 /]# cd dataVolumeContainer2
[root@c8c41a2a0831 dataVolumeContainer2]# ls
docker01.txt  docker02.txt

3、回到docker01发现可以看到 02 和 03 添加的共享文件

[root@VM-0-6-centos ~]#  docker attach docker01
[root@cd87cb3eb33b dataVolumeContainer2]# ls -l
total 0
-rw-r--r-- 1 root root 0 Jun  5 08:56 docker01.txt
-rw-r--r-- 1 root root 0 Jun  5 08:58 docker02.txt
-rw-r--r-- 1 root root 0 Jun  5 09:00 docker03.txt

删除 docker01 后 ,docker02 修改文件后, docker03 还可以正常共享数据

容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。 存储在本机的文件则会一直保留!

大家想想,Nginx,tomcat,mysql 这些镜像都是哪里来的?官方能写,我们不能写吗?

我们要研究自己如何做一个镜像,而且我们写的微服务项目以及 springboot 打包上云部署,Docker就是最方便的。

微服务打包成镜像,任何装了Docker的地方,都可以下载使用,极其的方便。

流程:开发应用=>DockerFile=>打包为镜像=>上传到仓库(私有仓库,公有仓库)=> 下载镜像 => 启动 运行。

还可以方便移植!

Docker -DockerFile

什么是 DockerFile

dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本

构建步骤:

1、编写DockerFile文件

2、docker build 构建镜像

3、docker run

查看之前拉取的 centos :https://hub.docker.com/_/centos

image-20210606163702268

查看Dockerfile 文件

image-20210606163720066

DockerFile 构建过程

基础知识:

1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数

2、指令按照从上到下,顺序执行

3、# 表示注释

4、每条指令都会创建一个新的镜像层,并对镜像进行提交

流程:

1、docker从基础镜像运行一个容器

2、执行一条指令并对容器做出修改

3、执行类似 docker commit 的操作提交一个新的镜像层

4、Docker再基于刚提交的镜像运行一个新容器

5、执行dockerfile中的下一条指令直到所有指令都执行完成!

说明:

从应用软件的角度来看,DockerFile,docker镜像 与 docker容器 分别代表软件的三个不同阶段。

  • DockerFile 是软件的原材料 (代码)
  • Docker 镜像则是软件的交付品 (.apk)
  • Docker 容器则是软件的运行状态 (客户下载安装执行)

DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!

DockerFile:需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容 包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进 程和内核进程(当引用进行需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace的权 限控制)等等。

Docker镜像:在DockerFile 定义了一个文件之后,Docker build 时会产生一个Docker镜像,当运行 Docker 镜像时,会真正开始提供服务;

Docker容器:容器是直接提供服务的。

DockerFile 指令

关键字说明
FROM基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER镜像维护者的姓名混合邮箱地址
RUN容器构建时需要运行的命令
EXPOSE当前容器对外保留出的端口
WORKDIR指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV用来在构建镜像过程中设置环境变量
ADD将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY类似ADD,拷贝文件和目录到镜像中!
VOLUME容器数据卷,用于数据保存和持久化工作
CMD指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效!
ENTRYPOINT指定一个容器启动时要运行的命令!和CMD一样
ONBUILD当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的 ONBUILD被触发

CMD 和 ENTRYPOINT 的区别

我们之前说过,两个命令都是指定一个容器启动时要运行的命令

  • CMD

    Dockerfile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换!

  • ENTRYPOINT

    docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!

测试 CMD 命令

1、编写文件

[root@VM-0-6-centos dockerfile-test]# vim dockerfile-cmd-test
[root@VM-0-6-centos dockerfile-test]# cat dockerfile-cmd-test
FROM centos 
CMD [ "ls", "-a" ]

2、构建并运行

docker build -f dockerfile-cmd-test -t cmdtest .

docker run cmdtest


3、如果我们希望用 -l 列表展示信息,我们就需要加上 -l参数

[root@VM-0-6-centos dockerfile-test]#  docker run cmdtest -l
# 发现报错:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.

问题:我们可以看到可执行文件找不到的报错,executable file not found。

之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。

因此这里的 -l 替换了原来的 CMD,而不是添加在原来的 ls -a 后面。

而 -l 根本不是命令,所以自然找不到。

那么如果我们希望加入 -l这参数,我们就必须重新完整的输入这个命令:

docker run cmdtest ls -al

测试 ENTRYPOINT 命令

1、编写文件

[root@VM-0-6-centos dockerfile-test]# vim dockerfile-entrypoint-test
[root@VM-0-6-centos dockerfile-test]# cat dockerfile-entrypoint-test
FROM centos
ENTRYPOINT [ "ls", "-a" ]

2、构建并运行

docker build -f dockerfile-entrypoint-test -t entrypointtest .

docker run entrypointtest

3、测试 -l 参数,发现可以直接使用,这里就是一种追加

我们可以明显的知道 CMD 和 ENTRYPOINT 的区别了

docker run entrypointtest -l

image-20210606171953764

实战测试

CentOS

官方默认的 CentOS 的情况不支持 vimifconfig 指令

我们自己构建一个支持这些指令的镜像

1、编写文件

[root@VM-0-6-centos home]# cd dockerfile-test
[root@VM-0-6-centos dockerfile-test]# ls
my-centos
[root@VM-0-6-centos dockerfile-test]# cat my-centos
FROM centos
MAINTAINER zhiyuan<oddfar@163.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools


EXPOSE 80

CMD echo $MYPATH
CMD echo "----end-----"
CMD /bin/bash

2、构建

命令最后有一个 . 表示当前目录

docker build -f my-centos(文件名) -t mycentos(镜像名):0.1(TAG) .(表示当前目录)

成功后:

3、运行

docker run -it mycentos:1.1

测试后,可以看到,我们自己的新镜像进入之后默认在``/usr/local`并且已经支持 vim 和 ifconfig的命令了

  • 列出镜像的变更历史:

    docker history 镜像名\镜像id

Tomcat

步骤:

  • 将 JDK 和 tomcat 安装的压缩包拷贝/home/build 目录下

  • 新建一个 read.txt 文件

  • 新建一个 Dockerfile 文件

[root@VM-0-6-centos home]# cd build
[root@VM-0-6-centos build]# ls
apache-tomcat-9.0.46.tar.gz  Dockerfile  jdk-8u11-linux-x64.tar.gz  read.txt  tomcat

Dockerfile 内容

FROM centos

MAINTAINER zhiyuan<test@qq.com>
#把宿主机当前上下文的read.txt拷贝到容器/usr/local/路径下
COPY read.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u11-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.46.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#变量
ENV MYPATH /usr/local
#设置工作访问时候的WORKDIR路径,登录落脚点
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.46
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.46
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.46/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.46/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.46/bin/logs/catalina.out

构建镜像:

docker build -t diytomcat .

在此目录下默认构建 Dockerfile 文件,所以不需要带上文件名

启动:

docker run -d  -p 9090:8080 --name mydiytomcat -v /home/build/tomcat/test:/usr/local/apache-tomcat-9.0.46/webapps/test -v /home/build/tomcat/logs/:/usr/local/apache-tomcat-9.0.46/logs --privileged=true diytomcat

备注:Docker挂载主机目录Docker访问出现cannot open directory Permission denied

解决办法:在挂载目录后多加一个–privileged=true参数即可

写个测试网站扔到test目录:

web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="true">

  <display-name>Test</display-name>

</web-app>

a.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
	Hello World!<br/>
	<% System.out.println("-------my docker tomcat-------");%>
</body>
</html>

查看日志:

[root@VM-0-6-centos tomcat]# cd logs
[root@VM-0-6-centos logs]# cat catalina.out

image-20210606174533465

SpingBoot

1、使用 IDEA 构建一个 SpringBoot 项目

2、编写 Controller

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
	    return "hello,world";
    }
}

打包成 jar 包

3、构建镜像

将打包好的 jar 包拷贝到 Dockerfile 同级目录,编写 Dockerfile文件

FROM java:8

# 服务器只有dockerfile和jar在同级目录
COPY *.jar /app.jar

CMD ["--server.port=8080"]

# 指定容器内要暴露的端口
EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]

构建运行

# 构建镜像
docker build -t idea-ks .

# 运行
docker run -d -P --name idea-ks idea-ks

最后测试访问

Docker 网络

理解Docker

查看本地ip ip addr

[root@VM-0-6-centos ~]# ip addr
#lo本机回环地址
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever pr	eferred_lft forever
#eth0:阿里云的私有IP
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:9a:88:4d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.6/20 brd 172.17.15.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe9a:884d/64 scope link 
       valid_lft forever preferred_lft forever
# docker网桥
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:d1:ba:72:7a brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d1ff:feba:727a/64 scope link 
       valid_lft forever preferred_lft forever

Docker 是如何处理容器网络访问的?

我们之前安装ES的时候,留过一个问题,就是安装Kibana的问题,Kibana得指定ES的地址!或者我们实际场景中,我们开发了很多微服务项目,那些微服务项目都要连接数据库,需要指定数据库的url地址,通过ip。但是我们用Docker管理的话,假设数据库出问题了,我们重新启动运行一个,这个时候数据库的地址就会发生变化,docker会给每个容器都分配一个ip,且容器和容器之间是可以互相访问的。 我们可以测试下容器之间能不能ping通过。

[root@VM-0-6-centos ~]# docker run -d -P --name tomcat01 tomcat
# 查看tomcat01的ip地址,docker会给每个容器都分配一个ip!
[root@VM-0-6-centos ~]#  docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0	``
       valid_lft forever preferred_lft forever
# 虚拟机可以和容器ping通!
[root@VM-0-6-centos ~]# ping 172.18.0.2

原因

每一个安装了 Docker 的 linux 主机都有一个 docker0 的虚拟网卡。这是个桥接网卡,使用了 veth-pair 技术!

  • 再次查看主机的 ip addr :本来有三个网络,启动tomcat容器之后,会多了一个网络!

  • 每启动一个容器,linux主机就会多了一个虚拟网卡。

    #启动一个tomcat01,主机的ip地址多了个  25: veth2b7cb71@if24
    #然后我们在tomcat01容器中查看容器的ip  24: eth0@if25
    
    #我们再启动一个tomcat02观察
    [root@VM-0-6-centos ~]# docker run -d -P --name tomcat02 tomcat
    
    # 然后发现linux主机上又多了一个网卡	27: veth4d2bd95@if26
    # 我们看下tomcat02的容器内ip地址是	  26: eth0@if27
    [root@VM-0-6-centos ~]# docker exec -it tomcat02 ip addr
    

    可以发现:只要启动一个容器,就有一对网卡。

    veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。

    正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!

    “Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络结构,比如 OpenStack Neutron。

  • 我们来测试下 tomcat01 和 tomcat02 容器间是否可以互相 ping 通

    [root@VM-0-6-centos ~]# docker exec -it tomcat02 ping 172.18.0.2
    PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
    64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
    

    所以:容器和容器之间是可以互相访问的。

    结论:tomcat1 和 tomcat2 共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是 docker0 网络。 docker 默认会给容器分配一个可用 ip 。

小结

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据 Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网 关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接 通信。

image-20210615232726561

Docker 容器网络就很好的利用了 Linux 虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫 veth pair);

Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。

Link参数

思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?

就像 jdbc:mysql://mysql:3306,这样的话哪怕 mysql 重启,我们也不需要修改配置了!

docker提供了 --link 的操作!

# 我们使用tomcat02,直接通过容器名ping,不使用ip
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat01
# ping 不通
ping: tomcat01: Name or service not known

#我们再启动一个tomcat03,但是启动的时候连接tomcat02
[root@VM-0-6-centos ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
80ed9c4e1f9428598a91c727ed13b7d0534d86d569855d4fb8739baabe5d6b91

#这个时候,我们就可以使用tomcat03 ping通 tomcat02 了
[root@VM-0-6-centos ~]#  docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.092 ms

# tomcat3 ping不通 tomcat1
[root@VM-0-6-centos ~]# docker exec -it tomcat03 ping tomcat01
ping: tomcat01: Name or service not known
# tomcat2 ping不通 tomcat3 反向也ping不通
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

这是为什么呢?

#进入tomcat03中查看下host配置文件
[root@VM-0-6-centos ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
#发现tomcat2直接被写在这里
172.18.0.3	tomcat02 cff25f666b32
172.18.0.4	80ed9c4e1f94

所以这里其实就是配置了一个 hosts 地址而已!

原因:--link 的时候,直接把需要 link 的主机的域名和 ip 直接配置到了 hosts 文件中了

--link 早都过时了,我们不推荐使用!我们可以使用自定义网络的方式

自定义网络

基本概念

指令列表

[root@VM-0-6-centos ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

查看所有网络

[root@VM-0-6-centos ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4b873066daf7   bridge    bridge    local
86da632adad6   elastic   bridge    local
64b606f257e7   host      host      local
34ab4fdb73c0   none      null      local

所有网路模式

网络模式配置说明
bridge模式–net=bridge默认值,在 Docker 网桥 docker0 上为容器创建新的网络栈
none模式–net=none不配置网络,用户可以稍后进入容器,自行配置
container 模式– net=container:name/id容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
host模式–net=host容器和宿主机共享Network namespace
用户自定义–net=自定义网络用户自己使用network相关命令定义网络,创建容器的 时候可以指定为自己定义的网络,就像 elastic

查看一个具体的网络的详细信息

[root@VM-0-6-centos ~]# docker network inspect 4b873066daf7
[
    {
        "Name": "bridge",
        "Id": "4b873066daf7eca3fd7a79ce17b46dff17a89368cb7f43d01c88dd9ee08d9407",
        "Created": "2021-06-11T18:42:36.937993641+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                //默认 docker0 是管理这个子网范围内的。0~16,
                //也就是 255*255,去掉0个255,我们有65534可以分配的ip
                //所以 docker0 网络默认可以支持创建6万多个容器ip不重复
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "220fac5f16f3cf7f2619131502cb6bb4004f334c3b501a0ceff8804c361cf027": {
                "Name": "tomcat01",
                "EndpointID": "d54c9b71aff1843c3a1609de8eaa85785ebddd8a419ea5fae346fb538568946f",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "80ed9c4e1f9428598a91c727ed13b7d0534d86d569855d4fb8739baabe5d6b91": {
                "Name": "tomcat03",
                "EndpointID": "a6dd8dd8ba2b5b341cbed8318a2463a4e28f1059cc848504a409fbf75ae21f4f",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "cff25f666b32df808923a51e14f2f2686fc9aff161e07c188c28ce15d0b38401": {
                "Name": "tomcat02",
                "EndpointID": "b5b18a038166b64a0308cc4a506f543b92d35b9fc50f5758f8d5daccc1df87bd",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

自定义网卡

1、先删除之前创建的 tomcat 镜像以及容器

2、创建容器

但是我们知道默认创建的容器都是 docker0 网卡的

#默认我们不配置网络,也就相当于默认值 --net bridge 使用的docker0
docker run -d -P --name tomcat01 --net bridge tomcat

docker0网络的特点

  1. 它是默认的
  2. 域名访问不通
  3. –link 域名通了,但是删了又不行

3、我们可以让容器创建的时候使用自定义网络

自定义创建的默认default “bridge” 一个网络

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@VM-0-6-centos ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4b873066daf7   bridge    bridge    local
64b606f257e7   host      host      local
7f9fbfea6931   mynet     bridge    local
34ab4fdb73c0   none      null      local
[root@VM-0-6-centos ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "7f9fbfea6931271e917c7a932c47d05f311f2fe6f1e694b95e4ef3fcf060446e",
        "Created": "2021-06-16T15:56:58.841772626+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

我们来启动两个容器测试,使用自己的 mynet

docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat

来测试ping容器名和ip试试

# 都可以ping通
[root@VM-0-6-centos ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.118 ms
[root@VM-0-6-centos ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.059 ms

发现,我们自定义的网络docker都已经帮我们维护好了对应的关系

所以我们平时都可以这样使用网络,不使用 --link 效果一样,所有东西实时维护好,直接域名 ping 通。

网络连通

docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:

大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有 订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所 以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全部业务都在 order-net 网络下)其他业务在其他网络。

那关键的问题来了,如何让 tomcat-net-01 访问 tomcat1?

image-20210616162056466

# 启动默认的容器,在docker0网络下
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat

有个命令 connect 用来连接网络

# 我们来测试一下!打通mynet-docker0
[root@VM-0-6-centos ~]# docker network connect mynet tomcat01
[root@VM-0-6-centos ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "7f9fbfea6931271e917c7a932c47d05f311f2fe6f1e694b95e4ef3fcf060446e",
        "Created": "2021-06-16T15:56:58.841772626+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "52395d45d1fcad0170da201db471ea6ac75c25c9f7d91d10b6260dce2739fd54": {
                "Name": "tomcat-net-01",
                "EndpointID": "3c1aea820c4276b0d0dbe249ebd6f43547baceb7c3e774f8ee4b61b0e4b0b11f",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            //发现我们的tomcat01就进来这里了
            "c159a99201d5b3f0f6be065d562c1a0e6439b316084361937f9eda9a22e997ab": {
                "Name": "tomcat01",
                "EndpointID": "e11948dcd704e50b8008ee41546ff7c9f506b636f41fb6e6697081fd9d398dc5",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            },
            "f2106d157b5ea6c5bdb87e04b9dc18be2b2e25a41d61e25851ea0afbf1e9ea39": {
                "Name": "tomcat-net-02",
                "EndpointID": "3cb8b199df4fca69e1a6428ae0536ff3291f9215f8b9d9303a2ec3402bdc704f",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

tomcat01 可以ping通了

[root@VM-0-6-centos ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.075 ms

tomcat02 依旧ping不通,大家应该就理解了

[root@VM-0-6-centos ~]#  docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER 连接

部署 Redis 集群

创建网卡

docker network create redis --subnet 172.38.0.0/16

通过脚本创建六个redis配置

for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

启动6个容器

for port in $(seq 1 6); \
do \

docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \

done

进入一个redis,注意这里是 sh命令

docker exec -it redis-1 /bin/sh

创建集群

redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

连接集群

redis-cli -c
# 查看集群信息
cluster info
# 查看节点
cluster nodes

此时,六个 redis 已搭建好

测试集群

先 set 一个数据

127.0.0.1:6379> set name zhiyuan
-> Redirected to slot [5798] located at 172.38.0.12:6379
OK
172.38.0.12:6379> get name
"zhiyuan"

停止到存值的容器 redis-1

然后再次 get name,发现依旧可以获取值

查看节点,发现高可用完全没问题

Docker -Compose

简介

官方介绍

https://docs.docker.com/compose/

Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。借助 Compose,您可以使用 YAML 文件来配置应用程序的服务。然后,使用单个命令,从配置中创建并启动所有服务。要了解有关 Compose 的所有功能的更多信息,请参阅功能列表

Compose 适用于所有环境:生产、登台、开发、测试以及 CI 工作流。您可以在Common Use Cases 中了解有关每个案例的更多信息。

使用 Compose 基本上是一个三步过程:

  1. 使用 定义您的应用程序的环境,Dockerfile以便它可以在任何地方复制。
  2. 定义组成您的应用程序的服务,docker-compose.yml 以便它们可以在隔离的环境中一起运行。
  3. 运行 docker compose upDocker compose command 启动并运行你的整个应用程序。您也可以docker-compose up使用 docker-compose 二进制文件运行。

可以用 Docker Compose 来轻松高效的管理容器。定义运行多个容器。

一个docker-compose.yml看起来像这样:

version: "3.9"  # optional since v1.27.0
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
    links:
      - redis
  redis:
    image: redis
volumes:
  logvolume01: {}

安装

1、下载

官网:

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

加速下载

curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

2、授权

sudo chmod +x /usr/local/bin/docker-compose

简单上手

官方文档

https://docs.docker.com/compose/gettingstarted/

构建一个在 Docker Compose 上运行的简单 Python Web 应用程序。该应用程序使用 Flask 框架并在 Redis 中维护一个命中计数器。

第1 步:设置

  1. 为项目创建一个目录:

    mkdir composetest
    cd composetest
    
  2. 创建app.py

    import time
    
    import redis
    from flask import Flask
    
    app = Flask(__name__)
    cache = redis.Redis(host='redis', port=6379)
    
    def get_hit_count():
        retries = 5
        while True:
            try:
                return cache.incr('hits')
            except redis.exceptions.ConnectionError as exc:
                if retries == 0:
                    raise exc
                retries -= 1
                time.sleep(0.5)
    
    @app.route('/')
    def hello():
        count = get_hit_count()
        return 'Hello World! I have been seen {} times.\n'.format(count)
    
  3. 在项目目录中创建 requirements.txt

flask
redis

第 2 步:创建 Dockerfile

项目目录中,创建 Dockerfile

# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

第 3 步:在 Compose 文件中定义服务

项目目录中创建 docker-compose.yml

version: "3.9"
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

第 4 步:使用 Compose 构建并运行您的应用程序

在项目目录中运行 docker-compose up

[root@VM-0-6-centos composetest]# docker-compose up

如果要后台运行

 docker-compose up -d

测试:

[root@VM-0-6-centos ~]# curl localhost:5000
Hello World! I have been seen 1 times.
[root@VM-0-6-centos ~]# curl localhost:5000
Hello World! I have been seen 2 times.
[root@VM-0-6-centos ~]# curl localhost:5000
Hello World! I have been seen 3 times.
  • 名字规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jKMgOSPT-1627739909802)(https://camo.githubusercontent.com/0086f6052154a656126528da19d8a13c3b2d5b8423afd3aad0af6e6db243451e/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f6f64646661722f7374617469632f696d672f446f636b65722e6173736574732f696d6167652d32303231303631373139323234363531362e706e67)]

默认的服务名:文件名_服务名 _ num

  • 可以看见多了个网络
[root@VM-0-6-centos ~]# docker network ls
NETWORK ID     NAME                  DRIVER    SCOPE
4b873066daf7   bridge                bridge    local
d87efab51b47   composetest_default   bridge    local
86da632adad6   elastic               bridge    local
64b606f257e7   host                  host      local
34ab4fdb73c0   none                  null      local

项目中的内容都在同个网络下。

tip 其他为演示 Compose 量身定制的示例

这些示例专门针对 Docker Compose:

yaml 规则

官方文档

https://docs.docker.com/compose/compose-file/

# 3层!
version: '' # 版本
services: # 服务
    服务1: web
    # 服务配置
    images
    build
    network
    
    服务2: redis
    ....
    服务3: redis
    ....

# 其他配置 网络/卷、全局规则
volumes:
networks:
configs:

Java测试发布

以上实例是用 python 写的,我们写一个 java 版本的测试下

image-20210617234848816

1、编写java代码

创建一个 springboot demo

@RestController
public class HelloController {

    @Autowired
    StringRedisTemplate redisTemplate;

    @GetMapping("/hello")
    public String hello(){
        Long views = redisTemplate.opsForValue().increment("views");
        return "hello world! views:"+ views;
    }

}

2、添加配置

  • 编写 application.properties 文件
server.port=8080
spring.redis.host=redis
  • 编写 Docker 文件
FROM java:8

COPY *.jar /app.jar

CMD ["--server.port=8080"]

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]
  • 编写 docker-compose.yml 文件
version: "3.9"
services:
  zhiyuanapp:
    build: .
    image: zhiyuanapp
    depends_on:
      - redis
    ports:
      - "8080:8080"

  redis:
    image: "library/redis:alpine"

3、上传并构建

把 jar包 、Docker、docker-compose 三个文件上传到一个目录下

并在此目录下构建:

[root@VM-0-6-centos zhiyuanapp]# docker-compose up

4、测试:

[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:1
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:2
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:3

bridge local
d87efab51b47 composetest_default bridge local
86da632adad6 elastic bridge local
64b606f257e7 host host local
34ab4fdb73c0 none null local


项目中的内容都在同个网络下。

> tip 其他为演示 Compose 量身定制的示例

这些示例专门针对 Docker Compose:

- [快速入门:Compose 和 Django](https://docs.docker.com/samples/django/) - 展示了如何使用 Docker Compose 来设置和运行一个简单的 Django/PostgreSQL 应用程序。
- [快速入门:Compose 和 Rails](https://docs.docker.com/samples/rails/) - 展示了如何使用 Docker Compose 来设置和运行 Rails/PostgreSQL 应用程序。
- [快速入门:Compose 和 WordPress](https://docs.docker.com/samples/wordpress/) - 展示了如何使用 Docker Compose 在具有 Docker 容器的隔离环境中设置和运行 WordPress。

## yaml 规则

> 官方文档

https://docs.docker.com/compose/compose-file/

```sh
# 3层!
version: '' # 版本
services: # 服务
    服务1: web
    # 服务配置
    images
    build
    network
    
    服务2: redis
    ....
    服务3: redis
    ....

# 其他配置 网络/卷、全局规则
volumes:
networks:
configs:

Java测试发布

以上实例是用 python 写的,我们写一个 java 版本的测试下

[外链图片转存中…(img-EAwtwwmT-1627739909802)]

1、编写java代码

创建一个 springboot demo

@RestController
public class HelloController {

    @Autowired
    StringRedisTemplate redisTemplate;

    @GetMapping("/hello")
    public String hello(){
        Long views = redisTemplate.opsForValue().increment("views");
        return "hello world! views:"+ views;
    }

}

2、添加配置

  • 编写 application.properties 文件
server.port=8080
spring.redis.host=redis
  • 编写 Docker 文件
FROM java:8

COPY *.jar /app.jar

CMD ["--server.port=8080"]

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]
  • 编写 docker-compose.yml 文件
version: "3.9"
services:
  zhiyuanapp:
    build: .
    image: zhiyuanapp
    depends_on:
      - redis
    ports:
      - "8080:8080"

  redis:
    image: "library/redis:alpine"

3、上传并构建

把 jar包 、Docker、docker-compose 三个文件上传到一个目录下

并在此目录下构建:

[root@VM-0-6-centos zhiyuanapp]# docker-compose up

4、测试:

[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:1
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:2
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:3
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Docker是一个开源的容器化平台,它可以让开发者打包他们的应用程序和所有依赖项到一个轻量级的、可移植的容器中。Docker容器可以在任何环境中运行,从开发人员的笔记本上到生产环境中的物理机器和虚拟机中。 学习Docker有很多好处,首先,它可以帮助开发人员更快地构建、测试和部署应用程序。通过将应用和依赖项打包到一个容器中,开发人员可以确保在不同的环境中应用能够一致地运行。另外,Docker还可以提高系统的可移植性和可伸缩性,从而减少了在不同环境中部署和管理应用程序的成本和复杂性。 在了解Docker的基本概念之后,可以开始学习如何构建和管理Docker容器。这包括学习Docker镜像、容器和Dockerfile等概念,以及如何使用Docker命令行工具来管理容器和镜像。另外,还需要了解Docker Compose和Docker Swarm等工具,它们可以帮助开发人员更方便地管理多个容器和构建Docker集群。 最后,学习Docker也需要了解如何将Docker与持续集成/持续部署(CI/CD)工具和云平台集成,从而构建一个完整的DevOps工作流程。这样可以让开发团队更快速地交付高质量的应用,并及时地对应用进行更新和维护。 总之,Docker入门白皮书可以帮助开发人员了解容器化技术的基本概念和原理,以及如何在实际工作中应用Docker来提高开发效率和应用可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值