Docker版本选择:Docker之前没有区分版本,但是2017年推出(将docker更名为)新的项目Moby,github地址:https://github.com/moby/moby,Moby项目属于Docker项目的全新上游,Docker将是一个隶属于的Moby的子产品,而且之后的版本之后开始区别为CE版本(社区版本)和EE(企业收费版),CE社区版本和EE企业版本都是每个季度发布一个新版本,但是EE版本提供后期安全维护1年,而CE版本是4个月 Docker安装下载rpm包安装:
Centos yum源安装:
rm -rf /etc/yum.repos.d/* wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce
systemctl start docker
systemctl enable docker
Ubuntu安装
curl -fsSL https://get. | bash -s docker --mirror Aliyun
sudo vim /etc/apt/sources.list deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
sudo apt-get update sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common 2. 安装GPG证书 curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - 3. 写入软件源信息 sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" 4. 更新 sudo apt-get -y update
5. 发现Docker-CE的版本: # apt-cache madison docker-ce docker-ce | 5:19.03.2~3-0~ubuntu-bionic | http://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic/stable amd64 Packages docker-ce | 5:19.03.1~3-0~ubuntu-bionic | http://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic/stable amd64 Packages 6. 安装指定版本的Docker-CE:(VERSION例如上面的17.03.1〜ce-0〜ubuntu-xenial) sudo apt install docker-ce-cli=5:18.09.9~3-0~ubuntu-bionic sudo apt install docker-ce=5:18.09.9~3-0~ubuntu-bionic 7. 验证版本
最后一行有个警告:警告:不支持交换限制
解决方法: sudo vim /etc/default/grub 在GRUB_CMDLINE_LINUX=""这行加上 GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1" 更新下grub,然后重启 sudo update-grub reboot
Docker命令
docker info
docker version
docker ps
4. 搜索nginx的镜像(第一个是默认的,也是下载最多的) docker search nginx 5. 下载nginx的镜像 docker pull nginx 6. 查看已经下载的镜像列表,TAG版本号默认都是latest docker images 7、进入容器后,安装基础命令:
启动容器# 启动一个在后台运行的 docker 容器
docker run -it -d --name 'test-nginx' nginx
# -p指定端口映射,
-p 80:80
# 指定 ip 地址和传输协议 udp 或者 tcp:
-p 192.168.7.108:80:80/tcp
# 也可以在创建时手动指定容器的 dns
--dns 223.6.6.6
# 指定名称
--name "centos3"
vi docker-enter.sh chmod +x docker-enter.sh 进入容器
docker exec -it b7a13ace208d bash
docker inspect -f "{{.State.Pid}}" 02a1907e7c89 19080 nsenter -t 19080 -m -u -i -n -p 3. 脚本方式进入容器 #!/bin/bash docker_in(){ NAME_ID=$1 PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID}) nsenter -t ${PID} -m -u -i -n -p } docker_in $1 启动 ./docker-enter.sh centos-test
更多命令以名义名:nginx为例子
docker rmi nginx
2. 手动导出docker镜像 docker save nginx -o /root/nginx.tar.gz docker save nginx > /root/nginx.tar.gz
docker save nginx -o /root/nginx.tar.gz docker save nginx > /root/nginx.tar.gz
# d5ab2595f09a是CONTAINER ID
docker stop d5ab2595f09a
docker start d5ab2595f09a
docker rm d5ab2595f09a
docker kill d1ad4fa0b74c
docker加快加速配置:国内下载国外的某些有时候会很慢,因此可以更改docker配置文件添加一个加速器,可以通过加速器达到加速下载替代的目的。 获取加速地址:浏览器打开http://cr.console.aliyun.com,编码或登录阿里云账号,单击垂直的嵌套加速器,将会得到一个专属的加速地址,而且下面有使用配置说明:
1. 可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["你的加速地址"] } EOF 2. 重启服务 sudo systemctl daemon-reload sudo systemctl restart docker 使用docker info 查看
Docker命令与镜像管理:Docker 镜像含有启动容器所需要的文件系统及所需要的内容, 因此镜像主要用于创建并启动 docker 容器。 Docker 镜像含里面是一层层文件系统,叫做 Union FS(联合文件系统) ,联合文件系统,可以将几层目录挂载到一起,形成一个虚拟文件系统,虚拟文件系统的目录结构就像普通 linux 的目录结构一样, docker 通过这些文件再加上宿主机的内核提供了一个 linux 的虚拟环境,每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读( readonly)、读写( readwrite)和写出( whiteout-able),但是 docker 镜像中每一层文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样,当使用镜像的时候,我们只会看到一个完全的整体,不知道里面有几层也不需要知道里面有几层,结构如下: 一个典型的 Linux 文件系统由 bootfs 和 rootfs 两部分组成, bootfs(boot filesystem) 主要包含 bootloader 和 kernel, bootloader 主要用于引导加载 kernel, 当 kernel 被加载到内存中后 bootfs 会被 umount 掉, rootfs (root file system) 包含的就是典型 Linux 系统中的/dev, /proc, /bin, /etc 等标准目录和文件, 下图就是 docker image 中最基础的两层结构,不同的 linux 发行版(如 ubuntu和 CentOS ) 在 rootfs 这一层会有所区别。但是对于 docker 镜像通常都比较小, 官方提供的 centos 基础镜像在 200MB 左右,一些其他版本的镜像甚至只有几 MB, docker 镜像直接调用宿主机的内核,镜像中只提供 rootfs,也就是只需要包括最基本的命令、工具和程序库就可以了, 比如 alpine 镜像,在 5M 左右。 下图就是有两个不同的镜像在一个宿主机内核上实现不同的 rootfs。 容器、 镜像父镜像: docker常用命令示例
# 带指定版本号 docker search centos:7.2.1511 # 不带版本号默认 latest docker search centos
docker pull 仓库服务器:端口/项目名称/镜像名称:版本号
docker images
# 方法1 docker save centos -o /opt/centos.tar.gz # 方法2 docker save centos > /opt/centos-1.tar.gz
tar xvf centos.tar.gz cat manifest.json
docker load < /opt/centos.tar.gz
删除镜像 docker rmi centos
docker rm 容器 ID/容器名称
docker命令:
docker [OPTIONS] COMMAND
[COMMAND]
attach 此方式进入容器的操作都是同步显示的且 exit 后容器将被关闭
build 从Dockerfile构建一个镜像
commit 从容器的更改中创建一个新镜像
cp 在容器和本地文件系统之间复制文件/文件夹
create 创建新容器
diff 检查容器文件系统上文件或目录的更改
events 从服务器获取实时事件
exec 在运行的容器中运行命令
export 将容器的文件系统导出为tar包
history 显示镜像的历史
images 列出镜像
import 从tarball导入内容以创建文件系统镜像
info 显示整个系统的信息
inspect 返回Docker对象的底层信息
kill 停止一个或多个正在运行的容器
load 从tar包或标准输出加载镜像
login Log in to a Docker registry
logout Log out from a Docker registry
logs 获取容器的日志
pause 暂停一个或多个容器中的所有进程
port 列出容器的端口映射或特定映射
ps 列出正在运行的容器
pull 下载镜像
push 上传镜像
rename 重命令一个容器
restart 重启容器
rm 移除一个或多个容器
rmi 移除一个或多个镜像
run 在新容器中运行命令
save 将一个或多个图像保存到tar存档文件(默认情况下流到STDOUT)
search 在Docker仓库中搜索镜像
start 启动一个或多个处在停止状态的容器
stats 显示容器资源使用统计数据的实时流
stop 停止一个或多个正在运行的容器
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top 显示容器的运行进程
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version 查看版本
wait 阻塞直到一个或多个容器停止,然后打印它们的退出代码
子命令帮助docker COMMAND --help
退出容器不注销:Ctrl + P + Q
run在新容器中运行命令
docker run [选项] 镜像名 [shell 命令] [参数...]
-p list 指定容器的端口发布到主机
-P 将所有公开的端口发布到随机端口
--name string 为容器分配一个名称
-d 在后台运行容器并打印容器ID
-it 创建并进入容器
--rm 当容器退出时自动删除它
例如:
#docker run [镜像名] [shell 命令] docker run centos /bin/echo 'hello wold'
docker run -it /centos bash
docker run -P /nginx
方式 1:本地端口 81 映射到容器 80 端口: docker run -p 81:80 --name "nginx-test" nginx 方式 2:本地 IP:本地端口:容器端口 docker run -p 192.168.10.205:82:80 --name "nginx-test" /nginx 方式 3:本地 IP:本地随机端口:容器端口 docker run -p 192.168.10.205::80 --name "nginx-test" /nginx 方式 4:本机 ip:本地端口:容器端口/协议,默认为 tcp 协议 docker run -p 192.168.10.205:83:80/udp --name "nginx-test" /nginx 方式 5:一次性映射多个端口+协议: docker run -p 86:80/tcp -p 443:443/tcp -p 53:53/udp --name "nginx-test" /nginx 5. 后台启动容器 docker run -d -P --name "nginx-test" /nginx
docker run -it --rm --name nginx-test /nginx
docker run -it --rm --dns 223.6.6.6 centos bash
ps列出正在运行的容器
docker ps [OPTIONS]
-a 显示所有容器(默认显示正在运行)
-f 根据提供的条件过滤输出
-n int 显示最后创建的n个容器(包括所有状态)(默认值-1)
-l 显示最新创建的容器(包括所有状态)
--no-trunc 不截断输出
-q 只显示数字id
-s 显示总文件大小
例:
docker ps
docker ps -a
rm移除一个或多个容器
docker rm [OPTIONS] CONTAINER [CONTAINER...]
docker rm -f 11445b3a84d3 # 11445b3a84d3是CONTAINER ID,通过docker ps 查询
docker rm -f `docker ps -aq -f status=exited`
docker rm -f $(docker ps -a -q)
logs获取容器的日志
docker logs [OPTIONS] CONTAINER
--details 显示提供给日志的额外细节
-f 跟踪日志输出
--since string 显示从时间戳开始的日志(如:42m表示42 分钟)
--tail string 从日志末尾显示的行数(默认为“all”)
-t 显示时间戳
--until string 在时间戳前显示日志(如:42m表示42 分钟)
例:
docker logs nginx-test-port3 #一次查看
docker logs -f nginx-test-port3 #持续查看
load从tar存档或STDIN加载镜像
docker load [OPTIONS]
-i string 从tar存档文件中读取,而不是从STDIN中读取
-q 不输出
例:
docker load -i nginx.tar.gz
port列出容器的端口映射或特定映射
docker port CONTAINER [PRIVATE_PORT[/PROTO]]
docker port nginx-test
stop停止一个或多个正在运行的容器
docker stop [OPTIONS] CONTAINER [CONTAINER...]
-t int 等待stop几秒钟后再杀死它(默认为10)
例:
docker stop f821d0cd5a99
docker stop $(docker ps -a -q)
kill杀死一个或多个正在运行的容器
docker kill [OPTIONS] CONTAINER [CONTAINER...]
-s string 发送到容器的信号(默认为“KILL”)
例:
docker kill $(docker ps -a -q)
start启动一个或多个停止的容器
docker start [OPTIONS] CONTAINER [CONTAINER...]
-a 附加STDOUT/STDERR和转发信号
--detach-keys string 覆盖用于分离容器的键序列
-i 将容器的STDIN
例:
docker start f821d0cd5a99
attach此方式进入容器的操作都是同步显示的且 exit 后容器将被关闭
docker attach [OPTIONS] CONTAINER
--detach-keys string 覆盖用于分离容器的键序列
--no-stdin 不附加STDIN
--sig-proxy 代理所有接收到的进程信号(默认为true)
例: docker attach 63fbc2d5a3ec
exec执行单次命令与进入容器,不是很推荐此方式, 虽然 exit 退出容器还在运行
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
-d 分离模式:在后台运行命令
--detach-keys string 覆盖用于分离容器的键序列
-e list 设置环境变量
-i 保持STDIN打开,即使没有连接
--privileged 为该命令授予扩展特权
-t 分配一个pseudo-TTY
-u string 用户名或UID(格式:< name| UID >[:<group|gid>])
-w string 容器内的工作目录
例:
docker exec -it centos-test /bin/bash
inspect返回Docker对象的底层信息
docker inspect [OPTIONS] NAME|ID ...
-f string 使用给定的Go模板格式化输出
例:
# docker inspect -f "{{.State.Pid}}" centos-test3 5892
commit从容器的更改中创建一个新镜像
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
-a string 作者
-c list 对创建的映像应用Dockerfile指令
-m string 提交消息
-p 提交期间暂停容器(默认为true)
例:
docker commit -a "chen" -m "nginx_yum_v1" --change="EXPOSE_80_443" f5f8c13d0f9f centos-nginx:v1
docker commit -m "nginx image" f5f8c13d0f9f jack/centos-nginx:v1
Docker 镜像与制作Docker 镜像有没有内核? 为什么没有内核? 手动制作nginx镜像Docker 制作类似于虚拟机的镜像制作,即按照公司的实际业务务求将需要安装的软件、相关配置等基础环境配置完成,然后将其做成镜像,最后再批量从镜像批量生产实例,这样可以极大的简化相同环境的部署工作, Docker 的镜像制作分为手动制作和自动制作(基于 DockerFile), 企业通常都是基于 Dockerfile 制作精细, 其中手动制作镜像步骤具体如下: 下载镜像并初始化系统:
docker pull centos
docker run -it /centos /bin/bash
yum install wget -y
cd /etc/yum.repos.d/
rm -rf ./*
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum install –y nginx wget pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
vim /etc/nginx/nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; daemon off; 4. 自定义 web 页面 echo "Docker Yum Nginx" > /usr/share/nginx/html/index.html
5. 提交为镜像:在宿主机基于容器 ID 提交为镜像 docker commit -a "xu" -m "nginx_yum_v1" --change="EXPOSE 80 4433" 75f52cfb13d2 centos-nginx:v1
docker commit -m "nginx image" 75f52cfb13d2 centos-nginx:v3
6. 查看创建的镜像 docker image ls
7. 从自己镜像启动容器,因为本机用的是云主机,没有备案和域名,所以使用4433端口映射 docker run -d -p 4433:80 --name my-centos-nginx 87e99ab0c9ab /usr/sbin/nginx # 87e99ab0c9ab 是IMAGE ID
8. 访问测试 容器端口映射成功
Dockerfile介绍DockerFile 可以说是一种可以被 Docker 程序解释的脚本, DockerFile 是由一条条的命令组成的,每条命令对应 linux 下面的一条命令, Docker 程序将这些DockerFile 指令再翻译成真正的 linux 命令,其有自己的书写方式和支持的命令, Docker 程序读取 DockerFile 并根据指令生成 Docker 镜像,相比手动制作镜像的方式, DockerFile 更能直观的展示镜像是怎么产生的,有了 DockerFile,当后期有额外的需求时,只要在之前的 DockerFile 添加或者修改响应的命令即可重新生成新的 Docke 镜像,避免了重复手动制作镜像的麻烦。 FROM 指定基础镜像定制镜像,需要先有一个基础镜像,在这个基础镜像上进行定制。FROM 就是指定基础镜像,必需放在有效指令的第一行 怎么选择合适的镜像呢?官方有nginx、redis、mysql、httpd、tomcat等服务类的镜像,也有操作系统类,如:centos、ubuntu、debian等。 例: FROM centos:latest MAINTAINER 指定维护者信息格式 MAINTAINER <name> RUN 执行命令
格式 RUN <command> # 或 RUN ["executable", "param1", "param2"]
RUN yum -y install epel-release && yum -y install nginx && rm -rf /usr/share/nginx/html/* \ && echo "<h1> docker test nginx </h1>" > /usr/share/nginx/html/index.html
CMD 启动容器时执行的命令
支持三种格式 # 使用 exec 执行,推荐方式; CMD ["executable","param1","param2"] # 在 /bin/sh 中执行,提供给需要交互的应用; CMD command param1 param2 # 提供给 ENTRYPOINT 的默认参数; CMD ["param1","param2"]
如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。 EXPOSE 分配端口号
格式 EXPOSE <port> [<port>...] ENV 环境变量
格式 ENV <key> <value> 例如 ENV PG_MAJOR 9.3 ENV PG_VERSION 9.3.4 RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && … ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
ADD 复制/解压
格式 ADD <src> <dest> COPY 复制
格式 COPY <src> <dest>
当使用本地目录为源目录时,推荐使用 ENTRYPOINT 容器启动后执行的命令
两种格式: ENTRYPOINT ["executable", "param1", "param2"]
# shell中执行
ENTRYPOINT command param1 param2
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效 VOLUME 挂载点
格式 VOLUME ["/data"]。
USER 指定用户名
格式 USER daemon 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户, 例如: RUN groupadd -r postgres && useradd -r -g postgres postgres
要临时获取管理员权限可以使用 gosu,而不推荐 sudo。 WORKDIR 工作目录
格式 WORKDIR /path/to/workdir。 可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如 WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为 /a/b/c。 ONBUILD
格式 ONBUILD [INSTRUCTION]
例如,Dockerfile 使用如下的内容创建了镜像 image-A。 ...
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
...
如果基于 image-A 创建新的镜像时,新的Dockerfile中使用 FROM image-A指定基础镜像时,会自动执行ONBUILD 指令内容,等价于在后面添加了两条指令。 FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
使用 构建镜像格式 docker build [选项] 路径
docker build -t nginx:v1 /usr/local/src/
DockerFile 制作yum版 nginx 镜像:
mkdir -pv /opt/dockerfile/web/nginx
vim /opt/dockerfile/web/nginx/Dockerfile
#Nginx web image
FROM centos:latest
RUN yum install epel-release -y
RUN yum install nginx -y && rm -rf /usr/share/nginx/html/*
ADD html.tar.gz /usr/share/nginx/html/
#copy
EXPOSE 80 443 8080
CMD ["/usr/sbin/nginx","-g","daemon off;"]
vi /opt/dockerfile/web/nginx/index.html
tar czvf html.tar.gz index.html
docker build -t chenjb/centos-nginx /opt/dockerfile/web/nginx/
构建
6. 查看镜像 docker images
docker run -it -d -p 80:80 --name "nginx-test" chenjb/centos-nginx
docker ps
# curl 127.0.0.1:8355
DockerFile 制作编译版 nginx 镜像: 下载镜像并初始化系统:docker pull centos mkdir -pv /opt/dockerfile/web/nginx
编写 Dockerfile:vim /opt/dockerfile/web/nginx/Dockerfile
# 第一行先定义基础镜像,后面的本地有效的镜像名,如果本地没有会从远程仓库下载,第一行很重要
From centos:latest
# 镜像维护者的信息:
MAINTAINER han 583343636@qq.com
#自动解压压缩包
ADD nginx-1.16.1.tar.gz /usr/local/src/
#执行的命令,将编译安装 nginx 的步骤执行一遍
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
RUN yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
RUN cd /usr/local/src/nginx-1.16.1 && ./configure --prefix=/usr/local/nginx --with-http_sub_module && make && make install
RUN cd /usr/local/nginx/
ADD nginx.conf /usr/local/nginx/conf/nginx.conf
RUN useradd nginx -s /sbin/nologin
RUN ln -sv /usr/local/nginx/sbin/nginx /usr/sbin/nginx
RUN echo "Nginx-make version 1.16.1 test page" > /usr/local/nginx/html/index.html
# 向外开放的端口,多个端口用空格做间隔,启动容器时候-p 需要使用此端向外映射,如: -p 8081:80,则 80 就是这里的 80
EXPOSE 80 443
# 运行的命令,每个 Dockerfile 只能有一条,如果有多条则只有最后一条被执行
CMD ["nginx","-g","daemon off;"]
#如果在从该镜像启动容器的时候也指定了命令,那么指定的命令会覆盖Dockerfile 构建的镜像里面的 CMD 命令,即指定的命令优先级更高, Dockerfile 的优先级较低一些
准备源码包与配置文件:
cp /usr/local/nginx/conf/nginx.conf /opt/dockerfile/web/nginx
cp /usr/local/src/nginx-1.16.1.tar.gz /opt/dockerfile/web/nginx
docker build –t jack/nginx-1.16.1:v1 /opt/dockerfile/web/nginx/ 4. 开始构建:可以清晰看到各个步骤执行的具体操作 构建成功了 5. 查看是否生成本地镜像,如果构建时出错可能会导致生成名字为none的镜像,使用命令删除即可 docker images
docker rmi -f $(docker images | grep "none" | awk '{print $3}') #过滤出仓库名和tag名为none的镜像ID并强制删除 6. 从镜像启动容器 docker run -d -p 80:80 --name mak1e-nginx peterhx/nginx-make-1.16.1:v1 /usr/sbin/nginx
制作 tomcat 镜像:基于官方提供的 centos 7.6. 基础镜像构建 JDK 和 tomcat 镜像,先构建 JDK 镜像,然后再基于 JDK 镜像构建 tomcat 镜像。 1、先构建 JDK 镜像
docker pull centos
mkdir -pv /opt/dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}}
# JDK Base Images
FROM centos:latest
ADD jdk-8u212-linux-x64.tar.gz /usr/local/src/
RUN ln -sv /usr/local/src/jdk1.8.0_212 /usr/local/jdk
ADD profile /etc/profile
ENV JAVA_HOME /usr/local/jdk
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin
RUN rm -rf /etc/localtime && ln -snf /usr/share/zoneinfo/Asia/Shanghai/etc/localtime && echo "Asia/Shanghai" > /etc/timezone
profile文件内容,(最下边声明的环境变量,其他的一样) # cat profile 执行构建 cat build-command.sh
#!/bin/bash
docker build -t centos-jdk1.8:v1 .
5. 启动容器 docker run -it centos-jdk1.8:v1 bash
进入容器后,要能查看到Java的环境(如果查不出来等于白做,检查是哪个环节出错)
2、从 JDK 镜像构建 tomcat-8 镜像
cd /opt/dockerfile/web/tomcat
vim Dockerfile
FROM centos-jdk:v1
RUN useradd www -u 2020
ENV TZ "Asia/Shanghai"
ENV LANG en_US.UTF-8
ENV TERM xterm
ENV TOMCAT_MAJOR_VERSION 8
ENV TOMCAT_MINOR_VERSION 8.0.49
ENV CATALINA_HOME /apps/tomcat
ENV APP_DIR ${CATALINA_HOME}/webapps
RUN mkdir /apps
ADD apache-tomcat-8.5.42.tar.gz /apps
RUN ln -sv /apps/apache-tomcat-8.5.42 /apps/tomcat
# cat build-command.sh #!/bin/bash docker build -t tomcat85:v1 .
docker images
mkdir -p /opt/dockerfile/app/tomcat-app1
cd /opt/dockerfile/app/tomcat-app1/
vim Dockerfile
FROM tomcat85:v1
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
ADD myapp/* /apps/tomcat/webapps/myapp/
RUN chown www.www /apps/ -R
RUN chmod +x /apps/tomcat/bin/run_tomcat.sh
EXPOSE 8080 8009
CMD ["/apps/tomcat/bin/run_tomcat.sh"]
mkdir myapp echo "Docker Tomcat Web Page1" > myapp/index.html
vim run_tomcat.sh
cat build-command.sh #!/bin/bash docker build -t tomcat85-app1:v1 .
docker images
docker run -d -p 8888:8080 tomcat85-app1:v1 访问测试
制作 haproxy 镜像:
mkdir -pv /opt/dockerfile/app/haproxy cd /opt/dockerfile/app/haproxy
vim Dockerfile #Haproxy Base Image FROM centos ADD haproxy-2.0.5.tar.gz /usr/local/src/ RUN yum install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdump wget ntpdate –y && cd /usr/local/src/haproxy-2.0.5 && make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy && make install PREFIX=/usr/local/haproxy && cp haproxy /usr/sbin/ && mkdir /usr/local/haproxy/run ADD haproxy.cfg /etc/haproxy/ ADD run_haproxy.sh /usr/bin RUN chmod +x /usr/bin/run_haproxy.sh EXPOSE 80 9999 CMD ["/usr/bin/run_haproxy.sh"]
vim run_haproxy.sh
#!/bin/bash
haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
vim haproxy.cfg
global
chroot /usr/local/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
nbproc 1
pidfile /usr/local/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info
defaults
option http-keep-alive
option forwardfor
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:q1w2e3r4ys
listen web_port
bind 0.0.0.0:80
mode http
log global
balance roundrobin
server web1 192.168.99.21:8888 check inter 3000 fall 2 rise 5
server web2 192.168.99.22:8889 check inter 3000 fall 2 rise 5
6. 准备构建脚本: docker build -t haproxy:v1 .
7. 从镜像启动容器: docker run -it -d -p 80:80 -p 9999:9999 haproxy:v1
8. web 访问验证 9. 访问tomcat业务app1
本地镜像上传至官方 docker 仓库:
docker login
[root@Server1 ~]# cat /root/.docker/config.json { "auths": { "https://index./v1/": { "auth": "cGV0ZXJoeDo5NjExMjFoeC4=" }, "registry.cn-beijing.aliyuncs.com": { "auth": "NTgzMzQzNjM2QHFxLmNvbTo5NjExMjFoeA==" } }, "HttpHeaders": { "User-Agent": "Docker-Client/19.03.8 (linux)" } }
docker images
docker tag a187dde48cd2 peterhx/alpine-test:alpine123
docker push peterhx/alpine-test:alpine123
7. 到 docker 官网验证
8. 更换到其他 docker 服务器下载镜像 # 登录 docker login # 下载 docker pull peterhx/alpine-test:alpine123 # 查看 docker images
docker run -it peterhx/alpine-test:alpine123 bash
docker 仓库之分布式 HarborHarbor 是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器,由vmware 开源,其通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源 Docker Distribution。作为一个企业级私有 Registry 服务器,Harbor 提供了更好的性能和安全。提升用户使用 Registry 构建和运行环境传输镜像的效率。 Harbor 支持安装在多个 Registry 节点的镜像资源复制,镜像全部保存在私有 Registry 中, 确保数据和知识产权在公司内部网络中管控, 另外,Harbor 也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等。
Harbor 功能官方介绍:基于角色的访问控制:用户与 Docker 镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。镜像复制:镜像可以在多个 Registry 实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景。图形化用户界面:用户可以通过浏览器来浏览,检索当前 Docker 镜像仓库,管理项目和命名空间。 AD/LDAP: Harbor 可以集成企业内部已有的 AD/LDAP,用于鉴权认证管理。 审计管理:所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。国际化:已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。RESTful API - RESTful API :提供给管理员对于 Harbor 更多的操控, 使得与其它管理软件集成变得更容易。 部署简单:提供在线和离线两种安装工具, 也可以安装到 vSphere 平台(OVA 方式)虚拟设备。 安装 Harbor:
本次使用 harbor 版本 1.2.2 离线安装包,具体名称为 下载 Harbor 安装包:方式1:下载离线安装包:https://github.com/goharbor/harbor/releases cd /usr/local/src/ wget https://storage./harbor-releases/release-1.7.0/harbor-offline-installer-v1.7.5.tgz
方式2:下载在线安装包 cd /usr/local/src/ wget https://storage./harbor-releases/release-1.7.0/harbor-online-installer-v1.7.5.tgz
配置安装 Harbor:在另一台云主机的机器(内网IP为:192.168.0.59)上安装harbor仓库
tar xf harbor-offline-installer-v1.7.5.tgz
ln -sv /usr/local/src/harbor /usr/local/
cd /usr/local/harbor/
yum install python-pip epel-release -y
pip install docker-compose
安装docker-compose时报错,缺少依赖及python的开发环境,yum install -y gcc python-devel 即可
# vim harbor.cfg
...
hostname = 192.168.0.59
...
harbor_admin_password = harbor123
...
其它配置说明
# 写本机ip,不要写localho
4. 准备 ./prepare docker-compose.yml 文件,用于配置数据目录等配置信息 5. 运行当前目录下的脚本开始安装 ./install.sh 安装完成,可以通过设定的连接通过浏览器进行访问(默认使用的是80,加密端口是443,此主机没有备案所以下面还需要修改一下端口) 后期修改配置:如果 harbor 运行一段时间之后需要更改配置,则步骤如下:这里顺便修改一下harbor仓库的访问的默认端口 2. 编辑 harbor.cfg 进行相关配置:(修改之前一定要记得先copy一份) vim harbor.cfg # 主配置文件不需要修改 ① 这里修改了两个端口 80改为888,443改为了4433
② 修改完之后还要修改一个文件 # pwd
/usr/local/harbor/common/templates/registry
[root@Server2 registry]# ls
config.yml config.yml.bak root.crt
[root@Server2 registry]# vim config.yml
url后加上修改后的默认端口,保存退出 ③ 修改docker的启动文件 #vim /usr/lib/systemd/system/docker.service 修改如下一行 ExecStart=/usr/bin/dockerd --insecure-registry=x.x.x.x:888 修改后重新加载并重启服务 systemctl daemon-reload && systemctl restart docker.service 3. prepare ./prepare 4. 启动 harbor 服务: docker-compose start 登录测试一下,登录成功
常见的2个报错信息解答: (1)Error response from daemon: Get https://192.168.0.59/v1/users/: dial tcp 192.168.0.59:443: getsockopt: connection refused (2)Error response from daemon: Get https://192.168.0.59:888/v1/users/: http: server gave HTTP response to HTTPS client 报这2个错误的都是如下2个原因: 1、是端口错了! 2、未在docker启动文件中添加--insecure-registry信任关系! 大多数这个错误是第2个原因,因为你没有添加信任关系的话,docker默认使用的是https协议,所以端口不对(443),会报连接拒绝这个错误; 或者提示你 "服务器给HTTPS端的是HTTP响应" 这个错误,因为你没添加端口信任,服务器认为这是默认的https访问,返回的却是http数据!
解决方法: 正确的添加信任关系包括端口号: --insecure-registry=192.168.0.59:888 一定要把主机与端口同时添加进去! 继续
2. 查看本地端口 3. web 浏览器访问 Harbor 管理界面
如果可以正常登录就说明之前的配置没毛病,下面就可上传镜像了
配置 docker 使用 harbor 仓库上传下载镜像:
vim /lib/systemd/system/docker.service
在 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.0.59:888
systemctl daemon-reload && systemctl restart docker
docker login 192.168.0.59:888
如果这里突然遇到密码错误(确认不是忘记了密码),可以试试重启docker-compose docker-compose stop
docker-compose start
docker load < /root/alpine.tar.gz
docker images
首先要新建一个项目,进入项目里,右侧推送镜像,按照指定格式进行修改才能上传到此项目中来
docker tag alpine:latest X.X.X.X:888/alpine/alpine-test2:v4
docker push x.x.x.x:888/alpine/alpine-test2:v4
从 harbor 下载镜像并启动容器:
sudo vim /lib/systemd/system/docker.service
systemctl daemon-reload
systemctl restart docker
3. 查看下载命令:
docker pull X.X.X.X:888/alpine/alpine-test2:v4
docker run -it x.x.x.x:888/alpine/alpine-test2:v4 sh
7. 成功启动,并可以正常使用
实现 harbor 高可用:Harbor 支持基于策略的 Docker 镜像复制功能, 这类似于 MySQL 的主从同步, 其可以实现不同的数据中心、 不同的运行环境之间同步镜像, 并提供友好的管理界面,大大简化了实际运维中的镜像管理工作,已经有用很多互联网公司使用harbor 搭建内网 docker 仓库的案例,并且还有实现了双向复制的案列,本文将实现单向复制的部署:
复制的原理是从源harbor上推到目标harbor,所以下面的配置是要在之前创建的harbor上配置。
测试从 harbor 镜像下载和容器启动:
在 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.0.36:888 --insecure-registry 192.168.0.59:888
systemctl daemon-reload
systemctl restart docker
docker pull 192.168.0.36:888/alpine/alpine111:v10 5. 下载完后查看镜像
docker run -it 192.168.0.36:888/alpine/alpine111:v10 sh
Docker 数据管理如果运行中的容器修如果生成了新的数据或者修改了现有的一个已经存在的文件内容,那么新产生的数据将会被复制到读写层进行持久化保存,这个读写层也就是容器的工作目录,此即“写时复制(COW) copy on write”机制 数据类型:Docker 的镜像是分层设计的,底层是只读的,通过镜像启动的容器添加了一层可读写的文件系统,用户写入的数据都保存在这一层当中,如果要将写入的数据永久生效,需要将其提交为一个镜像然后通过这个镜像在启动实例,然后就会给这个启动的实例添加一层可读写的文件系统,目前 Docker 的数据类型分为两种, 一是数据卷, 二是数据容器,数据卷类似于挂载的一块磁盘,数据容器是将数据保存在一个容器上
docker inspect f55c55544e05
什么是数据卷(data volume):数据卷实际上就是宿主机上的目录或者是文件,可以被直接 mount 到容器当中使用。 实际生成环境中,需要针对不同类型的服务、 不同类型的数据存储要求做相应的规划, 最终保证服务的可扩展性、 稳定性以及数据的安全性。 如下图: 左侧是无状态的 http 请求服务, 右侧为有状态。 创建 APP 目录并生成 web 页面:此 app 以数据卷的方式,提供给容器使用, 比如容器可以直接宿主机本地的 web_app,而需要将代码提前添加到容器中,此方式适用于小型 web 站点。 mkdir /data/testapp –p
echo "testapp page" > /data/testapp/index.html
在宿主机或容器修改数据
mkdir /data/app
echo "docker volume Pages1" > /data/app/index.html
启动容器并验证数据:启动两个容器, web1 容器和 web2 容器, 分别测试能否在容器内访问到宿主机的添加的数据。 docker run -d --name web1 -v /data/app/:/usr/share/nginx/html -p 85:80 nginx
docker run -d --name web2 -v /data/app/:/usr/share/nginx/html:ro -p 86:80 nginx
2、web 界面访问(这里使用命令行测试) 3、删除容器 删除容器的时候指定参数-v, 可以删除/var/lib/docker/containers/的容器数据目录,但是不会删除数据卷的内容 docker rm -fv d044730c0f4f
数据卷的特点及使用:
如何一次挂载多个目录
mkdir /data/xuecho "xu" > /data/xu/index.html
docker run -ti -d --name web1 -p 85:80 -v /data/app/nginx.conf:/etc/nginx/nginx.conf:ro -v /data/nginx/:/usr/share/nginx/html nginx
3. 验证 web 访问 数据卷容器:数据卷容器功能是可以让数据在多个 docker 容器之间共享,即可以让 B 容器访问 A 容器的内容,而容器 C 也可以访问 A 容器的内容,\ 即先要创建一个后台运行的容器作为 Server,用于卷提供, 这个卷可以为其他容器提供数据存储服务,其他使用此卷的容器作为 client 端: 启动一个卷容器 Server:先启动一个容器, 并挂载宿主机的数据目录: docker run -d --name volume-server -v /data/app/nginx.conf:/etc/nginx/nginx.conf:ro -v /data/nginx:/usr/share/nginx/html nginx
docker run -d --name web1 -p 85:80 --volumes-from volume-server nginx
docker run -d --name web2 -p 86:80 --volumes-from volume-server nginx
docker run -d --name web3 -p 83:80 --volumes-from web2 nginx
三个容器访问到的数据是一样的
docker exec -it 85466a0c2fda bash
5. 验证宿主机数据 # cat /data/nginx/index.html 3333
docker stop volume-server docker run -d --name web6 -p 86:80 --volumes-from volume-server nginx 停止了卷服务的容器,还可以从这个卷服务容器启动新的容器
docker rm -fv volume-server [root@Server1 ~]# docker run -d --name web7 -p 87:80 --volumes-from volume-server nginx # 这里就不行了,报错
重新创建容器卷 Serverdocker run -d --name volume-server -v /data/app/nginx.conf:/etc/nginx/nginx.conf:ro -v /data/nginx:/usr/share/nginx/html nginx
创建出 volume server 之后, 就可以创建基于 volume server 的新容器。 docker run -d --name web8 -p 88:80 --volumes-from volume-server nginx
在当前环境下, 即使把提供卷的容器 Server 删除, 已经运行的容器 Client 依然可以使用挂载的卷, 因为容器是通过挂载访问数据的, 但是无法创建新的卷容器客户端, 但是再把卷容器 Server 创建后即可正常创建卷容器 Client, 此方式可以用于线上共享数据目录等环境, 因为即使数据卷容器被删除了,其他已经运行的容器依然可以挂载使用 数据卷容器可以作为共享的方式为其他容器提供文件共享,类似于 NFS 共享,可以在生产中启动一个实例挂载本地的目录,然后其他的容器分别挂载此容器的目录,即可保证各容器之间的数据一致性。
十五:主要介绍docker网络相关知识,docker服务安装完成之后,至少在每个主机机会生成一个名称为docker0的网卡
docker结合负载实现网站高可用:整体规划图:
1.安装并配置keepalived
yum install keepalived haproxy -y vim /etc/keepalived/keepalived.conf ... ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from root@localhost smtp_server localhost smtp_connect_timeout 30 router_id LVS_DEVEL1 vrrp_skip_check_adv_addr #vrrp_strict vrrp_iptables vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_instance MAKE_VIP_INT { state MASTER interface eth0 virtual_router_id 1 priority 100 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.99.10 dev eth0 label eth0:1 } }
启动 systemctl restart keepalived
systemctl enable keepalived
yum install keepalived haproxy –y
配置 vim /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from root@localhost smtp_server localhost smtp_connect_timeout 30 router_id LVS_DEVEL2 vrrp_skip_check_adv_addr #vrrp_strict vrrp_iptables vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_instance MAKE_VIP_INT { state BACKUP interface eth0 virtual_router_id 1 priority 50 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.99.10 dev eth0 label eth0:1 } } 启动 systemctl restart keepalived
systemctl enable keepalived
2.安装并配置haproxy
echo "net.ipv4.ip_nonlocal_bind=1" >> /etc/sysctl.conf sysctl -p
vim /etc/haproxy/haproxy.cfg global maxconn 100000 uid 99 gid 99 daemon nbproc 1 log 127.0.0.1 local0 info defaults option http-keep-alive #option forwardfor maxconn 100000 mode tcp timeout connect 500000ms timeout client 500000ms timeout server 500000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys #================================================================ frontend docker_nginx_web bind 0.0.0.0:80 mode http default_backend docker_nginx_hosts backend docker_nginx_hosts mode http balance roundrobin server 192.168.99.22 192.168.99.22:81 check inter 2000 fall 3 rise 5 server 192.168.99.23 192.168.99.23:81 check inter 2000 fall 3 rise 5 启动haproxy
systemctl enable haproxy
systemctl restart haproxy
vim /etc/haproxy/haproxy.cfg global maxconn 100000 uid 99 gid 99 daemon nbproc 1 log 127.0.0.1 local0 info defaults option http-keep-alive #option forwardfor maxconn 100000 mode tcp timeout connect 500000ms timeout client 500000ms timeout server 500000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys #================================================================ frontend docker_nginx_web bind 0.0.0.0:80 mode http default_backend docker_nginx_hosts backend docker_nginx_hosts mode http balance roundrobin server 192.168.99.22 192.168.99.22:81 check inter 2000 fall 3 rise 5 server 192.168.99.23 192.168.99.23:81 check inter 2000 fall 3 rise 5 启动haproxy
systemctl enable haproxy
systemctl restart haproxy
3. docker服务器启动nginx容器并验证
docker pull nginx docker run --name nginx-web1 -d -p 81:80 nginx 验证网络访问
docker pull nginx docker run --name nginx-web1 -d -p 81:80 nginx 验证网络访问
容器之间的互联通过容器名称互联:即在同一个主机上的容器之间可以通过自定义的容器名称相互访问,某个业务前端静态页面是使用nginx,动态页面使用的是tomcat,由于容器在启动的时候其内部IP地址是DHCP随机分配的,所以如果通过内部访问的话,自定义名称是相对比较固定的,因此比较适用于此场景。
docker run -it -d --name app1 -p 88:80 nginx
[root@Server1 ~]# docker exec -it app1 bash root@260fea18537b:/# 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 172.17.0.2 260fea18537b
docker run -it -d -p 89:80 --name app2 --link app1 nginx
[root@Server1 ~]# docker exec -it app2 bash root@cd11e8d1d51e:/# 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 172.17.0.2 app1 260fea18537b ## 连接的对方容器的 ID 和容器名称 172.17.0.3 cd11e8d1d51e
可能需要先安装ping工具 apt-get update && apt install -y iputils-ping
通过自定义容器别名互联:上一步骤中,自定义的容器名称可能后期会发生变化,那么一旦名称发生变化,程序之间也要随之发生变化,此类程序通过容器名称进行服务调用,但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用,每次都进行更改的话又比较麻烦,因此可以使用自定义别名的方式解决,即容器名称可以随意更容易,只要不更改别名即可,具体如下: docker run -d --name 新容器名称 --link 目标容器名称:自定义的名称 -p 本地端口:容器端口 镜像名称 shell命令
docker run -it -d -p 90:80 --name app3 --link app1:web1 nginx
[root@Server1 ~]# docker exec -it app3 bash
root@9b99ad938dbe:/# 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
172.17.0.2 web1 260fea18537b app1 # 多了一个别名web1
172.17.0.4 9b99ad938dbe
查看当前docke的网卡信息: docker network list
(1)主机模式:使用参数–net = host指定。 访问容器的时候直接使用主机机IP +容器端口即可,不过容器的其他资源他们必须文件系统,系统进程等还是和主机保持隔离。模式的网络性能最高,但是各个容器之间的端口不能相同,适用于运行容器端口比较固定的业务。
docker rm -fv `docker ps -a -q`
2. 启动一个新容器,并指定网络模式为主机 docker run -d --name app1 --net=host nginx
3. 访问
主机模式不支持端口映射,当指定端口映射的时候会提示如下警告信息: docker run -d --name app2 -p 81:80 --net=host nginx
(2)None模式:使用参数–net = none指定 命令使用方式: docker run -it -d --name net_none -p 80:80 --net=none nginx
(3)容器模式:使用参数–net = container:name或ID 使用此模式创建的容器需要指定和一个已经存在的容器共享一个网络,而不是和容纳机共享网,新创建的容器不会创建自己的网卡也不会配置自己的IP,或者和一个已经存在的被指定的容器IP和端口范围, 因此该容器的端口不能和被指定的端口冲突,除了网络之外的文件系统,进展信息等仍保持相互隔离,两个容器的进展可以通过lo网卡及容器IP进行通信。
docker run -it -d --name app11 -p 7070:8080 nginx
docker run -it -d --name app12 --net=container:app11 tomcat85-app1:v1
(4)bridge模式: docker的交替模式即不指定任何模式就是bridge模式,也是使用比较多的模式,此模式创建的容器会为每一个容器分配自己的网络IP等信息,且多个容器连接到一个虚拟网桥与外界通信 查看bridge模式的信息 docker network inspect bridge
docker跨主机互联之简单实现:跨主机互联是说A主机的容器可以访问B主机上的容器,但是可以保证各主机之间的网络是可以相互通信的,然后各容器才可以通过主机访问到对方的容器,实现原理是在主机做一个网络路由就可以实现A主机的容器访问B主机的容器的目的, 复杂的网络或者大型的网络可以使用google开源的k8s进行互联。 修改各主机机网段: Docker的替代网段是172.17.0.x / 24,而且每个主机机都是一样的,因此路由选择的路由就是各个主机的网络不能一致,具体如下: 服务器A:192.168.0.36
vim /lib/systemd/system/docker.service 在 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.0.1/24
systemctl daemon-reload
systemctl restart docker
如果你的系统是Centos,需要打开ipforward echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf sysctl -p
docker run -it -p 87:80 nginx bash [root@781e7f053c20 /]# ifconfig eth0
route add -net 10.10.0.0/24 gw 192.168.0.59
iptables -A FORWARD -s 192.168.0.0/24 -j ACCEPT
vim /lib/systemd/system/docker.service
在 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.20.0.1/24
systemctl daemon-reload
systemctl restart docker
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf sysctl -p
docker run -it -p 82:80 nginx bash
[root@781e7f053c20 /]# ifconfig eth0
route add -net 10.10.0.0/24 gw 192.168.0.36
iptables -A FORWARD -s 192.168.0.0/24 -j ACCEPT
容器间互相ping测试 在另一台容器里反ping试一下 如果可以ping通就表示没有问题,两个不同宿主机上的容器可以互相通信了
创建自定义网络:可以基于docker命令创建自定义网络,自定义网络可以自定义IP地域和网关等信息。 帮助 docker network create –help
docker network create -d bridge --subnet 10.100.0.0/24 --gateway 10.100.0.1 my-net
docker network list
[root@Server1 ~]# docker run -itd --net=my-net centos-nginx:v1 bash
[root@Server1 ~]# docker exec -it 25d2c84d58bd bash
[root@25d2c84d58bd /]# yum install -y net-tools &> /dev/null
[root@25d2c84d58bd /]# ifconfig eth0
docker run -it centos-nginx:v1 bash [root@ed06c2785c92 /]# ifconfig eth0 [root@ed06c2785c92 /]# ping www.baidu.com
iptables-save > iptables.sh
# vim iptables.sh
把DOCKER-ISOLATION-STAGE-2除了
iptables-restore < iptables.sh
4. 验证通信 先看一下其他网段的容器ip地址 ping测试一下 经过以上的配置,目前就已经实现了不通网络间的通信
十六、Docker资源限制
默认情况下, 容器没有资源限制, 可以使用主机内核调度程序允许的尽可能多的给定资源, Docker 提供了控制容器可以限制容器使用多少内存或 CPU 的方法,设置 docker run 命令的运行时配置标志。 如下所示:
对于 Linux 主机, 如果没有足够的内容来执行其他重要的系统任务, 将会抛出OOM (Out of Memory Exception,内存溢出、 内存泄漏、 内存异常), 随后系统会开始杀死进程以释放内存, 凡是运行在宿主机的进程都有可能被 kill, 包括 Dockerd和其它的应用程序, 如果重要的系统进程被 Kill,会导致和该进程相关的服务全部宕机。 产生 OOM 异常时, Dockerd 尝试通过调整 Docker 守护程序上的 OOM 优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死,但是容器的 OOM优先级未调整, 这使得单个容器被杀死的可能性比 Docker 守护程序或其他系统进程被杀死的可能性更大,不推荐通过在守护程序或容器上手动设置--oomscore-adj 为极端负数,或通过在容器上设置--oom-kill-disable 来绕过这些安全措施。 OOM 优先级机制:linux 会为每个进程算一个分数,最终他会将分数最高的进程 kill。
容器的内存限制:Docker 可以强制执行硬性内存限制,即只允许容器使用给定的内存大小。 --oom-score-adj: 宿主机 kernel 对进程使用的内存进行评分, 评分最高的将被宿主机内核 kill 掉, 可以指定一个容器的评分制但是不推荐手动指定。 内存限制参数:-m, --memory:容器可以使用的最大内存量,如果设置此选项,则允许的最内存值为 4m (4 兆字节)。 swap 限制:--memory-swap:只有在设置了 --memory 后才会有意义。使用 Swap,可以让容器将超出限制部分的内存置换到磁盘上, WARNING:经常将内存交换到磁盘的应用程序会降低性能。
动态修改容器内存,先计算出所需要的内存的字节数:如268435456(256M),只能调大不能调小 echo "268435456" > /sys/fs/cgroup/memory/docker/9fa20d824b18.../memory.limit_in_bytes
内存限制验证:假如一个容器未做内存使用限制, 则该容器可以利用到系统内存最大空间, 默认创建的容器没有做内存资源限制。
docker pull lorel/docker-stress-ng
查看帮助 apt install stress-ng
stress-ng --help
或者这样也行 docker run -it --rm lorel/docker-stress-ng -help
内存大小硬限制查看docker状态 docker stats
docker run -it --rm --name c1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
docker run -it --rm -m 256m --name c2 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
# cat /sys/fs/cgroup/memory/docker/容器 ID /memory.limit_in_bytes
268435456
内存大小软限制:docker run -it --rm -m 256m --memory-reservation 128m --name c3 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
# cat /sys/fs/cgroup/memory/docker/容器 ID/memory.soft_limit_in_bytes
134217728
关闭 OOM 机制docker run -it --rm -m 256m --oom-kill-disable --name c4 lorel/dockerstress-ng --vm 2 --vm-bytes 256M
# cat /sys/fs/cgroup/memory/docker/容器 ID/memory.oom_control
oom_kill_disable 1
under_oom 1
oom_kill 0
交换分区限制docker run -it --rm -m 256m --memory-swap 512m --name magedu-c1 centos bash
宿主机 cgroup 验证: # cat /sys/fs/cgroup/memory/docker/容器 ID/memory.memsw.limit_in_bytes
536870912
容器的 CPU 限制一个宿主机,有几十个核心的 CPU, 但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务, 多进程共用一个 CPU 的核心依赖计数就是为可压缩资源, 即一个核心的 CPU 可以通过调度而运行多个进程, 但是同一个单位时间内只能有一个进程在 CPU 上运行, 那么这么多的进程怎么在 CPU 上执行和调度的呢? 实时优先级: 0 - 99 非实时优先级(nice): -20 - 19, 对应 100 - 139 的进程优先级 Linux kernel 进程的调度基于 CFS(Completely Fair Scheduler), 完全公平调度 CPU 密集型的场景:优先级越低越好, 计算密集型任务的特点是要进行大量的计算,消耗 CPU 资源,比如计算圆周率、 数据处理、 对视频进行高清解码等等,全靠 CPU 的运算能力。 IO 密集型的场景:优先级值高点, 涉及到网络、磁盘 IO 的任务都是 IO 密集型任务,这类任务的特点是 CPU 消耗很少,任务的大部分时间都在等待 IO 操作完成(因为 IO 的速度远远低于 CPU 和内存的速度),比如 Web 应用, 高并发,数据量大的动态网站来说,数据库应该为 IO 密集型。 磁盘的调度算法 # cat /sys/block/sda/queue/scheduler
noop deadline [cfq]
默认情况下,每个容器对主机 CPU 周期的访问权限是不受限制的, 但是我们可以设置各种约束来限制给定容器访问主机的 CPU 周期,大多数用户使用的是默认的 CFS 调度方式, 在 Docker 1.13 及更高版本中, 还可以配置实时优先级。 参数:--cpus :指定容器可以使用多少可用 CPU 资源, 例如,如果主机有两个 CPU,并且设置了--cpus =“1.5”,那么该容器将保证最多可以访问 1.5 个的 CPU(如果是 4 核 CPU, 那么还可以是 4 核心上每核用一点,但是总计是 1.5 核心的CPU), 这相当于设置--cpu-period =“100000”和--cpu-quota =“150000” 分配给容器的 CPU 超出了宿主机 CPU 总数。 # docker run -it --rm --cpus 2 centos bash
docker: Error response from daemon: Range of CPUs is from 0.01 to 1.00, as there are only 1 CPUs available.
See 'docker run --help'.
测试 CPU 限制
docker run -it --rm --name c10 lorel/docker-stress-ng --cpu 4 --vm 4
在宿主机使用 dokcer top 命令查看容器运行状态 docker top CONTAINER [ps OPTIONS]
容器运行状态: docker stats 在宿主机查看 CPU 限制参数: # cat /sys/fs/cgroup/cpuset/docker/${容器ID}/cpuset.cpus
0-3
docker run -it --rm --name c11 --cpus 2 lorel/docker-stress-ng --cpu 4 --vm 4
宿主机 cgroup 验证 # cat /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.cfs_quota_us 200000
宿主机 CPU 利用率
docker run -it --rm --name c12 --cpus 1 --cpuset-cpus 1,3 lorel/docker-stress-ng --cpu 2 --vm 2 # cat /sys/fs/cgroup/cpuset/docker/容器 ID /cpuset.cpus 1,3 容器运行状态
docker run -it --rm --name c13 --cpu-shares 10 lorel/docker-stress-ng --cpu 1 --vm 2
docker run -it --rm --name c14 --cpu-shares 5 lorel/docker-stress-ng --cpu 1 --vm 2
验证容器运行状态
宿主机 cgroup 验证 # cat /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.shares
1000
# cat /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.shares
500
echo 2000 > /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.shares
验证修改后的容器运行状态 docker stats 十七单机编排之Docker撰写:当在主机启动主机的容器时候,如果都是手动操作会觉得比较麻烦而且容器出错,这个时候推荐使用docker单机编排工具docker-compose,docker-compose是docker容器的一种单机编排服务,docker- compose是一个管理多个容器的工具,可以解决容器之间的依赖关系,就像启动一个nginx前端服务的时候会调用后端的tomcat,那就得先启动tomcat,但是启动tomcat容器还需要依赖数据库,则那就还得先启动数据库,docker-compose就可以解决这样的嵌套依赖关系,其完全可以替代docker run对容器进行创建,启动和停止。 docker-compose项目是Docker官方的开源项目,负责实现对Docker容器放置的快速编排,docker-compose将所管理的容器分为三层,分别是工程(项目),服务以及容器
基础环境准备:
配置安装港口:
cd /usr/local/src/ wget https://storage./harbor-releases/release-1.7.0/harbor-offline-installer-v1.7.5.tgz
tar xf harbor-offline-installer-v1.7.5.tgz ln -sv /usr/local/src/harbor /usr/local/
apt update apt install -y python-pip pip install docker-compose 中心: yum install epel-release yum install -y python-pip pip install --upgrade pip pip install docker-compose
# vim harbor.cfg ... hostname = 192.168.99.22 ... harbor_admin_password = root123 ...
vim /lib/systemd/system/docker.service 在ExecStart追加 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.99.21
制作nginx镜像
docker pull centos mkdir -pv /opt/dockerfile/web/nginx/html
cd /opt/dockerfile/web/nginx vim Dockerfile From centos:latest MAINTAINER han 123456@qq.com ADD nginx-1.10.3.tar.gz /usr/local/src/ RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm \ && yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop && cd /usr/local/src/nginx-1.10.3 && ./configure --prefix=/usr/local/nginx --with-http_sub_module && make && make install && cd /usr/local/nginx/ ADD nginx.conf /usr/local/nginx/conf/nginx.conf RUN useradd nginx -s /sbin/nologin && ln -sv /usr/local/nginx/sbin/nginx /usr/sbin/nginx && echo "test nginx page" > /usr/local/nginx/html/index.html EXPOSE 80 443 CMD ["nginx","-g","daemon off;"]
cd /opt/dockerfile/web/nginx/html echo "test nginx" > index.html cd /opt/dockerfile/web/nginx vim nginx.conf #user nobody; worker_processes 1; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /usr/local/nginx/html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
# cd .. # tree . . ├── Dockerfile ├── html │ └── index.html ├── nginx-1.10.3.tar.gz └── nginx.conf
docker build -t mynginx:v1 /opt/dockerfile/web/nginx
docker run --rm -p 81:80 --name nginx-web1 -v /opt/dockerfile/web/nginx/html/:/usr/local/nginx/html/ -v /opt/dockerfile/web/nginx/nginx.conf:/usr/local/nginx/conf/nginx.conf mynginx:v1
docker tag mynginx:v1 192.168.99.21/nginx/mynginx:v1
docker push 192.168.99.21/nginx/mynginx:v1
制作JDK环境
mkdir -p /opt/dockerfile/web/jdk cd /opt/dockerfile/web/jdk/
vim Dockerfile #JDK Base Image FROM centos:latest ADD jdk-8u211-linux-x64.tar.gz /usr/local/src/ RUN ln -sv /usr/local/src/jdk1.8.0_211 /usr/local/jdk ADD profile /etc/profile ENV JAVA_HOME /usr/local/jdk ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/ ENV PATH $PATH:$JAVA_HOME/bin RUN rm -rf /etc/localtime && ln -snf /usr/share/zoneinfo/Asia/Shanghai/etc/localtime && echo "Asia/Shanghai" > /etc/timezone
# /etc/profile # System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=`/usr/bin/hostname 2>/dev/null` HISTSIZE=1000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL # By default, we want umask to get set. This sets it for login shell # Current threshold for system reserved uid/gids is 200 # You could check uidgid reservation validity in # /usr/share/doc/setup-*/uidgid file if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge export JAVA_HOME=/usr/local/jdk export TOMCAT_HOME=/apps/tomcat export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$TOMCAT_HOME/bin:$PATH export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
# tree /opt/dockerfile/web/jdk /opt/dockerfile/web/jdk ├── Dockerfile ├── jdk-8u211-linux-x64.tar.gz └── profile
cd /opt/dockerfile/web/jdk
docker build -t myjdk:v1 .
docker tag myjdk:v1 192.168.99.21/jdk/myjdk:v1
docker push 192.168.99.21/jdk/myjdk:v1
从JDK整合重构tomcat
mkdir -p /opt/dockerfile/web/tomcat cd /opt/dockerfile/web/tomcat
vim Dockerfile FROM 192.168.99.21/jdk/myjdk:v1 RUN useradd www -u 2020 ENV TZ "Asia/Shanghai" ENV LANG en_US.UTF-8 ENV TERM xterm ENV TOMCAT_MAJOR_VERSION 8 ENV TOMCAT_MINOR_VERSION 8.0.49 ENV CATALINA_HOME /apps/tomcat ENV APP_DIR ${CATALINA_HOME}/webapps RUN mkdir /apps ADD apache-tomcat-8.5.45.tar.gz /apps RUN ln -sv /apps/apache-tomcat-8.5.45 /apps/tomcat
tree /opt/dockerfile/web/tomcat /opt/dockerfile/web/tomcat ├── apache-tomcat-8.5.45.tar.gz └── Dockerfile
docker build -t mytomcat:v1 .
docker tag mytomcat:v1 192.168.99.21/tomcat/mytomcat:v1
docker push 192.168.99.21/tomcat/mytomcat
构建tomcat-app业务运营:
mkdir -pv /opt/dockerfile/web/tomcat-app cd /opt/dockerfile/web/tomcat-app
vim Dockerfile FROM 192.168.99.21/tomcat/mytomcat:v1 ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh ADD myapp/* /apps/tomcat/webapps/myapp/ RUN chown www.www /apps/ -R RUN chmod +x /apps/tomcat/bin/run_tomcat.sh EXPOSE 8080 8009 CMD ["/apps/tomcat/bin/run_tomcat.sh"]
mkdir myapp echo "MyTomcat Web app Page1" > myapp/index.html
vim run_tomcat.sh #!/bin/bash echo "nameserver 223.5.5.5" > /etc/resolv.conf su - www -c "/apps/tomcat/bin/catalina.sh start" su - www -c "tail -f /etc/hosts"
# tree . ├── Dockerfile ├── myapp │ └── index.html └── run_tomcat.sh
docker build -t mytomcat-app:v1 .
docker tag mytomcat-app:v1 192.168.99.21/tomcat/mytomcat-app:v1
docker push 192.168.99.21/tomcat/mytomcat-app:v1
制作haproxy补充:
mkdir -pv /opt/dockerfile/app/haproxy cd /opt/dockerfile/app/haproxy
vim Dockerfile #Haproxy Base Image FROM centos ADD haproxy-2.0.5.tar.gz /usr/local/src/ RUN yum -y install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdump wget ntpdate && cd /usr/local/src/haproxy-2.0.5 && make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy && make install PREFIX=/usr/local/haproxy && cp haproxy /usr/sbin/ && mkdir /usr/local/haproxy/run ADD haproxy.cfg /etc/haproxy/ ADD run_haproxy.sh /usr/bin RUN chmod +x /usr/bin/run_haproxy.sh EXPOSE 80 9999 CMD ["/usr/bin/run_haproxy.sh"]
vim run_haproxy.sh #!/bin/bash haproxy -f /etc/haproxy/haproxy.cfg tail -f /etc/hosts
vim haproxy.cfg global chroot /usr/local/haproxy #stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin uid 99 gid 99 daemon nbproc 1 pidfile /usr/local/haproxy/run/haproxy.pid log 127.0.0.1 local3 info defaults option http-keep-alive option forwardfor mode http timeout connect 300000ms timeout client 300000ms timeout server 300000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys listen web_port bind 0.0.0.0:80 mode http log global balance roundrobin server web1 192.168.99.22:81 check inter 3000 fall 2 rise 5
docker build -t haproxy:v1 .
docker tag haproxy:v1 192.168.99.21/haproxy/haproxy:v1
从docker compose启动临时容器换成server2继续:
apt update apt install -y python-pip pip install docker-compose Centos: yum install epel-release yum install -y python-pip pip install --upgrade pip pip install docker-compose
docker-compose -v
在 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.99.21
systemctl daemon-reload
systemctl restart docker
mkdir -pv /opt/dockerfile/web/nginx/html cd /opt/dockerfile/web/nginx/html echo "test nginx" > index.html
cd /opt/ mkdir docker-compose cd docker-compose
vim docker-compose.yml service-nginx-web: image: 192.168.99.21/nginx/mynginx:v1 container_name: nginx-web1 expose: - 80 - 443 ports: - "80:80" - "443:443" volumes: - "/opt/dockerfile/web/nginx/html/:/usr/local/nginx/html/"
# docker ps | grep nginx 1e453106ca9c 192.168.99.21/nginx/mynginx:v1 "nginx -g 'daemon of…" 49 seconds ago Up 47 seconds 443/tcp, 0.0.0.0:80->80/tcp
启动多个容器docker pull 192.168.99.21/tomcat/mytomcat-app:v1
cd /opt/docker-compose/ vim docker-compose.yml service-nginx-web: image: 192.168.99.21/nginx/mynginx:v1 container_name: nginx-web1 expose: - 80 - 443 ports: - "81:80" - "443:443" volumes: - "/opt/dockerfile/web/nginx/html/:/usr/local/nginx/html/" service-tomcat-app1: image: 192.168.99.21/tomcat/mytomcat-app:v1 container_name: tomcat-app1 expose: - 8080 ports: - "8080:8080"
docker-compose restart/stop/start service-nginx-web
docker-compose restart
实现Nginx反向代理Tomcat创建nginx配置文件
mkdir /opt/app mkdir -p nginx/html/app{1..2} cd /opt/app mkdir -p nginx/conf cd nginx/conf
vim nginx.conf #user nobody; worker_processes 1; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main 'remote_addr - remote_user [time_local] "request" ' # 'status body_bytes_sent "http_referer" '
echo app111111 > /opt/app/nginx/html/app1/index.html echo app222222 > /opt/app/nginx/html/app2/index.html
创建haproxy配置文件cd /opt/app mkdir -p haproxy/conf
准备tomcat配置文件cd /opt/app mkdir -p tomcat/conf
vim tomcat/conf/server.xml <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- Note: A "Server" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/server.html --> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <!-- Security listener. Documentation at /docs/config/listeners.html <Listener className="org.apache.catalina.security.SecurityListener" /> --> <!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <!-- A "Service" is a collection of one or more "Connectors" that share a single "Container" Note: A "Service" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/service.html --> <Service name="Catalina"> <!--The connectors can use a shared executor, you can define one or more named thread pools--> <!-- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> --> <!-- A "Connector" represents an endpoint by which requests are received and responses are returned. Documentation at : Java HTTP Connector: /docs/config/http.html Java AJP Connector: /docs/config/ajp.html APR (HTTP/AJP) Connector: /docs/apr.html Define a non-SSL/TLS HTTP/1.1 Connector on port 8080 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- A "Connector" using the shared thread pool--> <!-- <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> --> <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 This connector uses the NIO implementation. The default SSLImplementation will depend on the presence of the APR/native library and the useOpenSSL attribute of the AprLifecycleListener. Either JSSE or OpenSSL style configuration may be used regardless of the SSLImplementation selected. JSSE style configuration is used below. --> <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true"> <SSLHostConfig> <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" type="RSA" /> </SSLHostConfig> </Connector> --> <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2 This connector uses the APR/native implementation which always uses OpenSSL for TLS. Either JSSE or OpenSSL style configuration may be used. OpenSSL style configuration is used below. --> <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true" > <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> <SSLHostConfig> <Certificate certificateKeyFile="conf/localhost-rsa-key.pem" certificateFile="conf/localhost-rsa-cert.pem" certificateChainFile="conf/localhost-rsa-chain.pem" type="RSA" /> </SSLHostConfig> </Connector> --> <!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- An Engine represents the entry point (within Catalina) that processes every request. The Engine implementation for Tomcat stand alone analyzes the HTTP headers included with the request, and passes them on to the appropriate Host (virtual host). Documentation at /docs/config/engine.html --> <!-- You should set jvmRoute to support load-balancing via AJP ie : <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"> --> <Engine name="Catalina" defaultHost="localhost"> <!--For clustering, please take a look at documentation at: /docs/cluster-howto.html (simple how to) /docs/config/cluster.html (reference documentation) --> <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> --> <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="/data/tomcat/webapps/app" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service> </Server>
cd /opt/app mkdir -p tomcat/app1/tomcat-app cd tomcat/app1/tomcat-app
vim showhost.jsp <%@page import="java.util.Enumeration"%> <br /> host: <%try{out.println(""+java.net.InetAddress.getLocalHost().getHostName());}catch(Exception e){}%> <br /> remoteAddr: <%=request.getRemoteAddr()%> <br /> remoteHost: <%=request.getRemoteHost()%> <br /> sessionId: <%=request.getSession().getId()%> <br /> serverName:<%=request.getServerName()%> <br /> scheme:<%=request.getScheme()%> <br /> <%request.getSession().setAttribute("t1","t2");%> <% Enumeration en = request.getHeaderNames(); while(en.hasMoreElements()){ String hd = en.nextElement().toString(); out.println(hd+" : "+request.getHeader(hd)); out.println("<br />"); } %>
创建docker-compose.ymlmkdir -p /opt/app cd /opt/app vim docker-compose.yml service-haproxy: image: 192.168.99.21/haproxy/haproxy:v1 container_name: haproxy volumes: - ./haproxy/conf/haproxy.cfg:/etc/haproxy/haproxy.cfg expose: - 80 - 443 - 9999 ports: - "80:80" - "443:443" - "9999:9999" links: - service-nginx-web service-nginx-web: image: 192.168.99.21/nginx/mynginx:v1 container_name: nginx-web1 volumes: - ./nginx/html/app1:/apps/nginx/html/app1 - ./nginx/html/app2:/apps/nginx/html/app2 - ./nginx/conf/nginx.conf:/usr/local/nginx/conf/nginx.conf expose: - 80 - 443 links: - service-tomcat-app1 - service-tomcat-app2 service-tomcat-app1: image: 192.168.99.21/tomcat/mytomcat-app:v1 container_name: tomcat-app1 volumes: - ./tomcat/app1:/data/tomcat/webapps/app/ROOT - ./tomcat/conf/server.xml:/apps/tomcat/conf/server.xml expose: - 8080 service-tomcat-app2: image: 192.168.99.21/tomcat/mytomcat-app:v1 container_name: tomcat-app2 volumes: - ./tomcat/app1:/data/tomcat/webapps/app/ROOT - ./tomcat/conf/server.xml:/apps/tomcat/conf/server.xml expose: - 8080 最终文件目录cd /opt/app # tree . ├── docker-compose.yml ├── haproxy │ └── conf │ └── haproxy.cfg │ ├── nginx │ ├── conf │ │ └── nginx.conf │ └── html │ ├── app1 │ │ └── index.html │ └── app2 │ └── index.html └── tomcat ├── app1 │ └── tomcat-app │ └── showhost.jsp └── conf └── server.xml 测试访问http://192.168.99.22/tomcat-app/showhost.jsp
以上就是Docke容器大部分的使用情景及功能实现 |
|