之前弄过的webNotepad,基于hexo到的博客,已经提供代理的nginx等,在新机上部署时都需要一堆繁琐的配置过程。刚好在看公司项目内网测试环境的docker脚本,于是想试试将之前部署的这些东西都迁移到docker容器内,体验一下docker的应用。

安装docker

1
2
3
4
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker

常用的几个命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看本地镜像列表
docker images
# 查看所有容器
docker ps -a
# 拉取镜像
docker pull ***
# 删除镜像
docker rmi ***
# 运行容器 itd 分别为交互操作,终端, 后台运行 --name 指定运行的容器名称 -v 映射匿名卷 -p 映射端口 后两个参数是 镜像名称 和 运行容器后执行的命令
docker run -itd --name ** -v ** - p ** *** bash
# 删除容器
docker rm -f **
# 进入正在运行的容器 -it 与 run中的意思相同
docker exec -it ** bash
# 使用容易创建镜像
docker commit *** ***
# 使用dockerfile构建镜像
docker build ***

在docker中部署程序体验

nginx

1
2
3
4
5
6
7
8
# 先拉取镜像
docker pull nginx:latest
# 运行容器 将nginx的配置文件映射到容器内对应目录, 映射外部需要访问的端口
docker run -itd --name nginx -v `pwd`/nginx/logs:/var/log/nginx -v `pwd`/nginx/conf.d:/etc/nginx/conf.d -v `pwd`/nginx/ssl:/etc/nginx/ssl -v `pwd`/nginx/html:/usr/share/nginx/html -p 80:80 -p 443:443 nginx bash
# 可以进入容器内 进行交互
docker exec -it nginx bash

# 使用nginx访问不同的容器端口

tomcat

1
2
docker  pull tomcat
docker run -itd --name tomcat -v `pwd`/tomcat/logs:/usr/local/tomcat/logs -v `pwd`/tomcat/webapps:/usr/local/tomcat/webapps -v `pwd`/tomcat/conf:/usr/local/tomcat/conf -p 8081:8081 tomcat bash

进浏览器访问

已经可以正常访问tomcat下webapps目录下部署的webNotepad页面了

dockerfile

dockerfile是构建镜像的配置文件,可以指定镜像的基础镜像,在构建的时候执行一些命令,指定镜像的匿名卷,暴露的端口等。主要就是各个指令的具体用法,随便一搜一大把,比如这个:点这里, 如果访问不了了,去搜一下就有了

dockerfile里面的run是在构建镜像的时候执行的命令,每一个命令都会包一层容器,所以最好将所有的命令组合到一条命令,例如:

1
2
3
RUN echo "start" \
&& npm install \
&& echo "end"

docker-compose

这是一个运行多容器的一个工具,使用yml配置程序需要的所有服务(容器),通过docker-compose命令可以批量管理所有服务。

安装

1
2
3
4
5
# 这个安装方法真粗暴
wget https://github.com/docker/compose/releases/download/1.26.0-rc3/docker-compose-Linux-x86_64
chmod +x docker-compose
mv docker-compose /usr/local/bin
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

常用命令

1
2
3
4
5
6
7
8
9
10
# 创建并运行所有的服务 -d 可选 代表后台运行
docker-compose up -d
# 停止并删除所有的服务
docker-compose down
# 运行所有/指定的服务
docker-compose start ***
# 停止所有/指定的服务
docker-compose stop ***
# 进入某一服务内部
docker-compose exec *** bash

docker-compose.yml

docker-compose的配置文件,可以配置各个容器服务的具体信息,结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
version: "3.7"
services:
nginx:
image: nginx
container_name: docker-nginx
volumes:
- "/root/docker/nginx/logs:/var/log/nginx"
- "/root/docker/nginx/conf.d:/etc/nginx/conf.d"
- "/root/docker/nginx/ssl:/etc/nginx/ssl"
- "/var/data:/var/data"
ports:
- "80:80"
- "443:443"
environment:
- "TZ=Asia/Shanghai"
webapp:
image: tomcat
container_name: docker-webapp
volumes:
- "/root/docker/tomcat/logs:/usr/local/tomcat/logs"
- "/root/docker/tomcat/ROOT:/usr/local/tomcat/webapps/ROOT"
- "/root/docker/tomcat/conf:/usr/local/tomcat/conf"
expose:
- "8081"
environment:
- "TZ=Asia/Shanghai"
hexo:
build: ./hexo
container_name: docker-hexo
volumes:
- "/root/docker/hexo/posts:/hexo/source/_posts"
- "/root/docker/hexo/hblog-src/entrypoint.sh:/hexo/entrypoint.sh"
- "/root/docker/hexo/hblog-src/posts:/hexo/posts"
expose:
- "4000"
environment:
- "TZ=Asia/Shanghai"

services 下为所有的容器,每日一个容器(nginx)下可以配置指导的镜像,容器名,匿名卷映射等,每个容器下个参数的意义基本与dockerfile的类似,可参考访问不了了,就随便搜一份

几个快捷指令

1
2
3
4
5
# 批量删除所有已退出的容器
docker rm -f `docker ps -a | grep "Exited" | grep -v "grep" | awk '{print $NF}'`
# 批量删除所有无标签的镜像
docker rmi -f `docker images | grep "<none>" | grep -v "grep" | awk '{print $3}'`

遇到的几个问题

webNotepad websocket无法连接

表现就是将webNotepad部署在tomcat容器中时,webNotepad可以访问,但是界面显示connect closed,在浏览器中F12 发现wss://*** 404了。

首先以为是nginx转发https的问题,于是把tomcat容器的暴露端口改为映射到宿主机,直接通过宿主机ip访问,依然出现ws://*** 404, 无果。

然后一番搜索,网上大部分解答都是 容器内的websocket监听的是本地地址,需要把localhost或者127.0.0.1 改成0.0.0.0 以便可以监听所有的地址。因为在容器没有netstat命令, 无法查看监听端口,且没有找到ServerEndPoint修改监听地址的地方,理论上应该是tomcat监听的哪就是哪,所以直接将tomcat运行到宿主机,通过netstat命令查看,发现已经是监听的0.0.0.0了,而且如果不是监听的0.0.0.0的话,就算部署在宿主机,在公网上也应该无法连接才对。

然后怀疑是docker的网络桥接会导致其中某一个握手过程不成功,于是将tomcat容器的网络 改成host,也就是直接使用宿主机网络,在宿主机中通过netstat命令可以看到,已经存在一个java进程在监听0.0.0.0:8081 了,就是我们的tomcat,结果用浏览器一连,依然是404。

排除了这些可能的因素以后,已经不知道直接部署在宿主机和部署在docker内有什么区别了,为了找更多的不同,分别的宿主机和docker内各运行了一次,然后截图tomcat的启动日志以及浏览器访问留下的日志。最后发现只有tomcat版本,以及java版本不同。tomcat 容器默认使用的是tomcat8 openjdk8,而宿主机是之前手动装的tomcat9 以及openjdk11。

虽然不知道是不是因为版本,但最后还是尝试了一次,不直接使用tomcat的镜像,写了一个dockerfile, form centos7.7 将手动下载的tomcat 解压到容器,然后安装jdk11, 再在容器跑tomcat的时候,websocket终于可以顺利连上了。

jenkins修改插件镜像源

在修改jenkins插件源时,因为国内源仅仅是复制了插件仓库,但是update.json里面的地址依然指向国外,所以在修改了update.json的所在地址之外,还需要将update.json中的国外地址通过host指向本地,然后通过nginx定向到想要的国内源。修改host的时候遇到了在build镜像的时候对hosts文件无访问权限。

尝试用USER 指令先将 用户换成 root, 修改完hosts之后再换回jenkins,但是依然出现了 sed: cannot rename /etc/sedR5SWIO: Device or resource busy

在网上搜索,发现是sed命令本质上是生成一个修改后的新文件,再替换原文件,但是在镜像构建过程中,这个文件是挂载进容器的,这样删除原文件,替换新文件就会出现上面的问题。但是echo命令就不需要删除原文件,于是将原来的 sed -i '$anginx mirrors.jenkins-ci.org' /etc/hosts 修改为 echo "$(sed '$anginx mirrors.jenkins-ci.org' /etc/hosts)" > /etc/hosts

然后发现自己傻了,这样根本行不通,每次docker启动的时候都会更新hosts文件,而往容器里增加域名解析,只需要在docker-compose.yml 中添加extra-hosts 就可以了。

普通用户使用docker

1
2
3
4
5
6
7
8
# 查看是否有docker组
cat /etc/group

# 如果没有docker组 则添加
groupadd docker

# 将普通用户添加到docker组
usermod -G docker sictiy

将docker的基本目录从root目录,移动到sictiy的home目录后,需要修改docker的columns 映射到修改后的目录,每次都需要修改docker-compose.yml 太麻烦了,在.yml的同目录下添加.env文件,添加BASE_DIR=/home/sictiy/docker, 并将docker-compose.yml 中所有目录修改为${BASE_DIR}***

最后的docker-compose.yml为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
version: "3.7"
services:
nginx:
image: nginx
container_name: docker-nginx
volumes:
- "${BASE_DIR}/nginx/logs:/var/log/nginx"
- "${BASE_DIR}/nginx/conf.d:/etc/nginx/conf.d"
- "${BASE_DIR}/nginx/ssl:/etc/nginx/ssl"
- "/var/data:/var/data"
ports:
- "80:80"
- "443:443"
environment:
- "TZ=Asia/Shanghai"
jenkins:
image: jenkins/jenkins
#build: ./jenkins
container_name: docker-jenkins
volumes:
- "${BASE_DIR}/jenkins/logs:/var/log/jenkins"
#- "${BASE_DIR}/jenkins/home:/var/jenkins_home"
- "/home/jenkins:/var/jenkins_home"
environment:
- "TZ=Asia/Shanghai"
extra_hosts:
- "mirrors.jenkins-ci.org:172.17.0.1"
webapp:
#image: tomcat
build: ./tomcat
container_name: docker-webapp
volumes:
- "${BASE_DIR}/tomcat/logs:/usr/local/tomcat/logs"
- "${BASE_DIR}/tomcat/ROOT:/usr/local/tomcat/webapps/ROOT"
- "${BASE_DIR}/tomcat/conf:/usr/local/tomcat/conf"
expose:
- "8081"
environment:
- "TZ=Asia/Shanghai"

... 后面还有类似的