架构
- 镜像:docker镜像,就相当于是一个root文件系统,比如官方镜像像ubuntu就包含了一套完整的ubuntu最小系统的root文件系统
- 容器:镜像和容器的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体.容器可以被创建 启动 停止 删除和暂停等
- 仓库:仓库可以被看一个代码控制中心,用来保存镜像
docker使用客户端 服务器架构模式,使用远程api来管理和创建docker容器.docker容器通过docker镜像来创建
概念 | 说明 |
---|---|
docker镜像(images) | docker镜像是用于创建docker容器的模板,比如ubuntu系统 |
docker容器(container) | 容器是独立运行的一个或一组应用,是镜像运行的实体 |
docker客户端(client) | docker客户端通过命令行或者其他工具使用docker sdk与docker的守护进行通信 |
docker主机(host) | 一个物理或者虚拟的机器用于执行docker守护进程和容器 |
docker registry | docker仓库用来保存镜像,可以理解为代码控制中的代码仓库,docker hub提供了庞大的镜像集合供使用.一个docekr registry中可以包含多个仓库,每个仓库可以包含多个标签,每个标签对应一个镜像,通常,一个仓库会包含同一个软件不同版本的进行,而标签就常用于对应该软件的各个版本.我们可以通过[仓库名]:[标签]的格式来指定具体是这个软件那个版本的镜像.如果不给出标签,将以latest作为默认标签 |
docker machine | docker machine是一个简化docekr安装的命令行工具,通过一个简单的命令行即可在对应的平台上安装docker比如virtualbox digital ocean microsoft azure |
docker使用
docker helloworld
docker允许你在容器内运行应用程序.在容器内运行一个应用程序并输出helloworld
docker run ubuntu:15.10 /bin/echo "Hello world"
- docker:docker的二进制执行文件
- run:与前面的docker组合来运行一个容器
- ubuntu15.10:指定要运行的镜像,docker首先从本地主机上查找镜像是否存在,如果不存在,docker就会从镜像仓库docker hub下载公共镜像
- /bin/echo “hello world”:在启动的容器里面执行的命令
以上命令的含义:docker以一个ubuntu15.10镜像创建一个新容器,然后再容器里面执行 /bin/echo “helloworld”,然后输出结果
交互式容器
通过docker的两个参数-i -t ,让docker运行的容器实现对话能力
docker run -i -t ubuntu:15.10 /bin/bash
-t :在新容器内指定一个伪终端,或者终端
-i :允许你对容器内的标准输入(STDIN)进行交互
cat /proc/version 查看当前系统的版本信息
运行exit命令或者ctrl+d来退出容器
后台启动容器
创建一个以进程方式运行的容器
docker run -d ubuntu:15.10 /bin/sh -c "while true;do echo hello world;sleep 1; done"
这个长字符串叫做容器的id,对每个容器来说都是唯一的,我们可以通过容器的id来查看对应的容器发生了什么.
查看容器有无在运行
docker ps
- container id 容器id
- image:使用的镜像
- command:启动容器时运行的命令
- created:容器创建的时间
- status:容器状态
- created(创建中)
- restarting(重启中)
- running或者up(运行中)
- removing(迁移中)
- paused(暂停中)
- exited(停止)
- dead(死亡)
- ports:容器端口信息和使用的连接类型(tcp\udp)
- names:自动分配的容器名称
原始主机中查看容器内的标准输出
docker logs 52dfdf29ba58
停止容器
docker stop 52dfdf29ba58
docker容器使用
docker客户端
查看docker客户端的所有命令选项
docker
查看具体命令的更深用法,如stats指令的具体用法
docker stats --help
容器获取
来取镜像
docker pull ubuntu
启动容器
使用一个ubuntu镜像启动一个容器,以参数为命令行模式进入该容器
docker run -it ubuntu /bin/bash
- -i 交互式操作
- -t 终端
- ubuntu: ubuntu镜像
- /bin/bash:放在镜像名后的是命令,这里我们希望有一个交互式的shell,因此使用的是/bin/bash
查看所有容器的命令
docker ps -a
启动一个已停止的容器
docker start
后台运行
大部分场景下我们是希望docker服务是在后台运行的,我们可以使用-d指定容器的运行模式
docker run -itd --name ubuntu-test ubuntu /bin/bash
- -d 默认不会进入该容器,想要进入容器需要使用指令docker exec
停止一个容器
docker stop [容器id]
停止的容器通过docker restart重启
docker restart [容器id]
进入容器
在使用-d参数之后,容器启动后会进入后台,此时想要进入容器,可以通过以下指令进入
- docker attach
- docker exec : 推荐使用docker exec命令,因为此退出容器终端,不会导致容器的停止
attach命令
docker attach cd2c8040fba6
退出容器,会导致容器停止
exec命令
docekr exec -it cd2c8040fba6 /bin/bash
导出和导入容器
导出本地容器,使用docker export命令
docker export cd2c8040fba6 > ubuntu.tar
导入容器快照
可以使用docker import从容器快照文件中在导入为镜像,以下将快照文件ubuntu.tar导入到镜像ubuntu:v1
cat ./ubuntu.tar | docker import - ubuntu:v1
也可以通过指定url或者某个目录来导入
docker import http://example.com/exampleimage.tgz example/imagerepo
删除容器
删除容器使用docker rm命令
docker rm -f cd2c8040fba6
清理掉所有处于终止状态的容器
docker container prune
web应用
运行一个web应用
将在docker容器中运行一个python flask应用来运行一个web应用
docker pull training/webapp#载入镜像docker run -d -P training/webapp python app.py
- -d 让容器在后台运行
- -P 将容器内部使用的网络端口随机映射到我们使用的主机上
查看web应用容器
docker ps
多了端口信息 ports
0.0.0.0:49153->5000/tcp, :::49153->5000/tcp
docker 开放了5000端口(默认python flask端口)映射到主机端口49153上
我们通过浏览器访问web应用
也可以通过-p参数来设置不一样的端口
docker run -d -p 5000:5000 training/webapp python app.py
容器内部的5000端口映射到我们本地主机的5000端口上
网络端口的快捷方式
通过docker ps命令可以查看到容器的端口映射,docker还提供了另一个快捷方式docker port,使用docker post可以查看指定(id 或者 名字)容器的某个确定端口映射到本机的端口号.上面我们创建的容器id为18b8aa6acac6名字为naughty_kalam.我们可以使用
docker port 18b8aa6acac6docker port naughty_kalam
查看web应用程序日志
查看容器内部的标准输出
docker logs [id或名字]
- -f:让docker logs像使用tail -f 一样来输出容器内部的标准输出,从上面可以看出来应用程序使用的是5000端口并且能够看到应用程序的访问日志
查看web应用程序容器的进程
查看容器内部运行的进程
docker top naughty_kalam
检查web应用程序
使用docker inspect 来查看docker的底层信息,它会返回一个json文件记录着docker容器的配置和状态信息
docker inspect naughty_kalam
停止web应用容器
docker stop friendly_perlman
重启web应用
已经停止的web容器,使用docekr start来启动
docker start friendly_perlman
查询最后一次创建的容器
docker ps -l
重启正在运行的容器
docker restart
移除web应用容器
删除不需要的容器
docker rm friendly_perlman
删除容器时,容器必须是停止状态,否则会报错
docker镜像使用
在运行容器时,使用的镜像如果在本地不存在,docker就会自动从docker镜像仓库中下载,默认是从docker hub公共镜像源下载
列出镜像列表
列出本地主机上的镜像
docker images
- repository :表示镜像仓库源
- tag :镜像的标签
- image id :镜像id
- created :镜像创建时间
- size :镜像大小
同一个仓库源可以有多个tag,代表这个仓库源的不同版本,如ubuntu仓库源里,有15.10 14.04等多个不同的版本,我们使用repository:tag来定义不同的镜像.所以当我们要使用版本为15.10的ubuntu系统镜像阿里运行容器时
docker run -t -i ubuntu:15.10 /bin/bash
- -i :交互式操作
- -t:终端
- ubuntu:15.10 :这里指用ubuntu15.10版本的镜像为基础来启动容器
- /bin/bash : 放在镜像名后面的是命令.这里我们希望有个交互式shell,因此用的是/bin/bash
如果要使用ubuntu14.04版本为系统镜像来运行容器时
docker run -i -t ubuntu:14.04 /bin/bash
如果不指定一个镜像的版本标签,例如你只是用ubuntu,docker将默认使用ubuntu:latest镜像
获取一个新的镜像
在本地主机上使用一个不存在的镜像时docker就会自动下载这个镜像.如果我们像预先下载这个镜像,我们就可以使用docker pull命令来下载
docker pull ubuntu:13.10
下完之后就可以直接使用这个镜像来运行docker
查找镜像
我们可以从docker hub网站来搜索镜像,docker hub网站https://hub.docker.com/.我们也可以使用docker search命令搜索镜像.比如我们需要一个httpd的镜像来作为我们的web服务.我们可以通过docker search命令搜索httpd来寻找适合我们的镜像
docker search httpd
- name :镜像仓库源的名称
- description:镜像的描述
- official:是否是docker官方发布
- stars:类似github上的star,表示点赞 喜欢
- automated:自动构建
拖取镜像
docker pull httpd
接着就可以使用这个镜像了
删除镜像
使用docker rmi命令
docker rmi a4c7cb30a6ff
删除所有镜像
docker rim i `docker images -q`
创建镜像
当我们从docker镜像仓库中下载的镜像不能满足我们的需求的时候,我们就可以通过以下两种方式对镜像进行更改
- 从已创建的容器中更新镜像,并提交这个镜像
- 使用dockerfile指令来创建一个新的镜像
更新镜像
更新镜像之前我们需要使用镜像来创建一个容器
docker run -it ubuntu:15.10 /bin/bash
在运行的容器内使用apt-get update命令进行更新,在操作完成之后,输入exit命令来退出容器,此时id为79171d4b8787的容器,是按照我们的需求更改的容器.我们可以通过命令docker commit来提交容器副本
docker commit -m="has update" -a="wanan" 79171d4b8787 ububtu:v2
- -m :提交的描述信息
- -a :指定镜像作者
- 79171d4b8787 :容器id
- ubuntu:v2 :指定要创建的目标镜像名
我们可以使用docker images来查看我们的新镜像
docker images
使用我们的新镜像ubuntu:v2来启动一个容器
构建镜像
使用命令docker bulid,从零开始来创建一个新的镜像,为此我们需要创建一个Dockerfile文件,其中包含一组指令来告诉docker如何构建我们的镜像
[root@mycentos ~]# cat DockerfileFROM centos:6.7MAINTAINER Fisher "fisher@sudops.com"RUN /bin/echo 'root:123456' |chpasswdRUN useradd runoobRUN /bin/echo 'runoob:123456' |chpasswdRUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/localEXPOSE 22EXPOSE 80CMD /usr/sbin/sshd -D
每一个指令都会在镜像上创建一个新的层,每一个指令的前缀必须都是大写的.第一条指令FROM 指定使用那个镜像源,RUN指令告诉docker在镜像内执行命令,安装了什么,然后我们使用Dockerfile文件,通过docker build命令来创建一个镜像
docker build -t wanan/centos:6.7 .
- -t :指定要创建的目标镜像名
- . : Dockerfile文件所在的目录,可以指定Dockerfile的绝对路径
使用docker images查看创建的镜像已经在列表中存在
我们可以使用新的镜像来创建容器
docker run -it wanan/centos:6.7 /bin/bash
设置镜像标签
我们可以使用docker tag命令,为镜像添加一个新的标签
docker tag 68bb92d72b8d wanan/centos:dev
可以看到id为68bb92d72b8d多一个标签
docker容器连接
前面我们实现了通过网络端口来访问运行在docker容器内的服务.容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过-P或者-p参数来指定端口映射,下面通过端口连接到一个docker容器
网络端口映射
创建一个python应用的容器
docker run -d -P training/webapp python app.py
另外,我们可以指定容器绑定的网络地址,比如绑定127.0.0.1.我们使用-P绑定端口号,使用docker ps可以看到容器5000绑定了主机端口49155
我们也可以使用-p标识来指定容器端口绑定到主机端口
- -P :是容器内部端口随机映射到主机的端口
- -p :是容器内部端口绑定到指定的主机端口
docker run -d -p 5000:5000 training/webapp python app.py
可以指定容器绑定的网络地址,比如绑定127.0.0.1
docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
这样我们就可以通过访问127.0.0.5001来访问容器5000端口了.之前的都是默认绑定tcp端口,如果要绑定udp端口,可以在端口后面加上/udp
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
docker port 命令可以让我们快捷查看端口的绑定情况
docker port loving_satoshi 5000/udp
docker容器互联
端口映射并不是唯一把docker连接到另一个容器的方法.docker有一个连接系统允许将多个容器连接在一起,共享连接信息.docker连接会创建一个父子关系,其中父容器可以看到子容器的信息
容器命名
当我们创建容器的时候,docker会自动对他进行命名.另外我们也可以使用–name 标识来命名容器
docker run -d -P --name wanan training/webapp python app.py
新建网络
下面创建一个新的docker网络
docker network create -d bridge test-net
- -d :参数指定docker网络类型,有bridge overlay
其中overlay网络类型用于swarm mode
连接容器
运行一个容器并连接到新建的test-net网络
docker run -itd --name test1 --network test-net ubuntu /bin/bash
打开一个新的终端,在运行一个容器并加入到test-net网络
docker run -itd --name test2 --network test-net ubuntu /bin/bash
通过平来证明test1容器和test2容器建立了互联关系,如果test1或者test2容器中无ping命令,则在容器内执行一下命令安装ping(可以在一个容器内按装好,提交到容器镜像,在以新的镜像重新运行以上两个容器)
docker exec -it test1 /bin/bashapt-get updateapt install iputils-ping
这样test1容器就和test2容器建立了相互连接,如果有多个容器需要相互连接,推荐使用docker compose
配置dns
可以在原始主机中的/etc/docker/daemon.json文件中添加以下内容来设置全部容器的dns
{ "dns" : [ "114.114.114.114", "8.8.8.8" ]}
设置完之后,启动容器的dns会自动配置为114.114.114.114和8.8.8.8.配置完,需要重启docker才能生效.查看容器的dns是否生效可以使用以下命令,他会输出容器的dns信息
docker run -it --rm ubuntu cat etc/resolv.conf
手动指定容器的配置
如果只是想在指定容器设置dns,则可以使用
docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
- –rm :容器退出时自动起立容器内部的文件系统
- -h HOSTNAME 或者 –hostname=HOSTNAME :设定容器的主机名,他会被写入到容器内的/etc/hostname和/etc/hosts
- –dns=IP_ADDRESS:添加dns服务器到容器的/etc/resolv.conf中,让容器用这个服务器来解析所有不在/etc/hosts中的主机名
- –dns-search=DOMAIN:设定容器的搜索域,当设定搜索域为.example.com时,在搜索一个名为host的主机时,dns不仅搜索host,还会搜索host.example.com
如果在容器启动时没有指定–nds和–dns-search,docker会默认用原始主机上的/etc/resolv.conf来配置dns
docker仓库管理
先给我去https://hub.docker.com免费注册一个账号去
登录和退出
docker login
docker logout
推送镜像
登录之后可以通过docker push命令将自己的镜像推送到docker hub
docker Dockerfile
dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需要的指令和说明
使用dockerfile定制镜像
定制一个nginx镜像
构建好的镜像内会有一个/usr/share/nginx/html/index.html文件
在一个空目录下新建一个名为Dockerfile文件,并在文件内添加以下内容
FROM nginxRUN echo "这是一个本地创建的nginx镜像" > /usr/share/nginx/html/index.
FROM和RUN指令的作用
- FROM:定制的镜像都是基于FROM的镜像,这里的nginx就是定制需要的基础镜像,后续的操作都是基于nginx
- RUN: 用于执行后面跟着的命令行命令.有两种格式
shell格式
RUN [命令行命令]# [命令行命令] 等同于在终端操作的shell命令
exec格式
RUN ["可执行文件","参数1","参数2"]#例如:#RUN ["./test.php","dev","offline"]等价于 RUN ./test.php dev offline
注意 dockerfile的指令每一次执行都会在docker上新建一层.所以过多无意义的层会造成镜像膨胀过大
FROM centosRUN yum -y install wgetRUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"RUN tar -xvf redis.tar.gz
以上执行会创建3层镜像.可简化为以下格式
FROM centosRUN yum -y install wget \&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \&& tar -xvf redis.tar.gz
如上,以&&符号连接命令,这样执行后,只会创建一层镜像
开始构建镜像
在dockerfile文件的存放目录下,执行构建动作.以下实例,通过目录下的dcokerfile构建一个nginx:v3(镜像名称:镜像标签)
最后的.代表本次执行的上下文路径
docker build -t nginx:v3 .
以上显示说明已经构建成功
上下文路径,有提到指令最后一个.是上下文路径,那么什么是上下文路径呢
docker bulid -t nginx:v3 .
上下文路径,是指docker在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径之后,会将路径下的所有内容打包.
由于docker的运行模式是c/s.我们本机是c,docker引擎是s.实际的构建过程是在docker引擎下完成的,所以这个时候无法用到我们本机的文件,这就需要我们本机的指定目录下的文件一起打包提供给docker引擎使用.如果未说明最后一个参数,那么默认上下文路径技术dockerfile所在的位置.
上下文路径不要放无用的文件,因为会一起打包发送给docker引擎,如果文件过多会造成过程缓慢.
docker compose
compose简介
compose是用于定义和运行多容器docker应用程序的工具.通过compose,您可以使用yml文件来配置应用程序需要的所有服务,然后使用一个命令就可以从yml文件配置中创建并启动所有服务.
使用compose的三个步骤
- 使用dockerfile定义应用程序的环境
- 使用docker-compose.yml定义构成应用程序的服务,这样他们可以在隔离环境中一起运行.
- 最后,执行docker-compose up命令来启动并运行整个应用程序
docker-compose.yml的配置案例如下
# yaml 配置实例version: '3'services: web: build: . ports: - "5000:5000" volumes: - .:/code - logvolume01:/var/log links: - redis redis: image: redisvolumes: logvolume01: {}
compose安装
linux上我们可以从github上下载二进制包来使用
curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composechmod +x /usr/local/bin/docker-compose docker-compose --version
对于alpine,需要下载依赖包.py-pip,python-dev,libffi-dev,openssl-dev,gcc,libc-dev,和 make。
新建一个app.py复制进去以下内容
import timeimport redisfrom flask import Flaskapp = 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)
在此实例中,redis是应用程序网络上redis容器的主机名,该主机使用的端口为6379.创建一个requirements.txt
flaskredis
创建dockerfile文件
FROM python:3.7-alpineWORKDIR /codeENV FLASK_APP app.pyENV FLASK_RUN_HOST 0.0.0.0RUN apk add --no-cache gcc musl-dev linux-headersCOPY requirements.txt requirements.txtRUN pip install -r requirements.txtCOPY . .CMD ["flask", "run"]
FROM python:3.7-alpine:从python3.7映像开始构建镜像
WORKDIR/code:将工作目录设置为/code
ENV FLASK_APP app.py ENV FLASK_RUN_HOST 0.0.0.0
设置flask命令使用的环境变量
RUN apk add –no-cache gcc musl-dev linux-headers:安装gcc ,以便诸如MarkupSafe 和 SQLAlchemy 之类的 Python 包可以编译加速。
COPY requirements.txt requirements.txt RUN pip install -r requirements
复制requirements.txt并安装python依赖项
COPY .:将.项目中的当前目录复制到.镜像中的工作目录
CMD[“flask”,“run”]:容器提供默认的执行命令为:flask run
创建docker-compose.yml
# yaml 配置version: '3'services: web: build: . ports: - "5000:5000" redis: image: "redis:alpine"
该compose定义了两个服务:web和redis
- web:该web服务使用从dockerfile当前目录中构建的镜像,然后,它将容器和主句绑定到暴露的端口5000.此示例服务使用Flask web服务的默认端口5000
- redis:该redis服务使用docker hub的公共redis映像
使用compose命令构建和运行应用
docker-compose up
docker安装ubuntu
查看可用ubuntu
访问 Ubuntu 镜像库地址: https://hub.docker.com/_/ubuntu” />
查看本地镜像
docker images
运行容器,并可以通过exec命令进入ubuntu容器
docker run -itd --name ubuntu-test ubuntu
安装centos
拉取指定版本的centos镜像
docker pull centos:centos7
查看本地镜像
docker images
运行容器并通过exec命令进入centos容器
docker run -itd --name centos-test centos:centos7docker exec -it centos-test bash
docker安装nginx
找版本
docker search nginx
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sV9ynXGU-1665117305902)(C:/Users/14980/AppData/Roaming/Typora/typora-user-images/image-20220402230406352.png)]
拉取
docker pull nginx
查看本地镜像
docker images
运行容器
docker run --name nginx-test -p 8080:80 -d nginx
- –name nginxe-test :容器名称
- -p 8080:80 :端口映射,将本地8080端口映射到容器内部的80端口
- -d nginx :设置容器在后台一直执行
docker exec -it nginx-test bash
nginx+php部署
拉取php
docker pull php:5.6-fpm
docker run --name myphp-fpm -v ~/nginx/www:/www -d php:5.6-fpm
- –name myphp-fpm:将容器命名为myphp-fpm
- -v ~/nginx/www:/www:将主机中项目的目录www挂载到容器的/www
创建~/nginx/conf/conf.d目录
mkdir ~/nginx/conf/conf.d
添加 ~/nginx/conf/conf.d/runoob-test-php.conf 文件
server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm index.php; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /www/$fastcgi_script_name; include fastcgi_params; }}
配置文件
- php:9000:表示php-fpm服务中的url
- /www/:是myphp-php中php文件存储路径,映射到本地的~/nginx/www目录
启动nginx
docker run --name runoob-php-nginx -p 8083:80 -d \ -v ~/nginx/www:/usr/share/nginx/html:ro \ -v ~/nginx/conf/conf.d:/etc/nginx/conf.d:ro \ --link myphp-fpm:php \ nginx
- -p 8083:80:端口映射,把nginx中的80映射到本地的8083端口
- ~/nginx/www:是本地html文件的存储目录,/usr/share/nginx/html是容器内html文件的存储目录
- ~/nginx/conf/conf.d 是本地nginx配置文件的存储目录,/etc/nginx/conf.d是容器内nginx配置文件的存储目录
- –link myphp-fpm:php :是把myphp-fpm的网络并入nginx,并通过修改nginx的/etc/hosts,把域名php映射成127.0.0.1,让nginx通过php:9000访问php-fpm
在~/nginx/www目录下创建index.php
checking OpenSSL library version >= 1.0.2...# > configure: error: Your version of OpenSSL is not compatible with this version of tcnative# see http://tomcat.10.x6.nabble.com/VOTE-Release-Apache-Tomcat-8-0-32-tp5046007p5046024.html (and following discussion)# and https://github.com/docker-library/tomcat/pull/31ENV OPENSSL_VERSION 1.1.0f-3+deb9u2RUN set -ex; \ currentVersion="$(dpkg-query --show --showformat '${Version}\n' openssl)"; \ if dpkg --compare-versions "$currentVersion" '< /etc/apt/sources.list.d/stretch.list; \ { \# add a negative "Pin-Priority" so that we never ever get packages from stretch unless we explicitly request them echo 'Package: *'; \ echo 'Pin: release n=stretch*'; \ echo 'Pin-Priority: -10'; \ echo; \# ... except OpenSSL, which is the reason we're here echo 'Package: openssl libssl*'; \ echo "Pin: version $OPENSSL_VERSION"; \ echo 'Pin-Priority: 990'; \ } > /etc/apt/preferences.d/stretch-openssl; \ fi; \ apt-get update; \ apt-get install -y --no-install-recommends openssl="$OPENSSL_VERSION"; \ rm -rf /var/lib/apt/lists/*; \ fiRUN apt-get update && apt-get install -y --no-install-recommends \ libapr1 \ && rm -rf /var/lib/apt/lists/*# see https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/KEYS# see also "update.sh" (https://github.com/docker-library/tomcat/blob/master/update.sh)ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23ENV TOMCAT_MAJOR 8ENV TOMCAT_VERSION 8.5.32ENV TOMCAT_SHA512 fc010f4643cb9996cad3812594190564d0a30be717f659110211414faf8063c61fad1f18134154084ad3ddfbbbdb352fa6686a28fbb6402d3207d4e0a88fa9ceENV TOMCAT_TGZ_URLS \# https://issues.apache.org/jira/browse/INFRA-8753?focusedCommentId=14735394#comment-14735394 https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz \# if the version is outdated, we might have to pull from the dist/archive :/ https://www-us.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz \ https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz \ https://archive.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gzENV TOMCAT_ASC_URLS \ https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc \# not all the mirrors actually carry the .asc files :'( https://www-us.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc \ https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc \ https://archive.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.ascRUN set -eux; \ \ savedAptMark="$(apt-mark showmanual)"; \ apt-get update; \ \ apt-get install -y --no-install-recommends gnupg dirmngr; \ \ export GNUPGHOME="$(mktemp -d)"; \ for key in $GPG_KEYS; do \ gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \ done; \ \ apt-get install -y --no-install-recommends wget ca-certificates; \ \ success=; \ for url in $TOMCAT_TGZ_URLS; do \ if wget -O tomcat.tar.gz "$url"; then \ success=1; \ break; \ fi; \ done; \ [ -n "$success" ]; \ \ echo "$TOMCAT_SHA512 *tomcat.tar.gz" | sha512sum -c -; \ \ success=; \ for url in $TOMCAT_ASC_URLS; do \ if wget -O tomcat.tar.gz.asc "$url"; then \ success=1; \ break; \ fi; \ done; \ [ -n "$success" ]; \ \ gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz; \ tar -xvf tomcat.tar.gz --strip-components=1; \ rm bin/*.bat; \ rm tomcat.tar.gz*; \ rm -rf "$GNUPGHOME"; \ \ nativeBuildDir="$(mktemp -d)"; \ tar -xvf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; \ apt-get install -y --no-install-recommends \ dpkg-dev \ gcc \ libapr1-dev \ libssl-dev \ make \ "openjdk-${JAVA_VERSION%%[.~bu-]*}-jdk=$JAVA_DEBIAN_VERSION" \ ; \ ( \ export CATALINA_HOME="$PWD"; \ cd "$nativeBuildDir/native"; \ gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \ ./configure \ --build="$gnuArch" \ --libdir="$TOMCAT_NATIVE_LIBDIR" \ --prefix="$CATALINA_HOME" \ --with-apr="$(which apr-1-config)" \ --with-java-home="$(docker-java-home)" \ --with-ssl=yes; \ make -j "$(nproc)"; \ make install; \ ); \ rm -rf "$nativeBuildDir"; \ rm bin/tomcat-native.tar.gz; \ \# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies apt-mark auto '.*' > /dev/null; \ [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ rm -rf /var/lib/apt/lists/*; \ \# sh removes env vars it doesn't support (ones with periods)# https://github.com/docker-library/tomcat/issues/77 find ./bin/ -name '*.sh' -exec sed -ri 's|^#!/bin/sh$|#!/usr/bin/env bash|' '{}' +# verify Tomcat Native is working properlyRUN set -e \ && nativeLines="$(catalina.sh configtest 2>&1)" \ && nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')" \ && nativeLines="$(echo "$nativeLines" | sort -u)" \ && if ! echo "$nativeLines" | grep 'INFO: Loaded APR based Apache Tomcat Native library' >&2; then \ echo >&2 "$nativeLines"; \ exit 1; \ fiEXPOSE 8080CMD ["catalina.sh", "run"]
通过Dockerfile文件创建一个镜像,换成自己的名字
docker build -t tomcat .
使用tomcat镜像
docker run --name tomcat -p 8080:8080 -v $PWD/test:/usr/local/tomcat/webapps/test -d tomcat
- -p 8080:8080:将主机的8080端口映射到容器的8080端口
- -v $PWD/test:/usr/local/tomcat/webapps/test :将主机中当前目录下的test挂载到容器的/test