Docker Study

Centos下Docker学习

Centos 7安装和卸载Docker CE开源社区版

1
2
3
4
5
6
7
8
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 curl       #安装设置镜像仓库所需包
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #设置stable镜像仓库
sudo yum list docker-ce.x86_64 --showduplicates | sort -r #列出软件可用的版本,可根据版本安装
sudo yum -y install docker-ce #安装最新版
sudo docker --version #查看docker版本
sudo docker run hello-world #验证是否安装成功
sudo yum remove docker-ce #卸载docker-ce
sudo rm -rf /var/lib/docker #删除所有镜像、容器和存储卷

配置加速器

第一种:

1
2
3
4
5
6
7
8
9
10
11
sudo mkdir -p /etc/docker
sudo cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors" : [
"https://i3jtbyvy.mirror.aliyuncs.com" #加速器地址还可为:https://registry.docker-cn.com
],
"debug" : true,
"experimental" : true
}
EOF
sudo systemctl restart docker

第二种:

1
2
3
sudo systemctl enable docker            #启用docker服务
sudo vi /etc/systemd/system/multi-user.target.wants/docker.service #编辑,找到ExecStart=这一行,改为下一行所示的内容
ExecStart=/usr/bin/dockerd --registry-mirror=https://i3jtbyvy.mirror.aliyuncs.com

Docker安装websphere

1
2
3
4
5
6
7
8
9
10
11
12
sudo docker login                                 #登录Docker Cloud,需输入用户名和密码 
sudo docker search websphere #查看与websphere相关的镜像
sudo docker pull ibmcom/websphere-traditional #下载镜像到本地
sudo docker images #查看本地镜像,不同的仓库它的镜像ID可以相同
sudo docker run --name websphere \ #通过镜像来运行一个名为websphere的容器,可指定端口映射,容器名等
-h websphere \
-e UPDATE_HOSTNAME=true \
-p 9043:9043 \
-p 9443:9443 \
-d ibmcom/websphere-traditional
sudo docker exec websphere cat /tmp/PASSWORD #进入容器内部输出websphere的登录密码,用户名为wsadmin
sudo docker ps #查看容器有没有在运行,访问http://localhost:9043/ibm/cosole来登录控制台

Docker常用命令

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
sudo docker ps -a                             #查看所有容器
sudo docker ps #查看在运行的容器
sudo docker stop 容器名/容器ID #停止一个运行中的容器,发出一个停止信号,等待容器停止
sudo docker kill 容器名/容器ID #直接杀死容器
sudo docker start 容器名/容器ID #运行一个容器
sudo docker rm 容器名/容器ID #删除一个容器
sudo docker rmi 仓库名:标签/镜像ID #删除一个镜像,基于此镜像运行的容器必须删除,同名需指定版本,即镜像名:版本
sudo docker rmi $(docker images -q) #删除所有镜像
sudo docker tag hello-world subcan/get-started:test #发布过程为先标记一个镜像,标记的仓库为自己docker hub上想存放镜像的仓库
sudo docker push subcan/get-started:test #发布镜像到Docker Cloud仓库
sudo docker login #登录Docker Cloud仓库
sudo docker pull subcan/get-started:FirstBuildImages #登录Docker Cloud后,可pull一个自己镜像仓库的的镜像到本地
sudo docker logout #退出登录
sudo docker inspect 容器名/容器ID #对容器进行详细的检查,返回配置信息
sudo docker inspect 镜像ID/仓库ID:标签 #查看镜像的详细信息
sudo docker run learn/tutorial apt-get install -y ping #运行一个容器并在容器中安装ping
sudo docker commit 容器名/容器ID 镜像名 #把一个容器做成镜像
sudo docker log [-f][-t] 镜像 #查看容器的日志
sudo docker top 容器名/容器ID #查看容器的进程
sudo docker exec 容器名 命令 #对运行中的容器启动一个新的进程
sudo man docker-run #使用Docker帮助文件。其他命令也可查看
sudo docker port 容器名/容器ID #查看容器端口映射的情况
sudo docker info #查看docker信息
sudo docker version #查看docker版
sudo docker images --no-trunc #可查看镜像完整的ID
sudo docker images -a #查看所有的镜像,其中为<none>的镜像表示中间层镜像
sudo docker images -q #只查看镜像ID
sudo docker images 仓库名字 #查看指定的镜像

docker run命令

1
2
docker run [参数] 
参数:-d 以守护式进程的方式运行容器

守护式容器

例:

1
2
3
docker run -i -t --name test1 ubuntu /bin/bash                       #进入交互式容器环境
Ctrl+P Ctrl+Q #退出交互式环境,不影响容器运行,如果输入exit退出,则容器停止运行
docker attach 容器名/容器ID #进入运行的容器中

docker 概念 仓库,仓库:标签
Dockerfile构建镜像
进入Dockerfile文件目录,执行命令,执行成功,即构建了一个镜像
docker build -t=”仓库名” .
docker build -t=”仓库名” –no-cache. #不使用镜像缓存

docker c/s模式的连接方式
unix:///var/run/docker.sock #默认使用它,可以nc来连接,如:nc -u /var/run/docker.sock
tcp://host:port
fd://socketfd

docker 远程访问
不同的机器,修改docker守护进程启动项(labels标签),区别服务器,保证client api 与server api版本一致,-H选项配置启动选项,客户端可通过export Docker_HOST=”服务端访问方式”,来访问服务端docker info,为空表示访问本地的docker

可自定义修改linux虚拟网桥docker0的ip地址和掩码,docker运行的容器通过网桥docker0来通信,每运行一个容器,docker0会自动分配一个ip和mac地址给容器
ifconfig docker0 192.168.200.1 netmask 255.255.255.0

yum install bridge-utils -y
brctl show #查看网桥

brctl addbr br0 #添加一个虚拟网桥
ifconfig br0 192.168.100.1 netmask 255.255.255.0
守护进程启动配置中添加DOCKER_OPS值 -b=br0,则可以将自定义的虚拟网桥添加给docker使用

容器与外部网络连接
sysctl net.ipv4.conf.all.forwarding 查看net.ipv4.conf.all.forwarding,默认开启,值等于1

More info: Deployment

Docker-Quick-Start-Guide

注:本文为转载

原文出处: enter

Docker入门级简易手册

本篇仅作为新手入门使用,大神们可以指导小弟修正,不喜勿喷,谢谢

在线版:https://github.com/buxiaomo/MarkdownBooks

本篇主要讲解如下几个知识点:

  1. CentOS7与Ubuntu下安装Docker,配置加速器

  2. 常见Dockerfile命令讲解

  3. docker-compo安装与常见命令讲解

  4. 集群环境下如何使用compose编排

  5. 根据项目如何使用Docker部署应用

    1. Swarm集群下发布基于LNMP的WordPress应用发布
    2. NodeJS应用发布
    3. Flask应用发布
    4. 基于Tomcat定制封装Jenkins镜像
  6. 每次代码写好了都要自己构建觉得麻烦怎么办?

CentOS7与Ubuntu下安装Docker

CentOS7

1
2
3
yum install -y yum-utils device-mapper-persistent-data lvm2 curl
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce

Ubuntu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apt-get remove docker docker-engine docker.io -y

apt-get update

apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y

curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

apt-key fingerprint 0EBFCD88

add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

apt-get update

apt-get install docker-ce -y

配置加速器

​ 不想申请加速器的朋友可以使用我的,也可以自己去申请阿里云或者Daocloud的加速器。

1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir -p /etc/docker

cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors" : [
"https://i3jtbyvy.mirror.aliyuncs.com"
],
"debug" : true,
"experimental" : true
}
EOF

systemctl restart docker

常见Dockerfile命令讲解

​ Dockerfile简单一点就是描述你这个镜像安装了哪些软件包,有哪些操作,创建了什么东西。有些人喜欢用 docker commit 命令去打包镜像,这样是不好的,首先commit出来的镜像比你使用Dockerfile构建出来的体积大,而且commit出来的镜像属于黑盒镜像,除了制作者,谁都不知道你在里面干了什么,属于不安全的镜像,很少会有人使用,最后就是不便于你最终的管理和更新。所以推荐使用Dockerfile去管理你的镜像,下面将简单介绍Dockerfile常见的指令和注意事项:

FROM

​ FROM命令是指定你所使用的基础镜像,一般写在文件开头,对于官方没给出Dockerfile的软件想Docker化,那么引用的镜像一般是debian:jessiealpineubuntu,如果官方已经有了,比如nginx、php、mysql这写,那么基本直接引用即可。

指令语法:

1
2
3
4
5
6
7
8
9
10
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>

eg:
FROM debian:jessie
FROM alpine:3.6
FROM ubuntu:16.04
FROM mysql:5.7
FROM python:2.7

MAINTAINER

​ MAINTAINER命令一般是描述这个Dockerfile的作者信息,

指令语法:

1
2
3
4
MAINTAINER <name>

eg:
MAINTAINER "MoMo" <95112082@qq.com>

RUN

​ 运行指定的命令,此命令只有在执行docker build时才会执行,其他情况下不会执行。这时候有很多初学者会以为在写SHELL,那么在一个Dockerfile里面会出现很多不合理的RUN指令,了解过Docker的朋友应该都知道Docker的镜像是分层结构,说白了就是Dockerfile里面一个指令的操作就是一层。比如下面的操作,一条RUN命令包含了更新源缓存,安装openjdk,清理垃圾,这样的好处是最终这一层会很小,假设你分开写,四个命令四个RUN指令,但是只有第二条命令才是你想要的,那么第一条产生的缓存垃圾就不发删除掉。这也算是优化的一部分。

指令语法:

1
2
3
4
5
6
7
8
这里只写第一种格式,有兴趣的朋友可以去官网看看其他的方式
RUN <command>

eg:
RUN apt-get update \
&& apt-get install openjdk-8-jdk --no-install-recommends -y \
&& apt-get clean all \
&& rm -rf /var/lib/apt/lists/*

CMD

​ 设置容器启动时要运行的命令只有在你执行 docker run 或者 docker start 命令是才会运行,其他情况下不运行。如果一个Dockerfile里面有多条CMD指令,那么只有文件最后一行的 CMD 指令才会生效,其他的全部没用,还有一点,还有一点 CMD 指令是可以在你执行 docker run 的时候覆盖的。

指令语法:

1
2
3
4
CMD ["executable","param1","param2"]

eg:
CMD ["python","flask.py"]

EXPOSE

​ 设置暴露的容器端口,注意是容器端口。

指令语法:

1
2
3
4
5
EXPOSE port

eg:
EXPOSE 80
EXPOSE 80 443

ENV

​ 功能为设置环境变量,此环节变量可以是在构建镜像时使用,也可以在运行中的容器使用。

指令语法:

1
2
3
4
5
6
7
8
9
10
11
12
ENV <key> <value>

eg:
一种写法
ENV JAVA_HOME /usr/lib/jvm/java-7-openjdk-amd64
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin:$JRE_HOME/bin

另一种写法
ENV JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 \
CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar \
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin

ADD

​ 复制命令,把本机的文件复制到镜像中,如果dest是目录则会帮你创建出这个目录,如果src是压缩文件会帮你解压出来。当然ADD指令中的src也可以是URL链接,还有另外一个指令(COPY),请注意区别!!!

​ 另外,src部分是是你Dockerfile的相对路径,这个请注意!!!

指令语法:

1
2
3
4
5
ADD <src> <dest>

eg:
ADD nginx.conf /etc/nginx/nginx.conf
ADD app.tar.gz /app/app.tar.gz

COPY

​ 与ADD指令一样,但是COPY的src部分只能是本地文件,文件路径是Dockerfile的相对路径。如果dest是目录并且目录不存在,会帮你创建,如果是压缩文件不会帮你解压。

指令语法:

1
2
3
COPY <src> <dest>

COPY app.tar.gz /app/

ENTRYPOINT

​ 启动时的默认命令,此指令设置的命令不可修改。与CMD是有区别的。此命令在Dockerfile只能有一个,若有多个,则以文件最后一个出现的才生效。

指令语法:

1
2
3
4
5
ENTRYPOINT ["executable", "param1", "param2"]

eg:
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]

​ 如上,如果执行 docker run -d --name nginx -P nginx 则最终容器内执行的命令是nginx -g daemon off; ,如果你执行的命令是 docker run -d --name nginx -P nginx bash 则最终容器内执行的命令是nginx bash 注意区别,细心体会。

VOLUME

​ 设置你的卷,在启动容器的时候Docker会在/var/lib/docker的下一级目录下创建一个卷,以保存你在容器中产生的数据。若没有申明则不会创建。

指令语法:

1
2
3
4
5
VOLUME ["/path/to/directory"]

eg:
VOLUME ["/data"]
VOLUME ["/data","/app/etc"]

USER

​ 指定容器运行的用户是谁,前提条件,用户必须存在。此指令可以在构建镜像是使用或指定容器中进程的运行用户是谁。

指令语法:

1
2
3
4
USER daemo

eg:
USER nginx

WORKDIR

​ 指定容器中的工作目录,可以在构建时使用,也可以在启动容器时使用,构建使用就是通过 WORKDIR 将当前目录切换到指定的目录中,容器中使用的意思则是在你使用 docker run 命令启动容器时,默认进入的目录是 WORKDIR 指定的,下面的example中我使用环境变量。

指令语法:

1
2
3
4
WORKDIR /path/to/workdir

eg:
WORKDIR /usr/local/zookeeper-${ZOOKEEPER_VERSION}

以上为常用的Dockerfile指令,详细文档请参考官方文档:https://docs.docker.com/engine/reference/builder/

docker-compose安装与常见命令讲解

docker-compose安装

方法一

1
2
3
4
curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
#查看版本
docker-compose version

方法二

1
2
3
4
5
6
7
8
9
10
11
12
CentOS:
yum install epel-release -y
yum install python-pip -y

Ubuntu:
apt-get install python-pip -y

# 通用命令
pip --version
pip install --upgrade pip
pip install -U -i https://pypi.tuna.tsinghua.edu.cn/simple docker-compose
docker-compose version

常见命令讲解

单机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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 定义docker-compose版本,有些参数只有高版本才有,底版本没有
version: '3.4'
# 定义服务,可以是一个,也可以是多个
services:
# 具体的服务名,其他的服务可以用过这个名字访问
nginx:
# 定义这个服务所使用的镜像以及进项版本,若不指定版本默认是latest,生产环境不建议使用latest
image: nginx:1.13.6-alpine
# 定义容器启动后的主机名,其他的服务可以用过这个名字访问
hostname: nginx
# 定义暴露端口,若写成 '80:80/tcp' 的格式则表示指定宿主机的80转发到容器的80,若写成 '80/tcp' 则表示Docker将随机分配一个宿主机端口给容器内的80端口,tcp表示协议类型,也可以是udp
ports:
- 80:80/tcp
# 网络定义部分
networks:
# 定义这个容器运行在哪个虚拟网络里面
wordpress:
# 设置这个容器在网络中的别名,可以是一个,可以是多个,其他的服务可以用过这个名字访问
aliases:
- nginx
# 定义卷,可以是卷,也可以是目录,可以设置容器内的权限是什么
volumes:
# 将docker-compose的相对目录下的nginx配置文件挂载到容器内的/etc/nginx/nginx.conf地方去,权限是只读
# 大致格式:src:dest:mode
# src: 可以是卷名,宿主机目录等,可以是文件或者目录,若是文件则文件必须存在,否则会是目录的形式挂载
# dest: 容器内的路径,可以是文件可以是目录,若是文件则文件必须存在,否则会是目录的形式挂载
# mode: 权限,只读(ro),可读可写(rw)
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./www:/var/www/html:rw
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
# 日志定义
logging:
# 使用的驱动是什么,官方给出很多方式,具体可以查看官方文档,这里使用的json-file
driver: json-file
# 定义日志的参数
options:
# 设置最大文件数3个,每个文件大小为100MB
max-file: '3'
max-size: 100m

# 下面的部分我只会将上面没有出现的部分注释出来,有的部分不做说明
wordpress:
image: wordpress:4.9.1-php7.1-fpm-alpine
hostname: php
networks:
wordpress:
aliases:
- wordpress
# 环境变量设置,key=value
environment:
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=root
- WORDPRESS_DB_NAME=xbclub
- WORDPRESS_TABLE_PREFIX=wp_
volumes:
- ./www:/var/www/html:rw
- ./php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
logging:
driver: json-file
options:
max-file: '3'
max-size: 100m
mysql:
image: mysql:5.7.20
hostname: mysql
networks:
wordpress:
aliases:
- mysql
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- ./mysql:/var/lib/mysql
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
logging:
driver: json-file
options:
max-file: '3'
max-size: 100m
redis:
image: redis:4.0.6
hostname: redis
networks:
wordpress:
aliases:
- redis
volumes:
- ./redis:/data:rw
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
logging:
driver: json-file
options:
max-file: '3'
max-size: 100m
# 定义这个compose文件中使用的网络
networks:
# 网络名称,和上文中的wordpress一直,这里注意不是上文中出现的wordpress这个服务,而是是网络!!!
wordpress:
# 是否是外部网络,这里可以理解为如果是外部网络那么网络的名字就叫wordpress,这样方便其他的服务接入到这个网络,如果不是,在你使用docker-compose up -d 命令的时候他会以你当前的文件夹的名字加上这里定义的网络名作为你这个compose的网络。比如我的这个compose文件在test下面,如果external为true,那么你需要手动创建这个网络然后去指定命令启动这个compose;如果为flase则网络的名字将会以test_wordpress出现在你的docker network ls中。具体可以自己去试一下就知道大概是什么意思了。
external: true

集群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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
version: '3.4'
services:
nginx:
image: nginx:1.13.6-alpine
hostname: nginx
ports:
- 3000:80/tcp
networks:
xbclub:
aliases:
- nginx
volumes:
- /nfs/xbclub/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- /nfs/xbclub/www:/var/www/html:rw
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
# 定义你这个服务的运行方式
deploy:
# 模式定义,主要两种,全局模式和副本模式(自己翻译的),全局模式将会在所有的Swarm节点上运行一个实例,副本模式则指定运行你在replicas指定的个数。
mode: replicated
replicas: 3
# 服务的运行规则,下面这部分的意识是“这个Nginx服务将只会匹配集群中的工作节点,但是主机名不是‘Docker-Swarm-MySQL’,‘Docker-Swarm-Redis’,‘Docker-Swarm-NFS’的节点上运行这个Nginx服务”。下面的部分基本大同小异,这里就不啰嗦了。
placement:
constraints:
- node.role == worker
- node.hostname != Docker-Swarm-MySQL
- node.hostname != Docker-Swarm-Redis
- node.hostname != Docker-Swarm-NFS
wordpress:
image: wordpress:4.9.1-php7.1-fpm-alpine
hostname: php
networks:
xbclub:
aliases:
- wordpress
environment:
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=root
- WORDPRESS_DB_NAME=xbclub
- WORDPRESS_TABLE_PREFIX=wp_
volumes:
- /nfs/xbclub/www:/var/www/html:rw
- /nfs/xbclub/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 3
placement:
constraints:
- node.role == worker
- node.hostname != Docker-Swarm-MySQL
- node.hostname != Docker-Swarm-Redis
- node.hostname != Docker-Swarm-NFS
mysql:
image: mysql:5.7.20
hostname: mysql
networks:
xbclub:
aliases:
- mysql
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- /mysql/xbclub:/var/lib/mysql
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == Docker-Swarm-MySQL
logging:
driver: json-file
options:
max-file: '3'
max-size: 100m
redis:
image: redis:4.0.6
hostname: redis
networks:
xbclub:
aliases:
- redis
volumes:
- /redis/xbclub:/data:rw
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == Docker-Swarm-Redis
# 这里需要说明,集群环境下你需要执行“docker network create --driver overlay NetworkName”命令创建,网络的SCOPE部分显示的是Swarm才是对的。
networks:
xbclub:
external: true

这里我只是把我常用的贴出来加以说明,如果各位有想要补充的可以告诉我,我在加上去,详细介绍可以看官网

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

根据项目如何使用Docker部署应用

Swarm集群下发布基于LRNMP的WordPress应用发布

​ 本实例,默认你已经装好系统,装好Docker并创建好Swarm集群。

​ 集群约定,对于无状态应用如Nginx,WordPress我们使用NFS去实现Web站点的数据保存以及共享服务以保证所有容器(Nginx、WordPress)数据一致性问题,MySQL数据库我将指定单台主机去实现MySQL数据库功能,数据库目录将存放在所在宿主机上,那么存在一个问题,MySQL高可用如何去实现,这里可以基于MySQL的架构去实现数据库这块的高可用性本篇不讨论如何实现。

应用目录结构:

站点在NFS主目录位置:/nfs/lnmp

站点目录:/nfs/lnmp/www

Nginx配置文件目录:/nfs/lnmp/nginx

WordPress配合文件目录:/nfs/lnmp/php

Redis数据目录(Docker-Swarm-Redis主机下):/redis/lnmp

MySQL数据目录(Docker-Swarm-MySQL主机下):/mysql/lnmp

镜像相关文档:

Redi:https://hub.docker.com/_/redis/

Nginx:https://hub.docker.com/_/nginx/

WordPress:https://hub.docker.com/_/wordpress/

MySQL:https://hub.docker.com/_/mysql/

集群节点清单:

主机名 节点作用 运行的容器
Docker-Swarm-MySQL MySQL节点,只跑MySQL不跑其他的应用 MySQL
Docker-Swarm-Redis Redis节点,只跑Redis不跑其他的应用 Redis
Docker-Swarm-NFS NFS节点,只用于数据共享,不运行任何应用 N/A
Docker-Swarm-Master01 Swarm集群管理节点 N/A
Docker-Swarm-Node01 Swarm集群工作节点 Nginx、WordPress
Docker-Swarm-Node02 Swarm集群工作节点 Nginx、WordPress

准备编排文件,内容如下(docker-compose.yaml):

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
version: '3.4'
services:
nginx:
image: nginx:1.13.6-alpine
hostname: nginx
ports:
- 3000:80/tcp
networks:
xbclub:
aliases:
- nginx
volumes:
- /nfs/lnmp/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- /nfs/lnmp/www:/var/www/html:rw
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 3
placement:
constraints:
- node.role == worker
- node.hostname != Docker-Swarm-MySQL
- node.hostname != Docker-Swarm-Redis
- node.hostname != Docker-Swarm-NFS
wordpress:
image: wordpress:4.9.1-php7.1-fpm-alpine
hostname: php
networks:
xbclub:
aliases:
- wordpress
environment:
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=root
- WORDPRESS_DB_NAME=xbclub
- WORDPRESS_TABLE_PREFIX=wp_
volumes:
- /nfs/lnmp/www:/var/www/html:rw
- /nfs/lnmp/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 3
placement:
constraints:
- node.role == worker
- node.hostname != Docker-Swarm-MySQL
- node.hostname != Docker-Swarm-Redis
- node.hostname != Docker-Swarm-NFS
mysql:
image: mysql:5.7.20
hostname: mysql
networks:
xbclub:
aliases:
- mysql
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- /mysql/lnmp:/var/lib/mysql
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == Docker-Swarm-MySQL
logging:
driver: json-file
options:
max-file: '3'
max-size: 100m
redis:
image: redis:4.0.6
hostname: redis
networks:
xbclub:
aliases:
- redis
volumes:
- /redis/lnmp:/data:rw
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == Docker-Swarm-Redis
networks:
xbclub:
external: true

Nginx配置文件(nginx.conf):

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
user  nginx nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_rlimit_nofile 51200;

events {
use epoll;
worker_connections 51200;
multi_accept on;
}

http {
include mime.types;
default_type application/octet-stream;

log_format main '{"remote_addr":"$remote_addr",'
'"http_x_forwarded_for":"$http_x_forwarded_for",'
'"remote_user":"$remote_user",'
'"time_local":"$time_local",'
'"request":"$request",'
'"status":"$status",'
'"request_time":"$request_time",'
'"body_bytes_sent":"$body_bytes_sent",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent"}';

server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;

sendfile on;
tcp_nopush on;

keepalive_timeout 60;

tcp_nodelay on;

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";

server_tokens off;

server {
listen 80;
server_name _;
index index.html index.htm index.php;
location / {
deny all;
}
}

server{
listen 80;
server_name www.example.com ;
server_name _;
index index.html index.htm index.php default.html default.htm default.php;
root /var/www/html;

location / {
try_files $uri $uri/ /index.php?$args;
}

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

# Deny access to PHP files in specific directory
#location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

location ~ [^/]\.php(/|$) {
try_files $uri =404;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi.conf;
}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}

location ~ .*\.(js|css)?$ {
expires 12h;
}

location ~ /.well-known {
allow all;
}

location ~ /\. {
deny all;
}
}
}

WordPress配置文件(uploads.ini):

1
2
3
4
5
file_uploads = On
memory_limit = 64M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 600

本实例项目地址:https://github.com/buxiaomo/docker-compose/tree/master/wordpress

总结:

本实例我们直接使用的是官方的镜像,没有做定制操作,原因如下:

1、不要重复造轮子,官方有镜像尽量使用官方的镜像不要自己构建

2、官方镜像有人维护,不需要自己维护,较少成本

3、官方镜像基本可以满足大部分应用需求,所以基本不需要进行定制化,如果需要定制化可以直接使用FROM BASEIMAGE去做定制化,而不是从头再来。

NodeJS应用发布

​ 针对自己写Dockerfile构将APP镜像,首先需要有一点,你的APP必须可以前台运行!!!

​ 由于官方有镜像,我们就直接引用即可,不需要自己去构建NodeJS的镜像,这里我一一个NodeJS的WebUI去实现镜像封装以及运行。对于NodeJS应用,大概分为两部分,下载依赖包,运行分为,这里可以更具实际情况决定Dockerfile如何编写,理论上依赖包只需要下载一次就行了,不需要每次运行分为都去下载镜像包,那么针对这种情况可以在构建的时候把依赖包一起打包到镜像中,当然,将依赖包打包到镜像中构建出来的镜像会有点大,但是好处就是启动服务的时候不需要下载依赖包,启动时间会很快,适合离线环境;一种是在启动的时候去下载依赖包,这样的话镜像会小一点,但是启动时会去下载依赖包,启动时间会比较长,具体方式可以自己选。下面简要说一下步骤:

编写Dockerfile内容如下:

1
2
3
4
5
6
7
8
9
10
11
FROM node:9.3.0

ADD app /app/

WORKDIR /app

RUN npm i

EXPOST 7001

CMD ["npm","run","dev"]

进入Dockerfile所在目录执行docker build -t=nodejs .构建镜像

待补充

Flask应用发布

项目代码:https://github.com/buxiaomo/dockerfile/tree/master/ssserverweb

​ 应用简介:应用通过Docker Engine API对基于Docker Swarm提供的SS服务管理用户添加删除和添加节点的小demo项目,本应用通过Swarm实现。Docker化应用类似于NodeJS。通过阿里云的域名API配置主机IP与域名的关系,本篇只针对应用如何使用Docker部署,代码实现不在本篇讨论范围这里不详细说明。

申明:代码可能存在逻辑问题,不要纠结这个,本篇只讨论如何容器化应用。

可以直接看GitHub的代码查看详情。准备Dockerfile,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM python:2.7.14

ADD . /app

WORKDIR /app

RUN pip install -r requirements.txt

ENV ALIYUN_ID NULL
ENV ALIYUN_Secret NULL
ENV ALIYUN_RegionId cn-hangzhou

ENV Domain NULL
ENV ManagerIP NULL

EXPOSE 8000

CMD ["python","ssserver.py"]

进入Dockerfile所在目录执行docker build -t=ssserverweb .构建镜像

启动容器:

1
2
3
4
5
6
7
8
docker run -d --name ssserverweb 
-p 8080:8000 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e ALIYUN_ID=*** \
-e ManagerIP=*** \
-e ALIYUN_Secret=**** \
-e DomainName=www.example.com \
ssserverweb:latest

查看服务,访问链接:http://IP:8080 即可访问到访问页面

基于Tomcat封装Jenkins镜像

待补充

每次代码写好了都要自己构建觉得麻烦怎么办?

1、可以结合GitHub与Dockerhub做到持续构建。

2、使用GitHub代码托管与daocloud的公有云服务,构建速度不错,比Dockerhub快,不用等太久。

3、Jenkins + github/Gitlab(自己动手丰衣足食)

DB Related

DB2

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
db2 get snapshot for dynamic sql on 库 >>snap.log                                #动态语句监控 
grep -n "Deadlocks detected" snap.log | grep -v "= 0" | more #识别是否存在死锁
grep -n " Number of executions" snap.log | grep -v "= 0" | sort -k 5,5rn | more #搜索语句的执行次数
grep -n " Rows read" snap.log | grep -v "= 0" | sort -k 5,5rn #读取行数最多的语句
grep -n " Total execution time" snap.log | grep -v "= 0.0" |sort -k 5,5rn | more #获取语句执行时间
grep -n " Statement text" snap.log | more #相似语句排序
cd /opt/ibm/db2/V10.5
db2iset -d db2inst1 #如果无法删除实例,执行此命令删除实例
db2 activate db LYLDB #激活数据库
db2 deactivate db LYLDB #关闭激活数据库
db2cklog $归档日志的数字编号 #检查归档日志文件是否完整,返回值'0',则完整
db2diag -g level=Error,db=SI2DB #db2diag按日志输出等级,库名过滤db2diag.log文件
db2ckbkp -h $备份文件 #检测备份文件的完整性

表统计

1
2
3
4
db2 "select count(*) from iplat.TEWWF02"         #表行数统计
db2 "describe table iplat.TEWWF02" #表结构查看
db2 "select substr(indname,1,10),substr(tabname,1,20),substr(colnames,1,20) from syscat.indexes where tabname='iplat.TEWWF02'" #查看表有哪些索引
db2 "select firstkeycard, first2keycard from syscat.indexes where indname='I_T1'" #具体表索引查看

db2恢复

一丶在线备份恢复,需要在线备份包和归档日志
1丶目录一致使用这种方式
1
2
3
4
5
db2 restore db lyldb from /data/db2bak/ taken at 20180710233503 LOGTARGET '/data/db2bak/'                #数据库恢复并指定生成目录 
#上传所需的日志到/data/db2bak/NODE0000/LOGSTREAM0000/下面,可采用的前滚有两种:
(1)丶db2 "rollforward db lyldb to 2018-07-11-11.30.00 using local time overflow log path (/data/db2bak/)" #前滚到指定时间点
db2 "rollforward database lyldb stop overflow log path (/data/db2bak/)"
(2)丶db2 "rollforward db lyldb to end of logs and complete overflow log path (/data/db2bak/)" #前滚到活动日志的末尾
2丶重定向恢复(目录不一致使用这种方式)
1
2
3
db2 restore db lyldb from /data/db2bak taken at 20180710233503 redirect generate script /data/db2bak/restore.sql    #生成重定向脚本修改restore.sql中表空间的路径,确保与服务器目录一致
db2 -tvf restore.sql -l out.log
db2 "rollforward db lyldb to end of logs and complete overflow log path (/data/db2bak/)"
二丶离线备份恢复

db2执行计划

1
2
db2expln -d SI2DB -i -g -stmtfile t1.sql -terminator ';' -output t1.exp    #t1.sql为一条需要执行计划的sql语句,例如:
UPDATE IPLAT.TEDMDM1 SET SEQ_VALUE=SEQ_VALUE + 1,REC_REVISOR=?,REC_REVISE_TIME=? WHERE SEQ_NAME=?

Oracle

1
2
lsnrctl start #开启监听
sqlplus / as sysdba #以管理员模式登录

mysql

suse linux 11安装mysql

从MySQL官网上分别下载mysql社区版服务器端与客户端应用包:官网
例如:
MySQL-server-5.5.59-1.sles11.x86_64.rpm
MySQL-client-5.5.59-1.sles11.x86_64.rpm

检测系统是否已安装mysql

1
2
3
rpm -qa | grep mysql
#若已经安装,则执行以下命令来删除,例如
rpm --nodeps -e mysql-5.5.31-0.7.10 mysql-client-5.5.31-0.7.10

安装mysql:

1
2
3
4
5
6
rpm -ivh MySQL-server-5.5.59-1.sles11.x86_64.rpm MySQL-client-5.5.59-1.sles11.x86_64.rpm
mkdir /data
chmod 755 -R /data
mv /var/lib/mysql /data
vim /etc/init.d/mysql #将datadir的值,修改为/data/mysql
cp /usr/share/mysql/my-medium.cnf /etc/my.cnf

编辑 my.cnf,对应内容如下

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
[client]
password = 123456
port = 3306
socket = /data/mysql/mysql.sock
default-character-set=utf8
[mysqld]
port = 3306
socket = /data/mysql/mysql.sock
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 1M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
character_set_server=utf8
collation-server=utf8_general_ci
lower_case_table_names=1
character_set_client=utf8
max_connections=1000
[mysql]
default-character-set = utf8
no-auto-rehash

重启mysql服务

1
2
3
cd /usr/bin
mysql_install_db
service mysql restart

登录mysql

1
2
3
4
5
6
7
8
mysql -u root -p
Enterpassword: (直接回车,因为第一次为空密码)
mysql> show databases;
mysql> use mysql;
mysql> show tables;
mysql> update user set password=password('123456')where user='root'; #登录成功后,修改密码
/usr/bin/mysqld_safe --user=mysql &
service mysql restart #最后重启mysql,密码生效

设置远程访问

1
2
3
4
5
mysql -u root -p                     
mysql> use mysql;
mysql> grant all PRIVILEGES on *.* to root@192.168.229.70 identified by 'password';
mysql> select host,user from user;
mysql> FLUSH PRIVILEGES;

mysql忘记密码

1
2
3
4
5
6
7
#停止mysql服务
/usr/bin/mysqld_safe --user=mysql --skip-grant-tables &
#输入mysql进入数据库
use mysql;
update user set password=password("密码") where user='root';
flush privileges;
#重启mysql服务

数据库备份

1
2
3
mysqldump -u用户 -p 库名 >库名.sql              #备份一个库
mysqldump -u用户 -p 库名 表名 >表名.sql #备份表
mysqldump -u用户 -p --all-databases >all.sql #备份所有库

恢复库

1
2
3
create database 库名 charset=utf8;
mysql -u用户 -p 库名 <库名.sql #恢复一个库
source 库名.sql #导入

删除库

1
drop databases 库名  #删除库

客户端连接远程主机

1
mysql -uroot -pLyl@1992 -h 192.168.229.85 -P3306

windows安装mysql

1丶下载windows对应的32位或者64位版本,例如32位7.7.22社区版本
2丶解压到目录,例如G:\mysql-5.7.22-win32
3丶在解压目录bin下初始化mysql

1
2
mysqld --initialize-insecure                #初始化
mysql -uroot -p #进入数据库,默认密码为空

4丶添加环境变量,系统变量path添加:G:\mysql-5.7.22-win32\bin
5丶将MySQL服务制作成windows服务

1
2
3
4
"G:\mysql-5.7.22-win32\bin\mysqld" --install              #制作MySQL的Windows服务
"G:\mysql-5.7.22-win32\bin\mysqld" --remove #移除MySQL的Windows服务
net start mysql #启动MySQL服务
net stop mysql #关闭MySQL服务

6丶给root设置密码,例如密码为123456

1
mysqladmin -uroot -p password 123456

SQL

SUBSTR函数,取一个字段中的某几位
SUBSTR(S,m,n),S表示字段名,m表示开始截取的位置,n表示截取的长度