This commit is contained in:
colben 2021-11-14 14:32:08 +08:00
parent f75ad8bedd
commit b0f6120151
152 changed files with 22219 additions and 8 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
#=========================================
# Author : Colben
#=========================================
/public/
/resources/
/themes/

View File

@ -48,15 +48,11 @@
- 克隆本仓库的前端目录
```bash
docker exec -ti gitea /bin/bash # 进入 gitea 容器
mkdir /html/www.colben.cn
chown gitea.www-data /html/www.colben.cn
chown gitea.www-data /html
su - gitea
cd /html/www.colben.cn
git init
git remote add -f origin https://git.colben.cn/colben/www.colben.cn.git
#git config core.sparsecheckout true
#echo 'public' > .git/info/sparse-checkout
git pull origin master
cd /html
git clone https://git.colben.cn/colben/www.colben.cn.git
hugo
exit # 退出容器
```

9
archetypes/default.md Normal file
View File

@ -0,0 +1,9 @@
---
title: "{{ replace .TranslationBaseName "-" " " | title }}"
date: {{ .Date }}
lastmod: {{ .Date }}
draft: true
tags: []
categories: []
---

View File

@ -0,0 +1,43 @@
---
title: "{{ replace .TranslationBaseName "-" " " | title }}"
date: {{ .Date }}
lastmod: {{ .Date }}
draft: true
keywords: []
description: ""
tags: []
categories: []
author: ""
# You can also close(false) or open(true) something for this content.
# P.S. comment can only be closed
comment: false
toc: false
autoCollapseToc: false
postMetaInFooter: false
hiddenFromHomePage: false
# You can also define another contentCopyright. e.g. contentCopyright: "This is another copyright."
contentCopyright: false
reward: false
mathjax: false
mathjaxEnableSingleDollar: false
mathjaxEnableAutoNumber: false
# You unlisted posts you might want not want the header or footer to show
hideHeaderAndFooter: false
# You can enable or disable out-of-date content warning for individual post.
# Comment this out to use the global config.
#enableOutdatedInfoWarning: false
flowchartDiagrams:
enable: false
options: ""
sequenceDiagrams:
enable: false
options: ""
---
<!--more-->

224
config.toml Normal file
View File

@ -0,0 +1,224 @@
baseURL = "https://colben.cn/"
languageCode = "en"
defaultContentLanguage = "zh-cn" # en / zh-cn / ... (This field determines which i18n file to use)
title = "Colben Notes"
preserveTaxonomyNames = true
enableRobotsTXT = true
enableEmoji = true
theme = ["hugo-search-fuse-js", "even"]
enableGitInfo = false # use git commit log to generate lastmod record # 可根据 Git 中的提交生成最近更新记录。
# Syntax highlighting by Chroma. NOTE: Don't enable `highlightInClient` and `chroma` at the same time!
pygmentsOptions = "linenos=table"
pygmentsCodefences = true
pygmentsUseClasses = true
pygmentsCodefencesGuessSyntax = true
hasCJKLanguage = true # has chinese/japanese/korean ? # 自动检测是否包含 中文\日文\韩文
paginate = 10 # 首页每页显示的文章数
disqusShortname = "" # disqus_shortname
googleAnalytics = "" # UA-XXXXXXXX-X
copyright = "" # default: author.name ↓ # 默认为下面配置的author.name ↓
[markup]
defaultMarkdownHandler = "blackfriday"
[author] # essential # 必需
name = "Colben"
[sitemap] # essential # 必需
changefreq = "weekly"
priority = 0.5
filename = "sitemap.xml"
[[menu.main]] # config your menu # 配置目录
name = "主页"
weight = 10
identifier = "home"
url = "/"
[[menu.main]]
name = "归档"
weight = 20
identifier = "archives"
url = "/post/"
[[menu.main]]
name = "标签"
weight = 30
identifier = "tags"
url = "/tags/"
[[menu.main]]
name = "分类"
weight = 40
identifier = "categories"
url = "/categories/"
[params]
version = "4.x" # Used to give a friendly message when you have an incompatible update
debug = false # If true, load `eruda.min.js`. See https://github.com/liriliri/eruda
since = "2019" # Site creation time # 站点建立时间
# use public git repo url to link lastmod git commit, enableGitInfo should be true.
# 指定 git 仓库地址,可以生成指向最近更新的 git commit 的链接,需要将 enableGitInfo 设置成 true.
gitRepo = "https://git.colben.cn/colben/www.colben.cn.git"
# site info (optional) # 站点信息(可选,不需要的可以直接注释掉)
logoTitle = "" # default: the title value # 默认值: 上面设置的title值
keywords = ["colben","notes"]
description = "personal blogs"
# paginate of archives, tags and categories # 归档、标签、分类每页显示的文章数目,建议修改为一个较大的值
archivePaginate = 16
# show 'xx Posts In Total' in archive page ? # 是否在归档页显示文章的总数
showArchiveCount = true
# The date format to use; for a list of valid formats, see https://gohugo.io/functions/format/
dateFormatToUse = "2006-01-02"
# show word count and read time ? # 是否显示字数统计与阅读时间
moreMeta = false
# Syntax highlighting by highlight.js
highlightInClient = false
# 一些全局开关,你也可以在每一篇内容的 front matter 中针对单篇内容关闭或开启某些功能,在 archetypes/default.md 查看更多信息。
# Some global options, you can also close or open something in front matter for a single post, see more information from `archetypes/default.md`.
toc = true # 是否开启目录
autoCollapseToc = false # Auto expand and collapse toc # 目录自动展开/折叠
fancybox = true # see https://github.com/fancyapps/fancybox # 是否启用fancybox图片可点击
# mathjax
mathjax = false # see https://www.mathjax.org/ # 是否使用mathjax数学公式
mathjaxEnableSingleDollar = false # 是否使用 $...$ 即可進行inline latex渲染
mathjaxEnableAutoNumber = false # 是否使用公式自动编号
mathjaxUseLocalFiles = false # You should install mathjax in `your-site/static/lib/mathjax`
postMetaInFooter = true # contain author, lastMod, markdown link, license # 包含作者上次修改时间markdown链接许可信息
linkToMarkDown = false # Only effective when hugo will output .md files. # 链接到markdown原始文件仅当允许hugo生成markdown文件时有效
contentCopyright = '' # e.g. '<a rel="license noopener" href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank">CC BY-NC-ND 4.0</a>'
changyanAppid = "" # Changyan app id # 畅言
changyanAppkey = "" # Changyan app key
livereUID = "" # LiveRe UID # 来必力
baiduPush = false # baidu push # 百度
baiduAnalytics = "" # Baidu Analytics
baiduVerification = "" # Baidu Verification
googleVerification = "" # Google Verification # 谷歌
# Link custom CSS and JS assets
# (relative to /static/css and /static/js respectively)
customCSS = []
customJS = []
uglyURLs = false # please keep same with uglyurls setting
[params.publicCDN] # load these files from public cdn # 启用公共CDN需自行定义
enable = true
jquery = '<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>'
slideout = '<script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>'
fancyboxJS = '<script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>'
fancyboxCSS = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">'
timeagoJS = '<script src="https://cdn.jsdelivr.net/npm/timeago.js@3.0.2/dist/timeago.min.js" integrity="sha256-jwCP0NAdCBloaIWTWHmW4i3snUNMHUNO+jr9rYd2iOI=" crossorigin="anonymous"></script>'
timeagoLocalesJS = '<script src="https://cdn.jsdelivr.net/npm/timeago.js@3.0.2/dist/timeago.locales.min.js" integrity="sha256-ZwofwC1Lf/faQCzN7nZtfijVV6hSwxjQMwXL4gn9qU8=" crossorigin="anonymous"></script>'
flowchartDiagramsJS = '<script src="https://cdn.jsdelivr.net/npm/raphael@2.2.7/raphael.min.js" integrity="sha256-67By+NpOtm9ka1R6xpUefeGOY8kWWHHRAKlvaTJ7ONI=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/flowchart.js@1.8.0/release/flowchart.min.js" integrity="sha256-zNGWjubXoY6rb5MnmpBNefO0RgoVYfle9p0tvOQM+6k=" crossorigin="anonymous"></script>'
sequenceDiagramsCSS = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/bramp/js-sequence-diagrams@2.0.1/dist/sequence-diagram-min.css" integrity="sha384-6QbLKJMz5dS3adWSeINZe74uSydBGFbnzaAYmp+tKyq60S7H2p6V7g1TysM5lAaF" crossorigin="anonymous">'
sequenceDiagramsJS = '<script src="https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.js" integrity="sha256-4O4pS1SH31ZqrSO2A/2QJTVjTPqVe+jnYgOWUVr7EEc=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/snapsvg@0.5.1/dist/snap.svg-min.js" integrity="sha256-oI+elz+sIm+jpn8F/qEspKoKveTc5uKeFHNNVexe6d8=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.8.3/underscore-min.js" integrity="sha256-obZACiHd7gkOk9iIL/pimWMTJ4W/pBsKu+oZnSeBIek=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/gh/bramp/js-sequence-diagrams@2.0.1/dist/sequence-diagram-min.js" integrity="sha384-8748Vn52gHJYJI0XEuPB2QlPVNUkJlJn9tHqKec6J3q2r9l8fvRxrgn/E5ZHV0sP" crossorigin="anonymous"></script>'
# Display a message at the beginning of an article to warn the readers that it's content may be outdated.
# 在文章开头显示提示信息,提醒读者文章内容可能过时。
[params.outdatedInfoWarning]
enable = false
hint = 30 # Display hint if the last modified time is more than these days ago. # 如果文章最后更新于这天数之前,显示提醒
warn = 180 # Display warning if the last modified time is more than these days ago. # 如果文章最后更新于这天数之前,显示警告
#[params.gitment] # Gitment is a comment system based on GitHub issues. see https://github.com/imsun/gitment
# owner = "colben" # Your GitHub ID
# repo = "comments" # The repo to store comments
# clientId = "1480b0d51916c635576f" # Your client ID
# clientSecret = "86344d4eecfa8e1cc1ee1e099f8489f731b43c77" # Your client secret
[params.utterances] # https://utteranc.es/
owner = "" # Your GitHub ID
repo = "" # The repo to store comments
[params.gitalk] # Gitalk is a comment system based on GitHub issues. see https://github.com/gitalk/gitalk
owner = "" # Your GitHub ID
repo = "" # The repo to store comments
clientId = "" # Your client ID
clientSecret = "" # Your client secret
# Valine.
# You can get your appid and appkey from https://leancloud.cn
# more info please open https://valine.js.org
[params.valine]
enable = false
appId = '你的appId'
appKey = '你的appKey'
notify = false # mail notifier , https://github.com/xCss/Valine/wiki
verify = false # Verification code
avatar = 'mm'
placeholder = '说点什么吧...'
visitor = false
[params.flowchartDiagrams]# see https://blog.olowolo.com/example-site/post/js-flowchart-diagrams/
enable = false
options = ""
[params.sequenceDiagrams] # see https://blog.olowolo.com/example-site/post/js-sequence-diagrams/
enable = false
options = "" # default: "{theme: 'simple'}"
[params.busuanzi] # count web traffic by busuanzi # 是否使用不蒜子统计站点访问量
enable = false
siteUV = true
sitePV = true
pagePV = true
[params.reward] # 文章打赏
enable = false
wechat = "/path/to/your/wechat-qr-code.png" # 微信二维码
alipay = "/path/to/your/alipay-qr-code.png" # 支付宝二维码
#[params.social] # 社交链接
# a-email = "mailto:colbenlee@163.com"
# #b-stack-overflow = "http://localhost:1313"
# c-twitter = "https://twitter.com/ColbenLee"
# #d-facebook = "http://localhost:1313"
# #e-linkedin = "http://localhost:1313"
# #f-google = "http://localhost:1313"
# g-github = "https://github.com/colben"
# #h-weibo = "http://localhost:1313"
# #i-zhihu = "http://localhost:1313"
# #j-douban = "http://localhost:1313"
# #k-pocket = "http://localhost:1313"
# #l-tumblr = "http://localhost:1313"
# #m-instagram = "http://localhost:1313"
# n-gitlab = "https://git.colben.cn"
# #o-bilibili = "http://localhost:1313"
# See https://gohugo.io/about/hugo-and-gdpr/
[privacy]
[privacy.googleAnalytics]
anonymizeIP = true # 12.214.31.144 -> 12.214.31.0
[privacy.youtube]
privacyEnhanced = true
# 将下面这段配置取消注释可以使 hugo 生成 .md 文件
# Uncomment these options to make hugo output .md files.
#[mediaTypes]
# [mediaTypes."text/plain"]
# suffixes = ["md"]
#
#[outputFormats.MarkDown]
# mediaType = "text/plain"
# isPlainText = true
# isHTML = false
#
#[outputs]
# home = ["HTML", "RSS"]
# page = ["HTML", "MarkDown"]
# section = ["HTML", "RSS"]
# taxonomy = ["HTML", "RSS"]
# taxonomyTerm = ["HTML"]

27
content/about.md Normal file
View File

@ -0,0 +1,27 @@
---
title: "关于"
date: 2019-10-29T17:38:52+08:00
lastmod: 2019-10-29T17:44:00+08:00
menu: "main"
weight: 50
---
<center>![Richard Matthew Stallman](/img/richard-stallman.png)</center>
<center><h2>俊赛潘安,才比管乐</h2></center>
<HR>
### **IT 运维工作注意事项**
- 无论世界怎样变化,用户总会有问题
- 当你拿不准时,请重启机器。
- 迟早有一天会遇到一个忘了插电源的人说电脑启动不起来。
- 会逐渐害怕来电话,因为没有人会通过技术支持电话向我道早安.
- 在通话的一开始没有用户会告诉你所有的事情真相
- "我没有做任何事"和"突然间就变成这样了"是用户的咒语,作为一个技术支持人员,你要做的事是识破用户的谎言,解决问题不过是一件附带的事
- 有些用户永远都不会去学习,这意味着运维永远都不会失业
- 要一直保持平静的语气。
- 无论你在做什么,都不要恐慌。
- 永远都应该像这样回答用户的问题: "相信我,我知道我在做什么"
- 修理一台电脑要比指出损坏原因要简单的多
- 用户总想知道问题被解决的原因,如果你并不太清楚请尽管撒谎,他们永远都不会知道的。例如说: "一个偏离的电子进入了处理器然后问题就产生了......"
- 同行之间探讨问题,如有可能尽量向年龄最小的人询问,因为只有他们会说实话。

44
content/others.md Normal file
View File

@ -0,0 +1,44 @@
---
title: "其他"
date: 2019-10-30T13:43:55+08:00
lastmod: 2019-10-30T13:43:55+08:00
menu: "main"
weight: 60
---
# Linux
- [**Linux监控命令图文详述**](http://www.linuxidc.com/Linux/2015-01/111577.htm)
- [**Linux crontab 命令详细用法及示例**](http://www.linuxidc.com/Linux/2015-03/114339.htm)
- [**Linux下top命令详解**](http://www.linuxidc.com/Linux/2015-04/116101.htm)
- [**Ubuntu 通过 Live CD 更新Grub恢复引导Boot Menu**](http://www.linuxidc.com/Linux/2015-04/116451.htm)
- [**Kickstart配置文件超详细解析**](http://www.linuxidc.com/Linux/2017-08/146168.htm)
- [**PXE+Kickstart无人值守安装CentOS 7**](http://www.linuxidc.com/Linux/2017-08/146169.htm)
- [**PXE+Kickstart无人值守安装CentOS 6**](http://www.linuxidc.com/Linux/2017-08/146170.htm)
- [**Cobbler无人值守批量安装Linux系统**](http://www.linuxidc.com/Linux/2017-08/146171.htm)
- [**PXE+DHCP+TFTP+Cobbler 无人值守安装CentOS 7**](http://www.linuxidc.com/Linux/2017-09/146705.htm)
- [**Linux下搭建无人执守安装服务器**](http://www.linuxidc.com/Linux/2017-04/143182.htm)
# Network
- [**关于TCP连接建立与终止那点事**](http://www.linuxidc.com/Linux/2015-09/122777.htm)
# Database
- [**Oracle Linux 5.8安装Oracle 11g RAC**](http://www.linuxidc.com/Linux/2013-05/84251.htm)
- [**RAC环境数据库重启实例**](http://www.linuxidc.com/Linux/2013-08/88855.htm)
- [**使用Oracle 的 imp ,exp 命令实现数据的导入导出**](http://blog.csdn.net/studyvcmfc/article/details/5674290)
- [**ORACLE EXPDP命令使用详细**](http://blog.csdn.net/zftang/article/details/6387325)
- [**控制文件和控制文件的备份**](http://blog.csdn.net/seertan/article/details/8449050)
- [**MySQL如何通过EXPLAIN分析SQL的执行计划**](https://www.linuxidc.com/Linux/2018-08/153354.htm)
# Container
- [**Docker 终极指南**](http://www.linuxidc.com/Linux/2015-01/111631.htm)
# Python
- [**Python 的 OptionParser 模块**](http://www.it165.net/pro/html/201211/4140.html)
# Firewalld
- [**Iptables防火墙规则使用详解**](https://www.linuxidc.com/Linux/2018-08/153378.htm)
# Dev
- [**Make 命令教程详解**](http://www.linuxidc.com/Linux/2015-06/118278.htm)
- [**深入理解Java内存与垃圾回收调优**](https://www.linuxidc.com/Linux/2018-08/153457.htm)

56
content/post/ansible.md Normal file
View File

@ -0,0 +1,56 @@
---
title: "Ansible"
date: 2019-10-30T11:38:39+08:00
lastmod: 2019-10-30T11:38:39+08:00
tags: ["ansible"]
categories: ["dev/ops"]
---
# CentOS7 安装 ansible
```bash
yum install ansible
```
# 修改配置文件 /etc/ansible/ansible.conf
```
# 取消 ssh key 验证
host_key_checking = False
# 改用 debug 输出模式
stdout_callback = debug
```
# 修改配置文件 hosts
```
# 增加 tomcat 服务器组
[tomcat]
tomcat101 ansible_ssh_host=192.168.1.101
tomcat102 ansible_ssh_host=192.168.1.102
tomcat103 ansible_ssh_host=192.168.1.103
# 增加 mysql 服务器组
[mysql]
mysql201 ansible_ssh_host=192.168.1.201 ansible_ssh_pass=111111
mysql202 ansible_ssh_host=192.168.1.202
mysql203 ansible_ssh_host=192.168.1.203
# 全局设置全部服务器的默认设置
[all:vars]
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=123456
```
# authorized_key 模块
```bash
# 分发密钥
ansible all -m authorized_key -a "user=root key='{{ lookup('file', '/root/.ssh/id_rsa.pub') }}'"
```
# 简单使用
- 批量设置主机名为资产名
```bash
ansible all -m shell -a 'hostnamectl set-hostname {{inventory_hostname}}'
ansible all -m shell -a 'echo "{{ansible_ssh_host}} {{inventory_hostname}}" >> /etc/hosts'
```
# ansible 常用 roles
- [https://gitee.com/colben/ansible](https://gitee.com/colben/ansible)

View File

@ -0,0 +1,211 @@
---
title: "安装 Archlinux"
date: 2021-07-04T11:23:00+08:00
lastmod: 2021-07-04T11:23:00+08:00
keywords: []
tags: ["archlinux"]
categories: ["os"]
---
# U 盘启动,进入 archlinux live
- 下载 archlinux 镜像
```bash
curl -LO https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/2021.07.01/archlinux-2021.07.01-x86_64.iso
```
- 把镜像写进一个无用的 U 盘(/dev/sdX)
```bash
dd if=archlinux-2021.07.01-x86_64.iso bs=1M of=/dev/sdX
```
- 使用该 U 盘启动自己的 PC进入 archlinux live
# 联网,硬盘分区,安装系统
- 插上网线,自动分配地址,验证是否可以连接外网
```bash
curl -I https://www.baidu.com
# 返回 200
```
- 规划硬盘,选择一个无用硬盘(/dev/sdX),规划 efi 分区和根分区
```bash
# fdisk 规划分区
fdisk /dev/sdX
g # 创建新的 gpt 分区表
n # 创建一个新分区
# 直接回车
# 直接回车
+256M # 指定大小
t # 更改分区类型
# 直接回车
1 # 选择 EFI System
n # 创建一个新分区
# 直接回车
# 直接回车
+XXXG # 指定根分区大小
w # 保存并退出 fdisk
官网还有 swap 分区,现在内存都比较大,不需要 swap 了
```
- 格式化分区
```bash
mkfs.fat -F32 /dev/sdX1
mkfs.ext4 /dev/sdX2
```
- 挂载分区
```bash
mount /dev/sdX2 /mnt
mkdir /mnt/EFI
mount /dev/sdX1 /mnt/EFI
```
- 修改软件源(vim /etc/pacman.d/mirrorlist),只保留中国源
```
## China
Server = http://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirrors.bit.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirrors.aliyun.com/archlinux/$repo/os/$arch
## China
Server = https://mirrors.cloud.tencent.com/archlinux/$repo/os/$arch
## China
Server = http://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirrors.zju.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirrors.xjtu.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirrors.163.com/archlinux/$repo/os/$arch
## China
Server = http://mirrors.sohu.com/archlinux/$repo/os/$arch
## China
Server = http://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirrors.shu.edu.cn/archlinux/$repo/os/$arch
## China
Server = http://mirror.lzu.edu.cn/archlinux/$repo/os/$arch
```
- 安装系统包
```bash
pacstrap /mnt base linux linux-firmware
# 这里会从中国源里下载安装包并安装,具体时间就看网速了
```
- 生成 fstab
```bash
genfstab -U /mnt >> /mnt/etc/fstab
```
- chroot 进入新系统
```bash
arch-chroot /mnt /bin/bash
```
# 配置新安装的系统
- 设置时区
```bash
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
```
- 编辑 /etc/locale.gen选择 en_US 和 zh_CN
```bash
sed -i \
-e '/^#en_US.UTF-8/s/^#//' \
-e '/^#zh_CN/s/^#//' \
/etc/locale.gen
locale-gen
# 生成 /etc/locale.conf
echo 'LANG=zh_CN.UTF-8' > /etc/locale.conf
```
- 设置主机名(xxxx)
```bash
echo xxxx > /etc/hostname
```
- 安装内核
```bash
mkinitcpio -P
```
- 设置 root 密码
```bash
passwd
```
- 创建一个普通用户(xxxx),用于自己日常使用
```bash
useradd -m xxxx
passwd xxxx
echo "xxxx ALL=(ALL) ALL" > /etc/sudoers.d/xxxx
```
- 安装其他必须包
```bash
pacman -S grub networkmanager
pacman -S intel-ucode # intel 处理器
pacman -S amd-code # amd 处理器
```
- 创建 efi 启动项(xxxx)
```bash
grub-install --target=x86_64-efi --efi-directory=/EFI --bootloader-id=xxxx
```
- 生成 grub.cfg
```bash
grub-mkconfig -o /boot/grub/grub.cfg
```
- 退出新系统,返回 archlinux live
```bash
exit
```
# 卸载硬盘,重启
- 卸载硬盘
```bash
umount -R /mnt
```
- 重启
```bash
reboot
```
# 日常使用
- 登陆普通用户
- 启动 NetworkManager并设置开机自动启动
```bash
sudo systemctl start NetworkManager
sudo systemctl enable NetworkManager
```
- 连接网络
```bash
nmtui
```
- 安装常用命令行软件
```bash
sudo pacman -S ctags cscope tmux expect git p7zip unrar zip unzip \
ntfs-3g espeak hostapd dnsmasq openssh tcpdump vim cdrtools \
tree ethtool openbsd-netcat arch-install-scripts
```
- 安装 gnome 桌面
```bash
sudo pacman -S wqy-zenhei ttf-liberation
sudo pacman -S gnome
sudo systemctl enable gdm.service
sudo pacman -S gvim file-roller freerdp mpv ibus-sunpinyin
```
- [Gnome 主题网站](https://gnome-look.org)

141
content/post/awk.md Normal file
View File

@ -0,0 +1,141 @@
---
title: "awk 命令"
date: 2019-10-30T00:47:01+08:00
lastmod: 2019-10-30T00:47:01+08:00
keywords: []
tags: ["awk"]
categories: ["shell"]
---
# 格式
- awk -F '分隔符正则' -v 变量名=值 'BEGIN{动作} 条件{动作} END{动作}' 文件1 文件2 ...
- awk -F '分隔符正则' -f awk脚本文件名 文件1 文件2 ...
# 常用内置变量
变量 | 说明
---- | ----
$0 | 当前记录
$1~$n | 当前记录的第n个字段字段间由FS分隔
FS | 输入字段分隔符 默认是空格
NF | 当前记录中的字段个数,就是有多少列
NR | awk 开始执行程序后所读取的数据行数就是行号从1开始
RS | 输入的记录他隔符默 认为换行符
OFS | 输出字段分隔符 默认也是空格
ORS | 输出的记录分隔符,默认为换行符
FNR | 当前记录数awk每打开一个新文件,FNR便从0重新累计
ARGC | 命令行参数个数
ARGV | 命令行参数字典ARGV[0] 是 'awk'ARGV[1] 是 FILENAME
FILENAME | 当前输入文件的名字
IGNORECASE | 如果为真,则进行忽略大小写的匹配
ENVIRON | UNIX环境变量如 ENVIRON["PATH"]
FIELDWIDTHS | 输入字段宽度的空白分隔字符串
OFMT | 数字的输出格式(默认值是%.6g)
RSTART | 被 match 匹配函数匹配的字符串位置
RLENGTH | 被 match 匹配函数匹配的字符串长度
# 函数
### 常用内置函数
函数 | 说明
---- | ----
int(x) | 返回 x 的整数部分
rand() | 返回 0 到 1 之间的浮点数
gsub(Ere, "dest", str) | 把 str 中匹配扩展正则 Ere 的全部子串换成字符串 "dest"
sub(Ere, "dest", str) | 把 str 中匹配扩展正则 Ere 的第一个子串换成字符串 "dest"
substr(str, start, len) | 返回 str 中从 start 开始(长度为 len )的子串
index(str1, str2) | 返回 str1 中出现 str2 的位置,如果未找到,返回 0
length(str) | 返回 str 的字符个数,如果未指定 str返回 $0 包含字符个数
blength(str) | 返回 str 的字节个数,如果未指定 str返回 $0 包含字节个数
match(str, Ere) | 返回 str 中匹配扩展正则 Ere 的位置,如果未找到,返回 0
split(str, arr, Ere) | 把 str 按照扩展正则 Ere 切分成字典,存储到 arr 中,返回字典长度
tolower(str) | 把 str 换成小写
toupper(str) | 把 str 换成大写
sprintf("%s-%d", "abcd", 1234) | 返回 abcd-1234
strtonum(str) | 返回十进制数字
delete arr[n] | 删除字典/字典的对应元素
getline | 读入当前行的下一行,重写变量 0
next | 停止处理当前记录,开始处理下一行
nextfile | 停止处理当前文件,开始处理下一个文件
system(shell-command) | 返回命令退出状态
exit n | 终止 awk返回 n
### 自定义函数
- 格式
```awk
function fun_name(arg1, arg2, ...){
#函数体
return
}
```
# 判断语句
```awk
if(条件){
# 语句
}else if(条件){
# 语句
}else{
# 语句
}
```
# 循环语句
- for
```awk
for(初始化;条件;变化){
# 语句
}
for(变量 in 字典){
# 语句
}
```
- while
```awk
while(条件){
# 语句
}
```
- do while
```awk
do{
# 语句
}while(条件)
```
- break 退出当前循环体
- continue 退出本次循环,继续下一次循环
# 脚本
```awk
#!/usr/bin/awk -f
# 自定义的变量和函数
# ...
# 从这里开始执行
BEGIN{
# 语句
}
条件{
# 语句
}
END{
# 语句
}
```
# 其他说明
- 变量在使用时直接赋值即可,无需提前声明或定义
- 个人认为awk 没有数组只有字典,数组是键为整数的字典
- 运算符(+, -, \*, /, ++, -- 等)和关系符操作(>, >=, <, <=, ~, !~ 等)与 C 基本一致,也支持三目运算符(条件?值1:值2)
- shell 中 awk 执行显式命令时,加载 shell 中的变量
```bash
#!/bin/bash
shell_value='abcd'
echo | awk '{print "'$shell_value'"}'
# 输出 abcd
```
# 参考
- man awk
- [其他内置函数](https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din)
- [gnu awk 手册](https://www.gnu.org/software/gawk/manual/gawk.html)

140
content/post/bond.md Normal file
View File

@ -0,0 +1,140 @@
---
title: "CentOS7 双网卡绑定"
date: 2019-10-30T11:07:30+08:00
lastmod: 2019-10-30T11:07:30+08:00
keywords: []
tags: ["centos", "bond"]
categories: ["network"]
---
# bond 概要
### 什么是 bond
- 网卡bond是通过把多张网卡绑定为一个逻辑网卡实现本地网卡的冗余带宽扩容和负载均衡。在应用部署中是一种常用的技术。
### bond的模式种类
- Mode=0(balance-rr) 表示负载分担round-robin和交换机的聚合强制不协商的方式配合
- Mode=1(active-backup) 表示主备模式只有一块网卡是active,另外一块是备的standby
- **如果交换机配的是捆绑,将不能正常工作,因为交换机往两块网卡发包,有一半包是丢弃的**
- Mode=2(balance-xor) 表示XOR Hash负载分担和交换机的聚合强制不协商方式配合需要xmit_hash_policy
- Mode=3(broadcast) 表示所有包从所有interface发出这个不均衡只有冗余机制...和交换机的聚合强制不协商方式配合
- Mode=4(802.3ad) 表示支持802.3ad协议和交换机的聚合LACP方式配合需要xmit_hash_policy
- Mode=5(balance-tlb) 是根据每个slave的负载情况选择slave进行发送接收时使用当前轮到的slave
- Mode=6(balance-alb) 在5的tlb基础上增加了rlb
# CentOS7 配置 bond
### 环境
- 操作系统 CentOS7.6,禁用 NetworkManager 服务
- 物理网卡 eth0, eth1 绑定到 bond0
- 物理网卡 eth2, eth3 绑定到 bond1
### 网卡 eth0 配置
- 修改 /etc/sysconfig/network-scripts/ifcfg-eth0
```
TYPE=Ethernet
BOOTPROTO=none
DEVICE=eth0
ONBOOT=yes
USERCTL=no
SLAVE=yes
MASTER=bond0
```
### 网卡 eth1 配置
- 修改 /etc/sysconfig/network-scripts/ifcfg-eth1
```
TYPE=Ethernet
BOOTPROTO=none
DEVICE=eth1
ONBOOT=yes
USERCTL=no
SLAVE=yes
MASTER=bond0
```
### 网卡 eth2 配置
- 修改 /etc/sysconfig/network-scripts/ifcfg-eth2
```
TYPE=Ethernet
BOOTPROTO=none
DEVICE=eth2
ONBOOT=yes
USERCTL=no
SLAVE=yes
MASTER=bond1
```
### 网卡 eth3 配置
- 修改 /etc/sysconfig/network-scripts/ifcfg-eth3
```
TYPE=Ethernet
BOOTPROTO=none
DEVICE=eth3
ONBOOT=yes
USERCTL=no
SLAVE=yes
MASTER=bond1
```
### 增加网卡 bond0 配置
- 创建 /etc/sysconfig/network-scripts/ifcfg-bond0
```
TYPE=Ethernet
BOOTPROTO=static
NAME=bond0
DEVICE=bond0
ONBOOT=yes
IPADDR=192.168.1.101
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=114.114.114.114
```
### 增加网卡 bond1 配置
- 创建 /etc/sysconfig/network-scripts/ifcfg-bond1
```
TYPE=Ethernet
BOOTPROTO=static
NAME=bond0
DEVICE=bond0
ONBOOT=yes
IPADDR=192.168.1.102
NETMASK=255.255.255.0
#GATEWAY=192.168.1.1
#DNS1=114.114.114.114
```
### 配置绑定模式
- 创建 /etc/modprobe.d/bonding.conf加入以下内容
```
alias bond0 bonding
alias bond1 bonding
options bonding miimon=100 mode=1
```
### 载入 bonding 模块,重启 network 服务
```bash
modprob bonding
systemctl restart network
```
### 查看网卡绑定状态
```bash
cat /proc/net/bonding/bond0
cat /proc/net/bonding/bond1
```
# CentOS8 配置 bond
- 建立 bond 连接配置文件
```bash
nmcli c add con-name bond0 type bond ifname bond0 mode active-backup
```
- 增加两个网卡都 bond0
```bash
nmcli c add type bond-slave ifname eth1 master bond0
nmcli c add type bond-slave ifname eth2 master bond0
```
- 启动这两个 slave 连接
```bash
nmcli c up bond-slave-eth1
nmcli c up bond-slave-eth2
```

View File

@ -0,0 +1,154 @@
---
title: "CentOS7 安装 Cassandra 集群"
date: 2019-10-30T00:59:02+08:00
lastmod: 2019-10-30T00:59:02+08:00
keywords: []
tags: ["cassandra"]
categories: ["database"]
---
# 环境
主机名 | Public IP | Cluster IP| 操作系统 | Cassandra 版本
---- | ---- | ---- | ---- | ----
cassandra101 | 10.0.4.101 | 10.10.10.101 | CentOS7.6 | 3.0.18
cassandra102 | 10.0.4.102 | 10.10.10.102 | CentOS7.6 | 3.0.18
cassandra103 | 10.0.4.103 | 10.10.10.103 | CentOS7.6 | 3.0.18
- 下载 [apache-cassandra-3.0.18-bin.tar.gz](https://mirrors.tuna.tsinghua.edu.cn/apache/cassandra/3.0.18/apache-cassandra-3.0.18-bin.tar.gz)
# 各节点初始配置
- 关闭 selinux、防火墙
- 部署 java 运行环境
- 创建 cassandra 用户
```bash
useradd -m cassandra
```
- 创建数据目录
```bash
cd /var/lib
mkdir -p cassandra/data1 #多个存储磁盘可以创建多个数据存储目录
mkdir -p cassandra/hints #建议与数据磁盘分开
mkdir -p cassandra/commitlog #建议与数据磁盘分开
mkdir -p cassandra/saved_caches #建议与数据磁盘分开
chown -R cassandra.cassandra cassandra/
```
- 创建日志目录
```bash
cd /var/log
mkdir -p cassandra
chown -R cassandra.cassandra cassandra/
```
- 创建 pid 目录
```bash
cd /run
mkdir -p cassandra
chown -R cassandra.cassandra cassandra/
```
- 增加 sysctl.conf 配置,执行 sysctl -p 生效
```
vm.max_map_count=1048576
```
- 安装 jemalloc (推荐)
```bash
yum install jemalloc
```
- 创建文件 /usr/lib/systemd/system/cassandra.service内容如下
```
[Unit]
Description=Cassandra
Requires=network.service
After=network.service
[Service]
Type=forking
WorkingDirectory=/opt/cassandra
Environment=JAVA_HOME=/opt/jre
Environment=LOCAL_JMX=no
PIDFile=/run/cassandra/cassandra.pid
ExecStart=/opt/cassandra/bin/cassandra -p /run/cassandra/cassandra.pid
User=cassandra
Group=cassandra
LimitNOFILE=65536
LimitNPROC=65536
LimitMEMLOCK=infinity
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
```
# 部署 Cassandra
- 登陆 cassandra101下载 cassandra解压至 /opt/ 下
- 修改 /opt/cassandra/conf/cassandra.yaml
```yaml
cluster_name: CassandraCluster
hists_directory: /var/lib/cassandra/hints
data_file_directories:
- /var/lib/cassandra/data1
commitlog_directory: /var/lib/cassandra/commitlog
saved_caches_directory: /var/lib/cassandra/saved_caches
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "10.10.10.101,10.10.10.102,10.10.10.103"
listen_address: 10.10.10.101
rpc_address: 10.0.4.101
```
- 修改 /opt/cassandra/conf/logback.xml
```bash
sed -i 's,\${cassandra.logdir},/var/log,' /opt/cassandra/conf/logback.xml
```
- 修改 /opt/cassandra/conf/cassandra-env.sh
```bash
# 这里我暂时关闭了 jmx 远程验证,否则需要手动创建 jmxremote.password 文件
sed -i 's/jmxremote.authenticate=true/jmxremote.authenticate=false/' /opt/cassandra/conf/cassandra-env.sh
```
- 修改 cassandra 目录的权限
```bash
chown -R cassandra.cassandra cassandra/
```
- 打包 cassandra 目录,部署到 cassandra102 和 cassandra103 的 /opt 下,并修改 cassandra.yaml
```
# cassandra102
listen_address: 10.10.10.102
rpc_address: 10.0.4.102
# cassandra103
listen_address: 10.10.10.103
rpc_address: 10.0.4.103
```
# 启动集群
- 启动 cassandra 服务
```bash
systemctl daemon-reload
systemctl start cassandra
```
# 简单使用
- cqlsh 连接数据库
```bash
/opt/cassandra/bin/cqlsh 10.0.4.101 9042
cqlsh> desc keyspaces;
```
# 注意事项
- 创建包含复合主键的表
```cql
create table t1 (
c1 text,
c2 text,
c3 text,
c4 text,
c5 text,
primary key((c1,c2),c3,c4)
);
- 复合主键的第一列 "(c1,c2)" 构成 PartitionKey其余列 c3,c4 都是 ClusteringKey
- Cassandra 对 PartitionKey 计算 Hash 值,决定该记录的存放 nodeClusteringKey 在 Partition 内部排序
- 默认只支持**主键列**和**索引列**查询,否则需要手动指定 **allow filtering**
- 根据多个 ClustringKey 查询时,需指定全部的 PartitionKeyClusteringKey 不能跳过
- 主键列不可修改

View File

@ -0,0 +1,63 @@
---
title: "Centos6 系统盘迁移"
date: 2019-10-30T13:34:47+08:00
lastmod: 2019-10-30T13:34:47+08:00
tags: ["centos", "系统盘迁移"]
categories: ["os"]
---
# 环境
- Linux 物理机,已安装 VirtualBox 虚拟机软件
- CentOS6.9 live 启动 U 盘
- CentOS6.9 iso 镜像文件
- 待安装笔记本 IBM x32
# VirtualBox 创建 Redhat6 虚拟机
- VMware 没用过,建议硬件配置尽量和目标设备一致
- Thinkpad X32 的处理器只有一核,无 PAE内存 1024MB
- 虚拟硬盘 8G 就够了,使用 CentOS6.9 iso 装好虚拟机后,禁用 selinux可能需要重启生效。
# 打包操作系统根目录
```
cd /
tar cvpzf backup.tgz --exclude=/backup.tgz --one-file-system /
```
# 导出 /backup.tgz 文件
- 返回物理机操作系统,通过 ssh、http 或其他方式把虚拟机的 /backup.tgz 拷贝至物理机中 /root 下
# 格式化磁盘
- 取出待安装笔记本的硬盘,通过 USB 或其他方式挂载到该物理机上fdisk 分区,格式化
```
#fdisk 分成俩个分区前面一个大的根分区后面一个2G的 swap 分区,其他情况自己决定
#假设刚挂载的这个目标磁盘设备是 sdg
mkfs.ext3 /dev/sdg1
mkswap /dev/sdg2
```
# 部署操作系统
- 挂载待部署磁盘的根分区,解压操作系统文件,修改启动相关参数
```
mount /dev/sdg1 /mnt
tar xvpzf /root/backup.tgz -C /mnt/
#查看目标磁盘根分区的 uuid替换 /mnt/boot/grub/grub.conf 和 /mnt/etc/fstab 中对应项
ls -lh /dev/disk/by-uuid/|grep sdg1
#查看目标磁盘 swap 分区的uuid替换 /mnt/etc/fstab 中对应项
ls -lh /dev/disk/by-uuid/|grep sdg2
#检查 /mnt/etc/mtab 中列出的信息是否正确
```
# 安装 grub2
- 取消挂载,把部署好的磁盘安装回待安装笔记本中,插上 CentOS6.9 的启动 U 盘,从 U 盘启动待安装笔记本,进入 live 模式(安装盘可以在安装界面开始时按下 Alt + F1 切换到 live 模式下),安装 grub2
```
#在 live 模式下切换到 root
sudo -i
#挂载(假设 live 识别到的硬盘根分区是 /dev/sda1)
mount /dev/sda1 /mnt
#安装 grub2
grub-install --root-directory=/mnt/ /dev/sda
#如果显示 “no error”即可退出取消挂载
exit
umount -f /mnt
```
- 此时重启就可以正常进入系统了

View File

@ -0,0 +1,88 @@
---
title: "Centos6 安装 nopae 内核"
date: 2019-10-30T13:06:52+08:00
lastmod: 2019-10-30T13:06:52+08:00
tags: ["centos", "nopae"]
categories: ["os"]
---
# 环境
- IBM Thinkpad X31
- VirtualBox
- [CentOS-6.9-i386-minimal.iso](http://mirrors.ustc.edu.cn/centos/6.9/isos/i386/CentOS-6.9-i386-minimal.iso)
# 需求
- 手头有台笔记本 IBM thinkpad X31,处理器不支持 pae不支持 64 位操作系统要安装一个32位 CentOS6且内核无 pae 要求。
# 准备环境
- 在支持 pae 的计算机上安装 [VirtualBox](https://www.virtualbox.org/wiki/Downloads) 及其扩展包,以支持 VirtualBox 虚拟机中挂载宿主机 USB 存储。
- 取出 Thinkpad 笔记本的硬盘,通过移动硬盘盒等方法连接刚刚安装 VirtualBox 的计算机,确保该存储正常识别可用。
- 下载[CentOS-6.9-i386-minimal.iso](http://mirrors.ustc.edu.cn/centos/6.9/isos/i386/CentOS-6.9-i386-minimal.iso)
# VirtualBox 下安装 CentOS6.9 虚拟机
- 创建 CentOS6.9 x32 虚拟机,这里无需创建虚拟磁盘,后面会把 Thinkpad 笔记本的硬盘挂载到虚拟机中,直接把操作系统安装到该硬盘中。
![不用创建虚拟磁盘](/img/03092704_DUG6.png "无需创建虚拟机磁盘")
- 设置虚拟机,启动 USB 3.0 控制器,增加筛选器,选中刚刚 USB 连接的 Thinkpad 硬盘;网络模式自选,确保虚拟机可上网。
![启用USB 3.0 控制器](/img/03094814_oVJY.png "设置 USB")
- 使用刚刚下载好的 CentOS-6.9-i386-minimal.iso 启动 CentOS6.9 虚拟机,如下图
![启动虚拟机](/img/03100036_sRDb.png "启动虚拟机")
- 此时查看菜单栏"设备",会发现 Thinkpad 硬盘已挂载,如下图
![输入图片说明](/img/03100217_mMNU.png "查看挂载的 USB 设备")
- 选择 "Install or upgrade an existing system" 安装系统,选择安装设备,会看到唯一一个磁盘,如下图
![磁盘选择](/img/03101245_wAKJ.png "默认唯一的磁盘即 USB 设备")
- 该设备就是通过 USB 挂载的 Thinkpad 磁盘,划分好分区,完成系统安装。
# CentOS6.9 虚拟机 Rescue 启动挂载
- 由于 VirtuaBox 虚拟机尚不支持从 USB 启动,所以在上一步完成系统安装后,重启虚拟机,依旧使用 CentOS-6.9-i386-minimal.iso 启动。
- 此时从 "Rescue Installed system" 启动,如下图
![rescue](/img/03102522_BRPU.png "Rescue Installed system")
- 根据提示选择好语言、键盘,激活网卡,如下图
![激活网络](/img/03104347_AHmM.png "激活网络")
- "OK" 确认,选择网卡,如下图
![选择网卡](/img/03103545_bX3Q.png "选择网卡")
- "OK",根据自己的网络环境配置上网方式,如下图
![配置网卡地址](/img/03103719_CPnJ.png "配置网卡地址")
- "OK",进入 Rescue 界面,如下图
![Rescue](/img/03103936_CZ1s.png "Rescue")
- "Continue",选择好磁盘,"OK" 确认,提示根分区已挂载至 /mnt/sysimage 下,如下图
![根目录挂载地址](/img/03104155_Lz45.png "根目录挂载至 /mnt/sysimage")
- "OK", 进入 Rescue Shell此时执行
```bash
chroot /mnt/sysimage/ /bin/bash
```
- 至此,通过 VirtualBox 虚拟机成功启动 USB 存储(Thinkpad 硬盘)中的根分区并进入其 Bash 环境。
# 安装 NONPAE 内核
- 在刚刚启动的 Bash Shell 中,检查网络
```bash
ping www.baidu.com
```
- 关闭 selinux (可选)
```bash
sed -i 's/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
```
- 安装 NONPAE 内核
```bash
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-6-8.el6.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install kernel-lt-NONPAE
```
- 检查系统已安装的内核
```bash
rpm -qa|grep kernel
```
- 发现两个内核,一个是官方的 kernel-2.6,另一个是刚刚安装的 kernel-3.10kernel-3.10 就是可以在无 pae 处理器上启动的 NONPAE 内核。
- 退出当前 Chroot Shell 和 Rescure Shell
```bash
exit
exit
```
# 启动 Thinkpad X31
- 关闭虚拟机,退出 USB 磁盘,把磁盘装回 Thinkpad X31 笔记本中,开机,选择 3.10 内核即可正常启动。
- 卸载官方 2.6 内核(推荐)
```bash
yum erase kernel-2.6.32*
yum erase kernel-firemware-2.6.32*
```

View File

@ -0,0 +1,122 @@
---
title: "CentOS6 安装 Oracle11g"
date: 2019-10-30T17:56:57+08:00
lastmod: 2019-10-30T17:56:57+08:00
tags: ["oracle", "centos"]
categories: ["database"]
---
# 安装依赖
```bash
yum install binutils compat-libstdc++-33 compat-libstdc++-33.i686 \
elfutils-libelf elfutils-libelf-devel gcc gcc-c++ glibc glibc.i686 \
glibc-common glibc-devel glibc-devel.i686 glibc-headers ksh libaio \
libaio.i686 libaio-devel libaio-devel.i686 libgcc libgcc.i686 libstdc++ \
libstdc++.i686 libstdc++-devel make sysstat unixODBC unixODBC-devel
```
# 创建用户和用户组
```bash
groupadd dba oinstall
useradd -g oinstall -m oracle
```
# 配置oracle用户环境变量
- 打开 oracle 用户的的默认shell配置文件 ~/.bashrc在最后添加以下代码
```bash
export ORACLE_BASE=/opt/oracle/app #oracle数据库安装目录
export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/db_home1 #oracle数据库路径
export ORACLE_SID=orcl #oracle启动数据库实例名
export PATH=$ORACLE_HOME/bin:/usr/sbin:$PATH #添加系统环境变量
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib #添加系统环境变量
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8" #设置Oracle客户端中文utf8
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK #设置Oracle客户端中文gbk
```
- 使设置立刻生效
```bash
source /.bashrc
```
# 创建oracle 11g软件安装路径
```bash
mkdir /opt/oracle/app/product/11.2.0/db_home1 -p
chown oracle.oinstall /opt/oracle -R
```
# 配置内核参数
- 编辑 /etc/sysctl.conf在文件尾追加下面的参数设置
```
fs.file-max = 6815744
fs.aio-max-nr =1048576
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
kernel.sem = 250 32000 100 128
```
- 使设置生效
```bash
sysctl -p
```
# 限制 oracle 用户资源
- 编辑 /etc/security/limits.conf在末尾添加以下代码
```
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
```
# 安装字体
- 一般需要安装中易宋体字体百度随便下载一个zysong.ttf切换到zysong.ttf所在路径运行
```bash
mkdir /usr/share/fonts/zh_CN/TureType/ -p
mv zydong.ttf /usr/share/fonts/zh_CN/TrueType/
fc-cache -fv
```
# 安装oracle 11g
- 解压下载好的oracle 11g文件
```bash
unzip linux.x64_11gR2_database_1of2.zip -d /home/oracle/
unzip linux.x64_11gR2_database_2of2.zip -d /home/oracle/
chown oracle.oinstall /home/oracle/database/ -R
```
- **切换到 oracle 用户下**,运行安装程序
```bash
su - oracle
cd database
./runInstaller
```
- 若提示swap空间不足自行百度解决
# 配置监听器数据库
- Oracle软件安装完后执行 netca 命令配置监听器
```
netca
```
- 在图形界面中按提示配置监听器
- 执行 dbca 命令安装数据库
```bash
dbca
```
- 在图形界面中按提示安装数据库就可以了。
# 测试运行
- 数据库安装完后监听器与数据库实例就已启动,
- 停止和启动监听器
```bash
lsnrctl stop
lsnrctl start
```
- 停止和启动实例
```
sqlplus /nolog
SQL> connect / as sysdba;
SQL> shutdown
SQL> startup
#执行其它SQL语句测试数据库
```

View File

@ -0,0 +1,126 @@
---
title: "CentOS7 系统盘迁移"
date: 2019-10-30T01:03:45+08:00
lastmod: 2019-10-30T01:03:45+08:00
keywords: []
tags: ["centos", "系统", "迁移"]
categories: ["os"]
---
# 环境
- 两台服务器(A,B)
- A 已安装好 CentOS7且已**关闭 selinux**
- B 裸机,待安装操作系统
# 打包根分区
- 从 B 上拆下系统硬盘,接在 A 上,启动 A
- 清空日志(推荐)
```bash
cd /var/log/
find . -type f | xargs rm -f
```
- 关闭 selinux
```bash
sed -i '/^SELINUX=/cSELINUX=disabled' /mnt/etc/selinux/config
```
- 如果 A 是 MBR 启动,则直接打包根分区
```bash
tar zcpf /centos7.tgz --exclude=/centos7.tgz --one-file-system /
```
- 如果 A 是 EFI 启动,则需打包根分区和 EFI 分区
```bash
# 假设 efi 分区挂载在 /boot/efi 下
tar zcpf /centos7.tgz --exclude=/centos7.tgz --one-file-system / /boot/efi
```
# 硬盘分区
- 假设 /dev/sdb 是 B 的系统硬盘
- MBR 启动时,分区表是 dos只分一个根分区即可
- EFI 启动时,分区表是 gpt需要分一个 512MB 的 **efi 分区**和一个根分区
```bash
fdisk /dev/sdb
# n 创建新分区
# t 指定分区类型 1 (即 efi system
```
# 格式化
- MBR 启动
```bash
mkfs.xfs /dev/sdb1
```
- EFI 启动
```bash
mkfs.vfat -F32 /dev/sdb1
mkfs.xfs /dev/sdb2
```
# 挂载硬盘
- MBR 启动
```bash
mount /dev/sdb1 /mnt/
```
- EFI 启动
```bash
mount /dev/sdb2 /mnt/
mkdir -p /mnt/boot/efi
mount /dev/sdb1 /mnt/boot/efi/
```
# 部署操作系统
- 解压之前打包的 /centos7.tgz
```bash
tar zxpf /centos7.tgz -C /mnt/
```
- 替换 fstab 中的 uuid 信息
```bash
# 获取 B 的系统硬盘分区的 uuid 信息
lsblk -f /dev/sdb
# 把结果中的 uuid 替换到 /mnt/etc/fstab 中的相应位置
```
- 如果打包时未关闭 selinux此时可以修改配置文件
```bash
sed -i '/^SELINUX=/cSELINUX=disabled' /mnt/etc/selinux/config
```
- 删除网卡硬件标识(推荐)
```bash
sed -i -e '/HWADDR/d' -e '/UUID/d' /mnt/etc/sysconfig/network-scripts/ifcfg-{eth,enp}*
```
- 删除 ssh 主机密钥(推荐)
```bash
rm -rf /etc/ssh/ssh_host_*
```
# 部署 grub
- MBR 启动
```bash
mount --bind /dev/ /mnt/dev/
mount -t proc procfs /mnt/proc/
mount -t sysfs sysfs /mnt/sys/
chroot /mnt
grub2-install /dev/sdb
grub2-mkconfig -o /boot/grub2/grub.cfg
exit
```
- EFI 启动
```bash
mount --bind /dev/ /mnt/dev/
mount -t proc procfs /mnt/proc/
mount -t sysfs sysfs /mnt/sys/
mount -t efivarfs efivarfs /target/sys/firmware/efi/efivars/
chroot /mnt
efibootmgr -c -p 1 -d /dev/sdb -L "centos"
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
exit
```
# 启动操作系统
- 卸载 B 的系统硬盘
```bash
umount -R /mnt
```
- 关闭 A拆下刚部署好操作系统的硬盘接回 B 中
- 启动 B刚部署的 CentOS7 正常启动
# 参考
- [https://wiki.centos.org/zh/HowTos/ManualInstall?highlight=%28grub2-install%29](https://wiki.centos.org/zh/HowTos/ManualInstall?highlight=%28grub2-install%29)

189
content/post/centos7.md Normal file
View File

@ -0,0 +1,189 @@
---
title: "CentOS7 笔记"
date: 2019-10-30T10:58:18+08:00
lastmod: 2019-10-30T10:58:18+08:00
keywords: []
tags: ["centos"]
categories: ["os"]
---
# 常用初始配置
- 系统更新
```bash
yum update
```
- 禁用 firewalld
```bash
systemctl stop firewalld
systemctl disable firewalld
```
- 禁用 NetworkManager
```bash
systemctl stop NetworkManager
systemctl disable NetworkManager
```
- 禁用 postfix
```bash
systemctl stop postfix
systemctl disable postfix
```
- 如果不用 NFS可以禁用 rpcbind
```bash
systemctl stop rpcbind
systemctl disable rpcbind
```
- 禁用 selinux可能需要重启操作系统
```bash
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
setenforce 0
# 可能需要重启
```
- 配置网卡静态地址
```bash
cd /etc/sysconfig/network-scripts
sed -i -e '/^BOOTPROTO/d' -e '/^ONBOOT/d' \
-e '/^IPADDR/d' -e '/^NETMASK/d' -e '/^PREFIX/d' \
-e '/^GATEWAY/d' -e '/^DNS/d' ${ifcfg}
cat >> ${ifcfg} <<-END
ONBOOT=yes
BOOTPROTO=static
IPADDR=${ip}
PREFIX=${mask}
GATEWAY=${gw}
DNS1=${dns}
END
systemctl restart network
```
- 修改 sysctl.conf
```bash
cat >> /etc/sysctl.conf <<-END
# 防止一个套接字在有过多试图连接到达时引起过载
net.ipv4.tcp_syncookies = 1
# 连接队列的长度默认值为128
net.core.somaxconn = 1024
# timewait的超时时间设置短一些
net.ipv4.tcp_fin_timeout = 10
# os直接使用timewait的连接
net.ipv4.tcp_tw_reuse = 1
# 回收timewait连接
net.ipv4.tcp_tw_recycle = 1
END
sysctl -p
```
- 修改主机名
```bash
hostnamectl set-hostname ${hostname}
sed -i "/[ \t]\+${hostname}[ \t]*$/d" /etc/hosts
echo "${ip} ${hostname}" >> /etc/hosts
```
- 禁用 sshd 域名解析
```bash
sed -i '/UseDNS/d' /etc/ssh/sshd_config
echo 'UseDNS no' >> /etc/ssh/sshd_config
```
- 删除可能存在的 TMOUT 环境变量
```bash
sed -i '/^export[ \t]\+TMOUT=/d' /etc/profile
```
- 配置 history 命令数量和执行时间
```bash
echo 'export HISTSIZE=10000' > /etc/profile.d/history.sh
echo 'export HISTTIMEFORMAT="[%F %T] "' >> /etc/profile.d/history.sh
```
- 修改时间同步服务器地址
```bash
sed -i '/^server /d' /etc/chrony.conf
echo "server ${ip|domain} iburst" >> /etc/chrony.conf
```
- 修改 rsyslog 服务的时间格式
```bash
cat > /etc/rsyslog.d/custom.conf <<EOF
template(name="CustomTime" type="list"){
property(name="timereported" dateformat="year")
constant(value="-")
property(name="timereported" dateformat="month")
constant(value="-")
property(name="timereported" dateformat="day")
constant(value=" ")
property(name="timereported" dateformat="hour")
constant(value=":")
property(name="timereported" dateformat="minute")
constant(value=":")
property(name="timereported" dateformat="second")
constant(value=" ")
property(name="hostname")
constant(value=" ")
property(name="syslogtag")
constant(value=" ")
property(name="msg" droplastlf="on")
constant(value="\n")
}
$ActionFileDefaultTemplate CustomTime
EOF
```
- 其他检查
- 卸载 ntpdate换 chrony
- 检查 /etc/rc.d/rc.local
# 安全设置
- /etc/pam.d/sshd
- 用户 ssh 登陆密码错误 3 次后锁住用户 10 分钟
```
auth required pam_tally2.so deny=3 unlock_time=600 even_deny_root
```
- /etc/login.defs
- 密码过期天数
```
PASS_MAX_DAYS 60
```
- 过期前警告天数
```
PASS_WARN_AGE 7
```
- 最短使用天数
```
PASS_MIN_DAYS 1
```
- 最短长度
```
PASS_MIN_LEN 8
```
- /etc/pam.d/system-auth
- 密码与前 5 次不同
```
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5
```
- /etc/security/pwquality.conf
- 密码最小长度 8 位
```bash
authconfig --passminlen=8 --update
```
- 密码最少 2 种字符
```bash
authconfig --passminclass=2 --update
```
- 最多 2 个连续相同字符
```bash
authconfig --passmaxrepeat=2 --update
```
- 最多 4 个连续同类字符
```bash
authconfig --passmaxclassrepeat=4 --update
```
- 至少 1 个小写字符
```bash
authconfig --enablereqlower --update
```
- 至少 1 个大写字符
```bash
authconfig --enablerequpper --update
```
- 至少 1 个数字
```bash
authconfig --enablereqdigit --update
```
- 至少 1 个特殊字符
```bash
authconfig --enablereqother --update
```

View File

@ -0,0 +1,535 @@
---
title: "RockyLinux 安装 Ceph"
date: 2019-10-30T11:09:30+08:00
lastmod: 2021-09-29T12:25:00+08:00
keywords: []
tags: ["ceph"]
categories: ["storage"]
---
# 环境
操作系统 | 主机名 | 公用地址 | 集群地址 | 数据裸盘 | ceph 版本
---- | ---- | ---- | ---- | ---- | ----
Rocky Linux 8.4 | ceph41 | 10.0.4.41 | 192.168.4.41 | /dev/sdb, /dev/sdc | 15.2.14
Rocky Linux 8.4 | ceph42 | 10.0.4.42 | 192.168.4.42 | /dev/sdb, /dev/sdc | 15.2.14
Rocky Linux 8.4 | ceph43 | 10.0.4.43 | 192.168.4.43 | /dev/sdb, /dev/sdc | 15.2.14
# 关闭防火墙,配置 host
- 在全部节点上执行如下操作
- 关闭 firewalld 和 SELinux
```bash
systemctl stop firewalld
systemctl disable firewalld
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config # 重启操作系统生效
```
- 配置各节点主机名解析
```bash
echo "10.0.4.41 ceph41" >> /etc/hosts
echo "10.0.4.42 ceph42" >> /etc/hosts
echo "10.0.4.43 ceph43" >> /etc/hosts
```
# 配置 yum 源
- 在全部节点上执行如下操作
- 移动系统默认的 repo 文件到备份目录
```bash
cd /etc/yum.repos.d
mkdir bak
mv Rocky-*.repo bak/
```
- 创建新的系统 yum 源文件 /etc/yum.repos.d/rocky-nju.repo使用南京大学镜像站内容如下
```
[appstream]
name=Rocky Linux $releasever - AppStream
baseurl=https://mirrors.nju.edu.cn/$contentdir/$releasever/AppStream/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial
[baseos]
name=Rocky Linux $releasever - BaseOS
baseurl=https://mirrors.nju.edu.cn/$contentdir/$releasever/BaseOS/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial
```
- 创建 epel yum 源文件 /etc/yum.repos.d/epel-tsinghua.repo使用清华大学镜像站内容如下
```
[epel]
name=Extra Packages for Enterprise Linux $releasever - $basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/$releasever/Everything/$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever
```
- 下载 RPM-GPG-KEY-EPEL-8
```bash
cd /etc/pki/rpm-gpg/
curl -LO https://mirrors.nju.edu.cn/epel/RPM-GPG-KEY-EPEL-8
```
- 创建 ceph yum 源文件 /etc/yum.repos.d/ceph-tsinghua.repo使用清华大学镜像站内容如下
```
[ceph]
name=Ceph packages for $basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-15.2.14/el8/$basearch
enabled=1
priority=2
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/ceph/keys/release.asc
[ceph-noarch]
name=Ceph noarch packages
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-15.2.14/el8/noarch
enabled=1
priority=2
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/ceph/keys/release.asc
```
- 导入 release.asc
```bash
rpm --import 'https://mirrors.tuna.tsinghua.edu.cn/ceph/keys/release.asc'
```
- 更新 yum 缓存
```bash
dnf clean all
dnf makecache
```
# 配置时间同步
- 在全部节点上执行如下操作
- 安装 chrony
```bash
dnf install chrony
```
- 如果内网没有时间服务器,可以在 ceph41 上启动一个时间同步服务,修改 /etc/chrony.conf
```
...
pool ntp.aliyun.com iburst
...
allow 10.0.4.0/24
...
local stratum 10
...
```
- 设置 ceph42 和 ceph43 从 ceph41 上同步时间,修改 /etc/chrony.conf
```
...
pool ceph41 iburst
...
```
- 在全部服务器上启动 chronyd 服务,并设置开机自动启动
```bash
systemctl start chronyd
systemctl enable chronyd
```
# 安装 ceph
- 在全部节点上执行如下操作
```bash
dnf install leveldb gdisk gperftools-libs python3-ceph-argparse nvme-cli
dnf install ceph
```
- 创建 ceph 配置文件 /etc/ceph/ceph.conf内容如下
```
[global]
fsid = aaaa0000-bbbb-1111-cccc-2222dddd3333
mon_initial_members = ceph41, ceph42, ceph43
mon_host = 10.0.4.41, 10.0.4.42, 10.0.4.43
public_network = 10.0.4.0/24
cluster_network = 192.168.4.0/24
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
osd_pool_default_size = 2 # 推荐使用官方默认的 3
osd_pool_default_min_size = 2
```
# 部署 mon
- 在 ceph41 上执行如下操作
- 这里创建了一堆傻逼密钥文件,没看懂啥意思,照搬官网
```bash
ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'
ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'
ceph-authtool --create-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring --gen-key -n client.bootstrap-osd --cap mon 'profile bootstrap-osd' --cap mgr 'allow r'
ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring
ceph-authtool /tmp/ceph.mon.keyring --import-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring
chown ceph:ceph /tmp/ceph.mon.keyring
monmaptool --create --add ceph41 10.0.4.41 --add ceph42 10.0.4.42 --add ceph43 10.0.4.43 --fsid aaaa0000-bbbb-1111-cccc-2222dddd3333 /tmp/monmap
```
- 初始化 mon 数据目录
```bash
sudo -u ceph mkdir /var/lib/ceph/mon/ceph-ceph41
sudo -u ceph ceph-mon --mkfs -i ceph41 --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring
```
- 启动 mon 服务,并设置开机自动启动
```bash
systemctl start ceph-mon@ceph41
systemctl enable ceph-mon@ceph41
```
- 复制密钥文件到 ceph42 和 ceph43 上
```bash
scp /tmp/{ceph.mon.keyring,monmap} ceph42:/tmp/
scp /etc/ceph/ceph.client.admin.keyring ceph42:/etc/ceph/
scp /var/lib/ceph/bootstrap-osd/ceph.keyring ceph42:/var/lib/ceph/bootstrap-osd/
scp /tmp/{ceph.mon.keyring,monmap} ceph43:/tmp/
scp /etc/ceph/ceph.client.admin.keyring ceph43:/etc/ceph/
scp /var/lib/ceph/bootstrap-osd/ceph.keyring ceph43:/var/lib/ceph/bootstrap-osd/
```
- 在 **ceph42** 上执行如下操作
- 初始化 mon 数据目录
```bash
chown ceph:ceph /tmp/ceph.mon.keyring
sudo -u ceph mkdir /var/lib/ceph/mon/ceph-ceph42
sudo -u ceph ceph-mon --mkfs -i ceph42 --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring
```
- 启动 mon 服务,并设置开机自动启动
```bash
systemctl start ceph-mon@ceph42
systemctl enable ceph-mon@ceph42
```
- 在 **ceph43** 上执行如下操作
- 初始化 mon 数据目录
```bash
chown ceph:ceph /tmp/ceph.mon.keyring
sudo -u ceph mkdir /var/lib/ceph/mon/ceph-ceph43
sudo -u ceph ceph-mon --mkfs -i ceph43 --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring
```
- 启动 mon 服务,并设置开机自动启动
```bash
systemctl start ceph-mon@ceph43
systemctl enable ceph-mon@ceph43
```
- 在任一节点上执行如下操作
- mon 额外配置
```bash
# 开启 msgr2监听 tcp 3300 端口
ceph mon enable-msgr2
# 禁用 auth_allow_insecure_global_id_reclaim
ceph config set mon auth_allow_insecure_global_id_reclaim false
```
## 查看集群状态
- 在任一节点上执行如下操作
```bash
ceph -s
```
- 集群状态如下
```
cluster:
id: aaaa0000-bbbb-1111-cccc-2222dddd3333
health: HEALTH_OK
services:
mon: 3 daemons, quorum ceph41,ceph42,ceph43 (age ...)
mgr: no daemons active
osd: 0 osds: 0 up, 0 in
data:
pools: 0 pools, 0 pgs
objects: 0 objects, 0 B
usage: 0 B used, 0 B / 0 B avail
pgs:
```
# 部署 mgr
- 在 ceph41 上执行如下操作
- 又是创建密钥文件,没看懂啥意思,照搬官网
```bash
sudo -u ceph mkdir /var/lib/ceph/mgr/ceph-ceph41
ceph auth get-or-create mgr.ceph41 mon 'allow profile mgr' osd 'allow *' mds 'allow *' -o /var/lib/ceph/mgr/ceph-ceph41/keyring
chown ceph.ceph /var/lib/ceph/mgr/ceph-ceph41/keyring
```
- 启动 mgr 服务,并配置开机自动启动
```bash
systemctl start ceph-mgr@ceph41
systemctl enable ceph-mgr@ceph41
```
- 在 ceph42 上执行如下操作
- 创建密钥文件
```bash
sudo -u ceph mkdir /var/lib/ceph/mgr/ceph-ceph42
ceph auth get-or-create mgr.ceph42 mon 'allow profile mgr' osd 'allow *' mds 'allow *' -o /var/lib/ceph/mgr/ceph-ceph42/keyring
chown ceph.ceph /var/lib/ceph/mgr/ceph-ceph42/keyring
```
- 启动 mgr 服务,并配置开机自动启动
```bash
systemctl start ceph-mgr@ceph42
systemctl enable ceph-mgr@ceph42
```
- 在 ceph43 上执行如下操作
- 创建密钥文件
```bash
sudo -u ceph mkdir /var/lib/ceph/mgr/ceph-ceph43
ceph auth get-or-create mgr.ceph43 mon 'allow profile mgr' osd 'allow *' mds 'allow *' -o /var/lib/ceph/mgr/ceph-ceph43/keyring
chown ceph.ceph /var/lib/ceph/mgr/ceph-ceph43/keyring
```
- 启动 mgr 服务,并配置开机自动启动
```bash
systemctl start ceph-mgr@ceph43
systemctl enable ceph-mgr@ceph43
```
## 查看集群状态
- 在任一节点上执行如下操作
```bash
ceph -s
```
- 集群状态如下
```
cluster:
id: aaaa0000-bbbb-1111-cccc-2222dddd3333
health: HEALTH_WARN
OSD count 0 < osd_pool_default_size 2
services:
mon: 3 daemons, quorum ceph41,ceph42,ceph43 (age ...)
mgr: ceph41(active, since ...), standbys: ceph42, ceph43
osd: 0 osds: 0 up, 0 in
data:
pools: 0 pools, 0 pgs
objects: 0 objects, 0 B
usage: 0 B used, 0 B / 0 B avail
pgs:
```
# 部署 osd
## 逻辑卷 osd
- 操作简单,推荐
- 直接创建并启动逻辑卷 osd
```bash
ceph-volume lvm create --bluestore --data /dev/sdb
ceph-volume lvm create --bluestore --data /dev/sdc
```
- 上一步执行成功后,每个 ceph-osd 服务都已启动,且开机自动启动
## 裸设备 osd
- 操作麻烦,不推荐
- 在全部节点上执行如下操作
- 准备 osd
```bash
ceph-volume raw prepare --bluestore --data /dev/sdb
ceph-volume raw prepare --bluestore --data /dev/sdc
```
- 查看 osd 的 id
```bash
ceph-volume raw list
```
- 激活 osd**使用裸设备创建 osd 时不支持 systemd需要单独配置开机自动启动**
```bash
ceph-volume raw activate --device /dev/sdb --no-systemd
ceph-volume raw activate --device /dev/sdc --no-systemd
```
- 在 ceph41 上启动 osd 服务
```bash
systemctl start ceph-osd@0
systemctl start ceph-osd@1
```
- 配置开机自动启动
```bash
chmod 0755 /etc/rc.d/rc.local
echo 'ceph-volume raw activate --device /dev/sdb --no-systemd
ceph-volume raw activate --device /dev/sdc --no-systemd
systemctl start ceph-osd@0
systemctl start ceph-osd@1
' >> /etc/rc.d/rc.local
```
- 在 ceph42 上启动 osd 服务
```bash
systemctl start ceph-osd@2
systemctl start ceph-osd@3
```
- 配置开机自动启动
```bash
chmod 0755 /etc/rc.d/rc.local
echo 'ceph-volume raw activate --device /dev/sdb --no-systemd
ceph-volume raw activate --device /dev/sdc --no-systemd
systemctl start ceph-osd@2
systemctl start ceph-osd@3
' >> /etc/rc.d/rc.local
```
- 在 ceph43 上启动 osd 服务
```bash
systemctl start ceph-osd@4
systemctl start ceph-osd@5
```
- 配置开机自动启动
```bash
chmod 0755 /etc/rc.d/rc.local
echo 'ceph-volume raw activate --device /dev/sdb --no-systemd
ceph-volume raw activate --device /dev/sdc --no-systemd
systemctl start ceph-osd@4
systemctl start ceph-osd@5
' >> /etc/rc.d/rc.local
```
## 查看集群状态
- 在任一节点执行如下操作
```bash
ceph -s
```
- 集群状态如下
```
cluster:
id: aaaa0000-bbbb-1111-cccc-2222dddd3333
health: HEALTH_OK
services:
mon: 3 daemons, quorum ceph41,ceph42,ceph43 (age ...)
mgr: ceph41(active, since ...), standbys: ceph42, ceph43
osd: 6 osds: 6 up (since ...), 6 in (since ...)
data:
pools: 1 pools, 1 pgs
objects: 0 objects, 0 B
usage: ... GiB used, ... GiB / ... GiB avail
pgs: 1 active+clean
```
# 部署 mds
- 只有 cephfs 会用到 mds
- 在 ceph41 上执行如下操作
- 创建密钥文件 ...... 照搬官网
```bash
sudo -u ceph mkdir -p /var/lib/ceph/mds/ceph-ceph41
sudo -u ceph ceph-authtool --create-keyring /var/lib/ceph/mds/ceph-ceph41/keyring --gen-key -n mds.ceph41
ceph auth add mds.ceph41 osd "allow rwx" mds "allow *" mon "allow profile mds" -i /var/lib/ceph/mds/ceph-ceph41/keyring
```
- 启动 mds 服务,并配置开机自动启动
```bash
systemctl start ceph-mds@ceph41
systemctl enable ceph-mds@ceph41
```
- 在 ceph42 上执行如下操作
- 创建密钥文件 ...... 照搬官网
```bash
sudo -u ceph mkdir -p /var/lib/ceph/mds/ceph-ceph42
sudo -u ceph ceph-authtool --create-keyring /var/lib/ceph/mds/ceph-ceph42/keyring --gen-key -n mds.ceph42
ceph auth add mds.ceph42 osd "allow rwx" mds "allow *" mon "allow profile mds" -i /var/lib/ceph/mds/ceph-ceph42/keyring
```
- 启动 mds 服务,并配置开机自动启动
```bash
systemctl start ceph-mds@ceph42
systemctl enable ceph-mds@ceph42
```
- 在 ceph43 上执行如下操作
- 创建密钥文件 ...... 照搬官网
```bash
sudo -u ceph mkdir -p /var/lib/ceph/mds/ceph-ceph43
sudo -u ceph ceph-authtool --create-keyring /var/lib/ceph/mds/ceph-ceph43/keyring --gen-key -n mds.ceph43
ceph auth add mds.ceph43 osd "allow rwx" mds "allow *" mon "allow profile mds" -i /var/lib/ceph/mds/ceph-ceph43/keyring
```
- 启动 mds 服务,并配置开机自动启动
```bash
systemctl start ceph-mds@ceph43
systemctl enable ceph-mds@ceph43
```
## 查看集群状态
- 在任一节点上执行如下操作
```bash
ceph -s
```
- 集群状态如下
```
cluster:
id: aaaa0000-bbbb-1111-cccc-2222dddd3333
health: HEALTH_OK
services:
mon: 3 daemons, quorum ceph41,ceph42,ceph43 (age ...)
mgr: ceph41(active, since ...), standbys: ceph42, ceph43
mds: cephfs:1 {0=ceph43=up:active} 2 up:standby
osd: 3 osds: 3 up, 3 in
data:
pools: 1 pools, 1 pgs
objects: 0 objects, 0 B
usage: ... GiB used, ... GiB / ... GiB avail
pgs: 1 active+clean
```
# 简单使用
## rbd
- 创建 rbd 池
```bash
ceph osd pool create rbd 128 128
ceph osd pool application enable rbd rbd
```
## cephfs
- 创建 cephfs 池
```bash
# 创建 cephfs 元数据池pg 不用太大,设置 3 个副本
ceph osd pool create cephfs_metadata 8 8
ceph osd pool set cephfs_metadata size 3
# 创建 cephfs 数据池,根据数据量配置相应 pg
ceph osd pool create cephfs_data 128 128
```
- 创建 cephfs 文件系统
```bash
ceph fs new cephfs cephfs_metadata cephfs_data
```
- 查看 mds 状态
```bash
ceph mds stat
```
- 在任一 ceph 节点服务器上查看 admin 用户的 key
```bash
cat /etc/ceph/ceph.client.admin.keyring | grep key | awk '{print $2}'
```
- 在其他服务器上挂载 cephfs
```bash
mount -t ceph 10.0.4.41:6789,10.0.4.42:6789,10.0.4.43:6789:/ /mnt -o name=admin,secret={admin 的 key}
```

177
content/post/ceph.md Normal file
View File

@ -0,0 +1,177 @@
---
title: "Ceph 笔记"
date: 2019-10-30T11:44:37+08:00
lastmod: 2019-10-30T11:44:37+08:00
tags: ["ceph"]
categories: ["storage"]
---
# 测试环境
操作系统 | 主机名 | IP | OSD 设备 | OSD ID | 容量 | ceph 版本
---- | ---- | ---- | ---- | ---- | ---- | ----
CentOS7 | ceph101 | 192.168.1.101 | /dev/sdb | 0 | 3TB | jewel
CentOS7 | ceph102 | 192.168.1.102 | /dev/sdb | 1 | 3TB | jewel
CentOS7 | ceph103 | 192.168.1.103 | /dev/sdb | 2 | 3TB | jewel
- ceph 部署机
- 操作系统: CentOS7
- 部署用户: cephdeploy
- 操作目录: /home/cephdeploy/ceph-cluster
- IP: 192.168.1.100
# 新增 OSD
- 设置 ceph 三个 noflag禁止 ceph 自动迁移数据
```bash
# 在任一节点上执行下面命令即可
ceph osd set noout
ceph osd set nobackfill
ceph osd set norecover
ceph -s # 此时能看到这三个 flag而且集群处于不健康状态
```
- 关闭这三台 ceph 服务器, 加装新的磁盘,个人认为无需配置多盘 raid
- 启动这三台 ceph 服务器,此时 ceph 自动启动,那三个 noflag 依旧有效
- 此时查看每台服务器的存储,应该能看到新增的一个或多个裸磁盘
```bash
lsblk
```
- 这里假设每台服务器新增两个磁盘(/dev/sdc,/dev/sdd),都配置成 osd
```bash
# 在 ceph 部署机上执行以下命令
su - cephdeploy
cd /home/cephdeploy/ceph-cluster
# 每次创建一个,别浪 ...
ceph-deploy osd create ceph101:/dev/sdc
ceph-deploy osd create ceph101:/dev/sdd
ceph-deploy osd create ceph102:/dev/sdc
ceph-deploy osd create ceph102:/dev/sdd
ceph-deploy osd create ceph103:/dev/sdc
ceph-deploy osd create ceph103:/dev/sdd
```
- osd 增加完成后, 取消之前设置的那三个 noflag
```bash
# 在任一节点上执行下面命令即可
ceph osd unset noout
ceph osd unset nobackfill
ceph osd unset norecover
```
- 此时数据向新增的 osd 上均衡,时间不确定 …… 只能等!
```bash
# 在任一节点上执行下面命令,观察数据迁移
ceph -w
```
- 直至 ceph 恢复健康状态
```bash
# 在任一节点上执行下面命令,查看集群状态
ceph -s
```
# 删除 OSD
- 把指定的 osd 踢出集群
```bash
# 在任一节点上执行下面命令即可
ceph osd out {osd-id}
ceph -s # 此时能看到一个 osd 已经 out
```
- 此时数据在剩下的几个 osd 上均衡,时间不确定 …… 只能等!
```bash
# 在任一节点上执行下面命令,观察数据迁移
ceph -w
```
- 直至 ceph 恢复健康状态
```bash
# 在任一节点上执行下面命令,查看集群状态
ceph -s
```
- 停止该被踢出的 osd
```bash
# 在运行该 osd 的节点上执行下面命令
systemctl stop ceph-osd@{osd-id}
ceph -s # 此时能看到一个 osd 已经 down
```
- 删除该被停止的 osd
```bash
# 在任一节点上执行下面命令即可
# 删除 CRUSH 图对应的 osd 条目
ceph osd crush remove osd.{osd-id}
# 删除 osd 认证密钥
ceph auth del osd.{osd-id}
# 删除 osd
ceph osd rm {osd-num}
# 删除各节点的 ceph.conf 可能存在的 osd.{osd-id} 配置
```
- 设置 ceph 三个 noflag禁止 ceph 自动迁移数据
```bash
# 在任一节点上执行下面命令即可
ceph osd set noout
ceph osd set nobackfill
ceph osd set norecover
ceph -s # 此时能看到这三个 flag而且集群处于不健康状态
```
- 关闭这三台 ceph 服务器,撤掉已被删除 osd 对应的旧磁盘
- 启动这三台 ceph 服务器,此时 ceph 自动启动,三个 noflag 依旧有效;
- 取消之前设置的那三个 noflag
```bash
# 在任一节点上执行下面命令即可
ceph osd unset noout
ceph osd unset nobackfill
ceph osd unset norecover
```
- 直至 ceph 恢复健康状态
```bash
# 在任一节点上执行下面命令,查看集群状态
ceph -s
```
# OSD 动态配置
- 查看 osd 当前配置
```bash
ceph -n osd.0 --show-config
```
- 动态修改 osd 某个参数
```bash
ceph tell osd.* injectargs '--osd_max_backfills 7'
```
# PG 和 PGP
- 少于 5 个 OSD 时可把 pg_num 设置为 128
- OSD 数量在 5 到 10 个时,可把 pg_num 设置为 512
- OSD 数量在 10 到 50 个时,可把 pg_num 设置为 1024
- OSD 数量大于 50 时,<osd数量> * 100/副本数量(默认3),该值接近的 2 的 N 次方值
- 存储池的 PG 和 PGP 数量一般相等,都是 2 的 N 次方,只能增加,每次增加为当前的 2 倍
- 查看存储池的 PG 和 PGP 数量
```bash
ceph osd pool get {pool_name} pg_num
ceph osd pool get {pool_name} pgp_num
```
- 增加/设置存储池的 PG 和 PGP 数量
```bash
ceph osd pool set {pool_name} <cur_pg_num>*2
ceph osd pool set {pool_name} <cur_pgp_num>*2
```
- 获取所有卡在某状态的归置组统计信息
```bash
ceph pg dump_stuck inactive|unclean|stale|undersized|degraded
#Inactive (不活跃)归置组不能处理读写,因为它们在等待一个有最新数据的 OSD 复活且进入集群
#Unclean (不干净)归置组含有复制数未达到期望数量的对象,它们应该在恢复中
```
- 获取一个具体归置组的归置组图
```bash
ceph pg map {pg-id}
```
# CEPH 服务器关机维护
- 设置 ceph 节点 down 后不自动迁移或恢复数据
```bash
ceph osd set noout
ceph osd set nobackfill
ceph osd set norecover
```
- 直接关机
- 下次开机
- 设置 ceph 节点开始自动迁移或回复数据
```bash
ceph osd unset noout
ceph osd unset nobackfill
ceph osd unset norecover
```

39
content/post/ch-buffer.md Normal file
View File

@ -0,0 +1,39 @@
---
title: "ClickHouse 表引擎之 Buffer"
date: 2020-10-08T18:08:00+08:00
lastmod: 2020-10-08T18:08:00+08:00
tags: []
categories: ["clickhouse"]
---
# Buffer 表引擎简介
- 只写内存,无持久化存储
- 缓冲高并发写入满足条件时Buffer 表会把数据刷新到目标表
# 创建 Join 引擎表
- 声明
```sql
ENGINE = Buffer(
database,
table,
num_layers,
min_time,
max_time,
min_rows,
max_rows,
min_bytes,
max_bytes
)
```
- database: 目标表所在数据库
- table: 目标表名
- num_layers: 刷新数据到目标表时开启的线程数,官方建议 16
- min_time 和 max_time: 时间条件,单位秒
- min_rows 和 max_rows: 数据行数条件
- min_bytes 和 max_bytes: 数据体量条件,单位字节
- 所有最小阈值都满足时,触发刷新
- 至少一个最大阈值满足时,触发刷新
- 如果一批数据的行数大于 max_rows或体量大于 max_bytes则数据直接写入目标表
- 各线程(num_layers)单独计算刷新规则

255
content/post/ch-datadict.md Normal file
View File

@ -0,0 +1,255 @@
---
title: "ClickHouse 数据字典"
date: 2020-09-23T13:30:00+08:00
lastmod: 2020-10-08T18:50:00+08:00
tags: []
categories: ["clickhouse"]
---
# 简介
- 常驻内存,支持动态更新
- 适合保存常量和经常使用的维度表数据
- 可通过字典函数访问,也可通过袋里表与其他数据表实现 JOIN 查询
# 内置字典
- 默认禁用
- 不想写了,没啥意思
# 外部扩展字典
## 配置文件
- 位置: /etc/clickhouse-server/\*\_dictionary.xml
- 自动感知变更,不停机在线更新
- 系统表: system.dictionaries
- 配置结构
```xml
<?xml version="1.0"?>
<dictionaries>
<dictionary>
<!-- 字典名称,全局唯一 -->
<name>dict_name</name>
<!-- 字典数据结构 -->
<structure>
<!-- 数值 keyUInt64支持字典类型: flat、hashed、range_hashed、cache -->
<id>
<name>field_name</name>
<id>
<!-- 复合 keyTuple类似复合主键支持字典类型: complex_key_hashed、complex_key_cache -->
<key>
<attribute>
<name>field_name</name>
<type>field_type</type>
</attribute>
<attribute>
...
</attribute>
</key>
<!-- 字符串 keyString支持字典类型: ip_trie -->
<key>
<attribute>
<name>field_name</name>
<type>String</type>
</attribute>
</key>
<!-- 只在 range_hashed 字典类型中使用 -->
<range_min>
<name>field_name</name>
</range_min>
<range_max>
<name>field_name</name>
</range_max>
<!-- 字典属性 -->
<attribute>
<!-- 字段名称,必填 -->
<name>field_name</name>
<!-- 字段类型,必填 -->
<type>field_type</type>
<!-- 查询时key 无对应字段时的默认值,必填,这里指定的是空字符串 -->
<null_value></null_value>
<!-- 函数或运算符表达式,非必填,默认无表达式 -->
<expression></expression>
<!-- 是否支持层次结构,非必填,默认 false -->
<hierarchical>false</hierarchical>
<!-- 是否支持单射优化,非必填,默认 false -->
<injective>false</injective>
<!-- 是否开启 MongoDB 优化,非必填,默认 false -->
<is_object_id>false</is_object_id>
</attribute>
</structure>
<!-- 在内存中的数据格式类型 -->
<layout>
<!-- 性能最高,只能用数值 key数组结构保存初始容量 1024上限 500000
支持数据源: Local file、Executable file、HTTP、DBMS -->
<flat/>
<!-- 只能用数值 key散列结构保存无存储上限
支持数据源: Local file、Executable file、HTTP、DBMS -->
<hashed/>
<!-- 只能用数值 key散列结构保存并按时间排序无存储上限
range_min 和 range_max 指定时间区间字段,且字段必须是 Date 或 DateTime 类型
支持数据源: Local file、Executable file、HTTP、DBMS -->
<range_hashed/>
<!-- 只能用数值 key固定大小(size_in_cells)数组存储
cells 数组未缓存的数据在查询时才会加载并缓存到 cells 中,性能不稳定
支持数据源: Executable file、HTTP、ClickHouse、MySQL -->
<cache>
<!-- 缓存大小,视内存而定 -->
<size_in_cells>16384</size_in_cells>
</cache>
<!-- 只能用复合 key其他与 hashed 一样 -->
<complex_key_hashed/>
<!-- 只能用复合 key其他与 cache 一样 -->
<complex_key_cache>
<size_in_cells>16384</size_in_cells>
</complex_key_cache>
<!-- 只能用单个 String 字段trie 树结构,专用语 IP 前缀查询
支持数据源: Local file、Executable file、HTTP、DBMS -->
<ip_trie/>
</layout>
<!-- 数据源 -->
<source>
<!-- 本地文件,如果文件修改时间出现变动,会出发数据更新 -->
<file>
<path>/path/to/data.csv</path>
<format>CSV</format>
</file>
<!-- 可执行文件,如果文件修改时间出现变动,会出发数据更新 -->
<executable>
<command>cat /path/to/data.csv</command>
<format>CSV</format>
</executable>
<!-- 远程文件,支持 http 和 https 协议post 请求,如果文件修改时间出现变动,会出发数据更新 -->
<http>
<url>http://192.168.1.2:9080/data.csv</url>
<format>CSV</format>
</http>
<!-- mysql -->
<mysql>
<user>root</root>
<password>123456<password>
<replica>
<host>192.168.1.3</host>
<priority>1</priority>
</replica>
<port>3306</port>
<db>db_name</db>
<table>table_name</table>
<!-- 查询过滤条件,非必填 -->
<where>id=1</where>
<!-- 指定一条 sql 语句,如果返回结果和上一次不一样,则更新,非必填 -->
<invalidate_query>sql</invalidate_query>
</mysql>
<!-- clickhouse -->
<clickhouse>
<user>default</root>
<password><password>
<host>192.168.1.4</host>
<port>9000</port>
<db>default</db>
<table>table_name</table>
<where>id=1</where>
<invalidate_query>sql</invalidate_query>
</clickhouse>
<!-- mongodb -->
<mongodb>
<user></root>
<password><password>
<host>192.168.1.5</host>
<port>27017</port>
<db>db_name</db>
<colection>collection_name</collection>
</mongodb>
<!-- odbc 连接其他数据库 ... -->
</source>
<!-- 字典自动更新频率单位秒min 和 max 都是 0 表示禁用更新
在 cache 字典中还代表缓存失效时间
字典更新时旧版本依旧提供服务,新版本完全更新成功后才会替代就版本 -->
<lifetime>
<min>300</min>
<max>360</max>
</lifetime>
</dictionary>
<dictionary>
...
</dictionary>
</dictionaries>
```
## 操作
- 手动更新全部数据字典
```sql
SYSTEM RELOAD DICTIONARIES;
```
- 手动更新指定字典
```sql
SYSTEM RELOAD DICTIONARY dict_name
```
- 查看所有字典信息
```sql
SELECT name, type, key, attribute.names, attribute.types source FROM system.dictionaries;
```
- 字典函数查询
```sql
SELECT dictGet('dict_name', 'attr_name', key)
```
- 其他字典函数
- 无符号整型: dictGetUInt8、dictGetUInt16、dictGetUInt32、dictGetUInt64
- 整型: dictGetInt8、dictGetInt16、dictGetInt32、dictGetInt64
- 浮点数: dictGetFloat32、dictGetFloat64
- 字符串: ditGetString、dictGetUUID
- 日期: dictGetDate、dictGetDateTime
- ddl 创建字典
```sql
CREATE DICTIONARY dict_name(
...
) PRIMARY KEY id
LAYOUT(FLAT())
SOURCE(FILE(PATH '/path/to/data.csv' FORMAT CSV))
LIFETIME(1);
```
# Dictionary 表引擎
- 创建字典表
```sql
CREATE TABLE table_name(
...
) ENGINE = Dictionary(dict_name);
```
- dict_name: 已加载的字典名称
- 创建字典数据库,自动为每个字典创建对应的字典表
```sql
CREATE DATABASE dict_db ENGINE = Dictionary;
```

343
content/post/ch-datatype.md Normal file
View File

@ -0,0 +1,343 @@
---
title: "ClickHouse 数据定义"
date: 2020-09-23T12:00:00+08:00
lastmod: 2020-09-23T12:00:00+08:00
tags: []
categories: ["clickhouse"]
---
# 基础类型
## 整数
声明 | 大小(字节) | 范围
---- | ---- | ----
Int8 | 1 | -128 到 127
UInt8 | 1 | 0 到 255
Int16 | 2 | -32768 到 32767
UInt16 | 2 | 0 到 65535
Int32 | 4 | -2147483648 到 2147483647
UInt32 | 4 | 0 到 4294967295
Int64 | 8 | -9223372036854775808 到 9223372036854775807
UInt64 | 8 | 0 到 18446744073709551615
## 浮点数
声明 | 大小(字节) | 有效精度(位数)
---- | ---- | ----
Float32 | 4 | 7
Float64 | 8 | 16
- 正无穷: SELECT 0.8/0
- 负无穷: SELECT -0.8/0
- 非数字: SELECT 0/0
## 定点数
- 原生声明: Decimal(P,S)
- P: 总位数(整数+小数),取值范围 1~38
- S: 小数位数,取值范围 0~P
- 其他声明
- Decimal32(S): -10^(9-S) 到 10^(9-S)
- Decimal64(S): -10^(18-S) 到 10^(18-S)
- Decimal128(S): -10^(18-S) 到 10^(38-S)
## 字符串
声明 | 备注
---- | ----
String | 长度不固定,不限字符集,建议 UTF-8
FixedString(N) | 长度固定null 字节填充
UUID | 格式是 8-4-4-4-120 填充
## 时间
声明 | 精度 | 示例
---- | ---- | ----
Datetime | 秒 | 2020-09-18 19:59:00
Datetime64(N) | 亚秒 | 2020-09-18 19:59:00.00
Date | 日 | 2020-09-18
# 复合类型
## 数组
- 声明: [T], Array(T)
- 查询时会以最小储存代价为原则推断类型
- 元素类型可以不同,但必须兼容
## 元组
- 声明: (T), tuple(T)
- 查询时会以最小储存代价为原则推断类型
- 元素类型可以不同,且无须兼容
## 枚举
声明 | Key 类型 | Value 类型
---- | ---- | ----
Enum8('k1'=1,'k2'=2, ... ,'kN'=N) | String | Int8
Enum16('k1'=1,'k2'=2, ... ,'kN'=N) | String | Int16
- 枚举的所有后续操作,都会使用 Int 类型的 Value 值
## 嵌套
- 声明
```sql
Nested(
column1 T,
column2 T
)
```
- 嵌套字段中的每一列期望写入的是数组: Array(T)
- 同一行数据内,嵌套字段中的每一列的数组长度必须相等
- 访问嵌套字段中的列时用点(.)连接
## 可空类型
- 声明: Nullable(T)
- 只能和基础类型搭配使用,不用用于复合类型和索引字段
- 慎用,会额外生成 [Column].null.bin 文件保存 null 值,导致双倍文件操作,使查询和写入变慢
## 域名类型
声明 | 封装类型
---- | ----
IPv4 | UInt32
IPv6 | FixedString(16)
- Domain 类型不是字符串,不支持自动类型转换
- 调用 IPv4NumToString 或 IPv6NumToString 函数返回 IP 的字符串形式
# 数据库
## 操作
- 创建
```sql
CREATE DATABASE [IF NOT EXISTS] db_name [ENGINE = engine];
```
- 查看数据库列表
```sql
SHOW DATABASES;
```
- 切换
```sql
USE db_name;
```
- 查看当前数据库中的数据表列表
```sql
SHOW TABLES;
```
## 引擎
- Ordinary: 默认引擎,无须刻意声明,可以使用任意类型表引擎
- Dictionary: 字典引擎,自动为所有数据字典创建数据表
- Memory: 内存引擎,存放临时数据,数据只停留在内存中
- Lazy: 日志引擎,只能使用 Log 系列的表引擎
- MySQL: MySQL 引擎,自动拉取远端 MySQL 中的数据,并创建 MySQL 表引擎的数据表
# 数据表
## 操作
- 常规建表,默认在 default 数据库中创建
```sql
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name {
column1 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
column1 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
...
columnM Nested(
column11 [type],
column22 [type],
...
),
...
} ENGINE = engine;
```
- 复制其他表的结构
```sql
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name
AS [db_name1.]table_name1
[ENGINE = engine];
```
- 通过 SELECT 字句建表,顺带写入 SELECT 子查询的数据
```sql
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name
ENGINE = engine
AS SELECT ... ;
```
- 删表
```sql
DROP TABLE [IF EXISTS] [db_name.]table_name;
```
- 增加表字段,默认值补全
```sql
ALTER TABLE [db_name.]table_name ADD COLUMN [IF NOT EXISTS]
col_name [type] [default_expr] [AFTER col_name_after];
```
- 修改表字段
```sql
ALTER TABLE [db_name.]table_name MODIFY COLUMN [IF EXISTS]
col_name [type] [default_expr];
```
- 修改备注
```sql
ALTER TABLE [db_name.]table_name COMMENT COLUMN [IF EXISTS]
name 'some comment';
```
- 删除字段
```sql
ALTER TABLE [db_name.]table_name DROP COLUMN [IF EXISTS] name;
```
- 移动数据表,只能在单节点内移动
```sql
RENAME TABLE [db_name.]tb_name TO [db_name1.]tb_name1,
[db_name2.]tb_name2 TO [db_name3.]tb_name3,
... ;
```
- 清空数据表
```sql
TRUNCATE TABLE [IF EXISTS] [db_name.]tb_name;
```
## 表字段默认值
- 声明: DEFAULT、MATERIALIZED、ALIAS
- 如果表字段没有明确类型定义,则可根据默认值进行类型推断
- 写入数据时,只有 DEFAULT 类型字段可以 INSERT
- 查询数据时,只有 DEFUALT 类型字段可以 SELECT * 返回
- DEFAULT 和 MATERIALIZED 类型字段可以持久化
# 临时表
## 操作
- 创建
```sql
CREATE TEMPORARY TABLE [IF NOT EXISTS] table_name {
column1 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
column1 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
...
columnM Nested(
column11 [type],
column22 [type],
...
),
...
};
```
## 其他
- 临时表只支持 Memory 表引擎,与会话绑定
- 临时表不属于任何数据库,创建时无数据库参数和表引擎参数
- 临时表优先级大于普通表
# 分区表
## 操作
- 创建
```sql
CREATE TABLE partition_v1 (
ID String,
URL String,
EventTime Date
) ENGINE = MergeTree()
PARTITION BY toYYYYMMM(EventTime)
GROUP BY ID;
```
- 查看分区状态
```sql
SELECT table,partition,path from system.parts WHERE table = 'partition_v1'
```
- 删除分区
```sql
ALTER TABLE tb_name DROP PARTITION part_expr;
```
- 复制分区,前提是两表的结构和分区键相同
```sql
ALTER TABLE table_name1 REPLACE PARTITION part_expr FROM table_name;
```
- 重置分区数据
```sql
ALTER TABLE table_name CLEAR COLUMN col_name IN PARTITION part_expr;
```
- 卸载分区
```sql
ALTER TABLE table_name DETACH PARTITION part_expr;
```
- 装载分区
```sql
ALTER TABLE table_name ATTACH PARTITION part_expr;
```
## 其他
- 分区支持删除、替换和重置,只有 MergeTree 系列表引擎支持
# 视图
## 操作
- 创建普通视图
```sql
CREATE VIEW [IF NOT EXISTS] [db_name.]view_name AS SELECT ... ;
```
- 创建物化视图
```sql
CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]table_name
[TO [db.]name] [ENGINE = engine] [POPULATE] AS SELECT ... ;
# 如果使用了 POPULATE 修饰符,那么在创建视图时会一并导入 SELECT 结果集
```
- 查看物化视图列表
```sql
SHOW TABLES
# 输出前缀是 .inner.
```
- 删除视图
```sql
DROP TABLE view_name
```
## 其他
- 普通视图只是查询代理
- 物化视图有独立存储,不支持同步删除
# 分布式 DDL
- 使用 ON CLUSTER cluster_name 声明语句
```sql
CREATE TABLE table_name ON CLUSTER cluster_name(
col1 [type],
col2 [type],
...
) ENGINE = engine ... ;
```
# 写入数据
- INSERT 语句三种语法
```sql
INSERT INTO [db_name.]table_name [(c1,c2,c3 ...)]
VALUES (v1,v2,v3 ...), (v4,v5,v6 ...) ... ;
INSERT INTO [db_name.]table_name [(c1,c2,c3 ...)]
FORMAT format_name data_set;
INSERT INTO [db_name.]table_name [(c1,c2,c3 ...)] SELECT ... ;
```
# 修改和删除数据
## 操作
- 删除
```sql
ALTER TABLE [db_name.]table_name DELETE WHERE filter_expr;
```
- 修改
```sql
ALTER TABLE [db_name.]table_name UPDATE col1 = expr1 [, ...]
WHERE filter_expr;
```
## 其他
- mutation 操作很重,后台执行,语句提交后立即返回,不支持事务,不能回滚
- 通过 system.mutations 系统表查询进度

30
content/post/ch-file.md Normal file
View File

@ -0,0 +1,30 @@
---
title: "ClickHouse 表引擎之 File"
date: 2020-10-08T12:00:00+08:00
lastmod: 2020-10-08T12:00:00+08:00
tags: []
categories: ["clickhouse"]
---
# File 表引擎简介
- 直接读取本地文件
- 修改文件 = 数据更新
- 导出数据到本地文件
- 数据格式转换
# 创建 FILE 引擎表
- 声明
```sql
ENGINE = File('format')
```
- format 是文件中的数据格式,如 TSV、CSV 和 JSONEachRow 等
- 数据文件保存在 config.xml 中指定的 path 下,目录名是表名,数据文件名是 data.{format}
- 可以通过 CREATE 语句建表,也可以直接在 shell 下创建目录文件,再通过 ATTACH 语句挂载
```sql
ATTACH TABLE file_table(
name String,
value UInt32
) ENGINE = file(CSV)
```

250
content/post/ch-install.md Normal file
View File

@ -0,0 +1,250 @@
---
title: "CentOS7 安装 ClickHouse 集群"
date: 2020-09-23T10:18:00+08:00
lastmod: 2020-10-10T01:40:00+08:00
tags: []
categories: ["clickhouse"]
---
# 环境
## Zookeeper 服务器
eth0 IP | eth1 IP | 操作系统 | ZK 版本 | myid
---- | ---- | ---- | ---- | ----
10.0.4.101 | 10.1.4.101 | CentOS7.8 | 3.4.14 | 101
10.0.4.102 | 10.1.4.102 | CentOS7.8 | 3.4.14 | 102
10.0.4.103 | 10.1.4.103 | CentOS7.8 | 3.4.14 | 103
- eth0 网卡用于向客户端提供服务eth1 网卡用于 Zookeeper 集群内部通信
- 配置时间同步,关闭 selinux 和 firewalld
## ClickHouse 服务器
eth0 IP | eth1 IP | 操作系统 | CH 版本 | shard 值 | replica 值
---- | ---- | ---- | ---- | ---- | ----
10.0.4.181 | 10.1.4.181 | CentOS7.8 | 20.3 LTS | 1 | 10.1.4.181
10.0.4.182 | 10.1.4.182 | CentOS7.8 | 20.3 LTS | 1 | 10.1.4.182
10.0.4.183 | 10.1.4.183 | CentOS7.8 | 20.3 LTS | 2 | 10.1.4.183
10.0.4.184 | 10.1.4.184 | CentOS7.8 | 20.3 LTS | 2 | 10.1.4.184
10.0.4.185 | 10.1.4.185 | CentOS7.8 | 20.3 LTS | 3 | 10.1.4.185
10.0.4.186 | 10.1.4.186 | CentOS7.8 | 20.3 LTS | 3 | 10.1.4.186
- eth0 网卡用于向客户端提供服务eth1 网卡用于 ClickHouse 集群内部通信
- 配置时间同步,关闭 selinux 和 firewalld
# 安装 Zookeeper 集群
- ClickHouse 集群依赖 zookeeper 管理集群配置
- 安装过程参考: [CentOS7 安装 zookeeper 集群](/post/zk-install/)
- 启动 zookeeper 集群zookeeper 正常运行后,才能进行后续步骤
# 安装 ClickHouse 集群
## 配置 ClickHouse yum 源
- 在每台 ClickHouse 服务器上执行如下操作
- 生成 clickhouse.repo 文件
```bash
echo '[clickhouse-lts]
name=ClickHouse - LTS Repository
baseurl=https://mirrors.tuna.tsinghua.edu.cn/clickhouse/rpm/lts/$basearch/
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/clickhouse/CLICKHOUSE-KEY.GPG
gpgcheck=1
enabled=1
EOF
' > /etc/yum.repos.d/clickhouse.repo
```
- 重建 yum 缓存
```bash
yum clean all
yum makecache fast
```
## 安装 ClickHouse
- 在每台 ClickHouse 服务器上执行如下操作
- 安装 clickhouse-server 和 clickhouse-client
```bash
yum install clickhouse-server clickhouse-client
```
## 修改 ClickHouse 配置
- 在每台 ClickHouse 服务器上执行如下操作
- 我没用 /etc/metrika.xml 和 config.d 子目录,直接修改的 config.xml先备份
```bash
cd /etc/clickhouse-server/
cp config.xml config.xml.origin
```
- 编辑 /etc/clickhouse-server/config.xml修改部分如下
```xml
<!-- 各节点用于集群内部通信的 eth1 网卡 IP -->
<interserver_http_host>10.1.4.181</interserver_http_host> <!-- 10.0.4.181 -->
<interserver_http_host>10.1.4.182</interserver_http_host> <!-- 10.0.4.182 -->
<interserver_http_host>10.1.4.183</interserver_http_host> <!-- 10.0.4.183 -->
<interserver_http_host>10.1.4.184</interserver_http_host> <!-- 10.0.4.184 -->
<interserver_http_host>10.1.4.185</interserver_http_host> <!-- 10.0.4.185 -->
<interserver_http_host>10.1.4.186</interserver_http_host> <!-- 10.0.4.186 -->
<!-- 监听全部 IPV4 地址 -->
<listen_host>0.0.0.0</listen_host>
<!-- 默认数据目录,建议在该目录下挂载单独硬盘 -->
<path>/var/lib/clickhouse/</path>
<!-- 自定义存储策略,这里随便写了个 jbod非必须配置 -->
<storage_configuration>
<disks>
<default>
<keep_free_space_bytes>1073741824</keep_free_space_bytes>
</default>
<disk1>
<path>/clickhouse/disk1/</path> <!-- 该目录建议挂载单独硬盘 -->
</disk1>
<disk2>
<path>/clickhouse/disk2/</path> <!-- 该目录建议挂载单独硬盘 -->
</disk2>
</disks>
<policies>
<policy_jbod>
<volumes>
<disk_group>
<disk>disk1</disk>
<disk>disk2</disk>
</disk_group>
</volumes>
</policy_jbod>
</policies>
</storage_configuration>
<!-- 内存锁定 -->
<mlock_executable>true</mlock_executable>
<!-- 集群配置,三分片双副本 -->
<remote_servers>
<cluster_3s2r>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>10.1.4.181</host>
<port>9000</port>
</replica>
<replica>
<host>10.1.4.182</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>10.1.4.183</host>
<port>9000</port>
</replica>
<replica>
<host>10.1.4.184</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>10.1.4.185</host>
<port>9000</port>
</replica>
<replica>
<host>10.1.4.186</host>
<port>9000</port>
</replica>
</shard>
</cluster_3s2r>
</remote_servers>
<!-- zookeeper 配置 -->
<zookeeper>
<node index="1">
<host>10.0.4.101</host>
<port>2181</port>
</node>
<node index="2">
<host>10.0.4.102</host>
<port>2181</port>
</node>
<node index="3">
<host>10.0.4.103</host>
<port>2181</port>
</node>
</zookeeper>
<!-- 各节点的宏变量 -->
<macros> <!-- 10.0.4.181 -->
<shard>1</shard>
<replica>10.1.4.181</replica>
</macros>
<macros> <!-- 10.0.4.182 -->
<shard>1</shard>
<replica>10.1.4.182</replica>
</macros>
<macros> <!-- 10.0.4.183 -->
<shard>2</shard>
<replica>10.1.4.183</replica>
</macros>
<macros> <!-- 10.0.4.184 -->
<shard>2</shard>
<replica>10.1.4.184</replica>
</macros>
<macros> <!-- 10.0.4.185 -->
<shard>3</shard>
<replica>10.1.4.185</replica>
</macros>
<macros> <!-- 10.0.4.186 -->
<shard>3</shard>
<replica>10.1.4.186</replica>
</macros>
```
## 启动 ClickHouse
- 在每台 ClickHouse 服务器上执行如下操作
- 启动 clickhouse-server 服务
```bash
systemctl start clickhouse-server
```
# 查看集群状态
- 在任一 ClickHouse 服务器上执行如下操作
- 查询 system.cluster 表
```sql
SELECT * FROM system.clusters;
```
# 简单使用
- 在任意节点上登陆 clickhouse
```bash
clickhouse-client -h 127.0.0.1
```
- 创建数据库
```sql
CREATE DATABASE db1 ON CLUSTER cluser_3s2r;
USE db1;
```
- 创建数据表
```sql
CREATE TABLE db1.t1_local
ON CLUSTER cluster_3s2r (
col1 UInt32,
col2 String
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/t1_local', '{replica}')
ORDER BY (col1)
SETTINGS STORAGE_POLICY='policy_jbod';
```
- 创建数据表对应的分布式代理表
```sql
CREATE TABLE db1.t1
ON CLUSTER cluster_3s2r
AS db1.t1_local
ENGINE = Distributed(cluster_3s2r, db1, t1_local, rand());
```
- 通过分布式代理表写入和查询数据
```sql
INSERT INTO db1.t1 values(1,'aa');
SELECT * FROM db1.t1;
```

27
content/post/ch-join.md Normal file
View File

@ -0,0 +1,27 @@
---
title: "ClickHouse 表引擎之 Join"
date: 2020-10-08T17:40:00+08:00
lastmod: 2020-10-08T17:40:00+08:00
tags: []
categories: ["clickhouse"]
---
# Join 表引擎简介
- 数据先写内存,再同步到磁盘,服务重启后全量加载到内存
- 与 Set 表引擎共用大部分处理逻辑
- 简单封装了一层 JOIN 查询,主要用做 JOIN 查询
# 创建 Join 引擎表
- 声明
```sql
ENGINE = Join(join_strictness, join_type, key1[, key2, ...])
```
- join_strictness: 连接精度,支持 ALL、ANY 和 ASOF
- join_type: 连接类型,支持 INNRE、OUTER、CROSS
- key1, key2 ...: 连接键,关联字段
- 如果连接精度是 ANY写入数据时会忽略连接键相同的数据
# 参考
- [ClickHouse 表引擎之 Join](/post/ch-search/#JOIN)

73
content/post/ch-kafka.md Normal file
View File

@ -0,0 +1,73 @@
---
title: "ClickHouse 表引擎之 Kafka"
date: 2020-10-08T10:42:00+08:00
lastmod: 2020-10-08T10:42:00+08:00
tags: []
categories: ["clickhouse"]
---
# Kafka 表引擎简介
- 对接 Kafka 系统,订阅 Kafka 主题,接收消息
# 创建 Kafka 引擎表
- 声明
```sql
ENGINE = Kafka()
SETTINGS
kafka_broker_list = 'host:port, ...',
kafka_topic_list = 'topic1, topic2, ...',
kafka_group_name = 'consumer_group_name',
kafka_format = 'data_format',
[kafka_row_delimiter = 'delimiter_symbol',]
[kafka_schema = '',]
[kafka_num_consumers = N,]
[kafka_skip_broken_messages = N,]
[kafka_commit_every_batch =N];
```
- kafka_broker_list: kafka 节点地址列表,用逗号分隔
- kafka_topic_list: 订阅的主题列表,用逗号分隔
- kafka_group_name: 消费组名称,引擎会依据此名称创建消费组
- kafka_format: 消息格式,如 TSV、JSONEachRow、CSV 等
- kafka_row_delimiter: 一行数据的结束符,默认 '\0'
- kafka_schema: kafka schema 参数
- kafka_num_consumers: 消费者数量,默认 1
- kafka_skip_broken_messages: 允许跳过的错误消息数量默认0
- kafka_commit_every_batch: kafka commit 频率,默认 0即整个 Block 完全写入后才 commit
# Kafka 表引擎其他参数
- stream_poll_timeout_ms: 默认每 500ms 消费一次数据,写入缓存
- 刷新缓存触发条件:
- 一个数据块(kafka_max_block_size默认 65536)写入完成
- 等待 7500 毫秒(stream_flush_interval_ms)
- config.xml 中的 librdkafka 配置,参考 [https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md)
```xml
<kafka>
<auto_offset_reset>smallest</auto_offset_reset>
</kafka>
```
# Kafka 引擎表一般用法
- 创建 Kafka 引擎表,充当数据管道
- 创建 MergeTree 引擎表,用于查询
- 创建物化视图,同步 kafka 数据到 MergeTree 引擎表
```sql
CREATE MATERIALIZED VIEW kafka_view TO mergetree_table
AS SELECT col1, col2, ... FROM kafka_table;
```
- 要停止数据同步,可以删除视图,也可以卸载视图
```sql
-- 删除
DROP TABLE kafka_view;
-- 卸载
DETACH TABLE kafka_view;
```
- 恢复数据同步,装载视图
```sql
ATTACH MATERIALIZED VIEW kafka_view TO mergetree_table
AS SELECT col1, col2, ... FROM kafka_table;
```

View File

@ -0,0 +1,26 @@
---
title: "ClickHouse 视图之 Live View"
date: 2020-10-08T19:05:00+08:00
lastmod: 2020-10-08T19:05:00+08:00
tags: []
categories: ["clickhouse"]
---
# Live View 视图简介
- 类似时间监听器
- 需设置 allow_experimental_live_view 为 1检查
```sql
SELECT name, value FROM system.settings WHERE name LIKE '%live_view%';
```
# 创建 Live View 视图
- 创建
```sql
CREATE LIVE VIEW lv_name AS SELECT count(*) FROM table_name;
```
- 监听
```sql
WATCH lv_name
```

36
content/post/ch-log.md Normal file
View File

@ -0,0 +1,36 @@
---
title: "ClickHouse 表引擎之日志"
date: 2020-10-08T18:23:00+08:00
lastmod: 2020-10-08T18:23:00+08:00
tags: []
categories: ["clickhouse"]
---
# 日志表引擎简介
- 数据量 100 万行一下,一次写入多次查询
- 不支持索引、分区、并发读写
# TinyLog 表引擎
- 数据文件按列存储
- 无标记文件,不支持并行读取
- 声明
```sql
ENGINE = TinyLog()
```
# StripeLog 表引擎
- 只用数据写入一个文件
- 有数据标记文件,可并行读取
- 声明
```sql
ENGINE = StripeLog()
```
# Log 表引擎
- 数据文件按列存储
- 有数据标记文件,可并行读取
- 声明
```sql
ENGINE = Log()
```

19
content/post/ch-memory.md Normal file
View File

@ -0,0 +1,19 @@
---
title: "ClickHouse 表引擎之 Memory"
date: 2020-10-08T13:00:00+08:00
lastmod: 2020-10-08T13:00:00+08:00
tags: []
categories: ["clickhouse"]
---
# Memory 表引擎简介
- 数据只存于内存中,无压缩,无格式转换
- 支持并行查询
- 一般用于 clickhouse 内部,作为集群间分发数据的载体
# 创建 Memory 引擎表
- 声明
```sql
ENGINE = Memory()
```

24
content/post/ch-merge.md Normal file
View File

@ -0,0 +1,24 @@
---
title: "ClickHouse 表引擎之 Merge"
date: 2020-10-08T18:35:00+08:00
lastmod: 2020-10-08T18:35:00+08:00
tags: []
categories: ["clickhouse"]
---
# Merge 表引擎简介
- 本身不存储数据,只整合其他数据表
- 不支持数据写入
- 合并异步查询的结果集
- 各异步查询的数据表需要在同一个数据库下,且表结构相同,表引擎和分区定义可不同
# 创建 Merge 表引擎
- 声明
```sql
ENGINE = Merge(database, table_name)
```
- database: 数据库名
- table_name: 数据表名,支持正则表达式
- Merge 引擎表可以使用虚拟字段 "\_table" 来查询和过滤数据表

View File

@ -0,0 +1,388 @@
---
title: "ClickHouse 表引擎之 MergeTree(合并树)"
date: 2020-10-06T19:55:00+08:00
lastmod: 2020-10-07T22:54:00+08:00
tags: []
categories: ["clickhouse"]
---
# 简介
- 支持主键索引、数据分区、数据副本、数据采样、ALTER 操作
- 扩展表引擎丰富,生产环境中大多使用该表引擎
- 数据以片段形式写入磁盘,后台定期合并片段到各分区相应片段
# 数据表
- 建表语句
```sql
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name(
...
) ENGINE = MergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...];
```
- PARTITION BY: 分区键,选填,支持单字段、多字段和表达式,默认生成一个 all 分区
- ORDER BY: 排序键,必填,支持单列和元组(包含多列)
- PRIMARY KEY: 主键,选填,默认与排序键相同,允许重复数据
- SAMPLE BY: 抽样,选填,该配置需在主键中同时声明
- SETTINGS: 其他参数,选填,示例如下
- index_granularity: 索引粒度,默认 8192通常不需要修改
- index_granularity_bytes: 每批次写入的数据大小,用于自适应索引间隔,默认 10MB0 表示无视数据大小
- enable_mixed_granularity_parts: 自适应索引间隔,默认开启
- merge_with_ttl_timeout: TTL 合并间隔时间,默认 86400(1天)
- storage_policy: 数据在硬盘上的存储策略
# 数据文件
- 目录和文件
```
table_name # 表名目录
|___ partition_1 # 分区目录
|___ checksums.txt # 校验文件,二进制,记录该分区目录中其他文件的大小和哈希值
|___ columns.txt # 列信息文件,明文,记录该分区下的列字段信息
|___ count.txt # 计数文件,明文,记录该分区总行数
|___ primary.txt # 一级索引文件,二进制,存放稀疏索引
|___ {column_name}.bin # 列数据文件,默认 LZ4 压缩
|___ {column_name}.mrk # 列标记文件,二进制,记录对应数据文件(.bin)中的数据偏移量
|___ {column_name}.mrk2 # 如果表使用了自适应索引间隔,那么对应的列字段标记文件以 .mrk2 命令
|___ partition.dat # 保存当前分区表达式的值,二进制
|___ minmax_{column_name}.idx # 保存当前分区字段对应原始数据的最小和最大值,二进制
|___ skp_idx_{column_name}.idx # 二级索引(跳数索引)文件
|___ skp_idx_{column_name}.mrk # 二级索引(跳数索引)列的标记文件
```
# 数据分区
## 分区 ID
- 单字段分区 ID 生成规则
类型 | 样例数据 | 分区表达式 | 分区 ID
---- | ---- | ---- | ----
无分区键 | - | 无 | all
整型 | 18,19,20 | PARTITION BY Age | 分区1: 18分区2: 19分区3: 20
整型 | 'A0', 'A1', 'A2' | PARTITION BY length(Code) | 分区1: 2
日期 | 2020-10-05, 2020-10-06 | PARTITION BY EventTime | 分区1: 20201005分区2: 20201006
日期 | 2020-09-25, 2020-10-06 | PARTITION BY toYYYYMM(EventTime) | 分区1: 202009分区2: 202010
其他 | 'www.colben.cn' | PARTITION BY URL | 分区1: {128 位 Hash 算法}
- 多字段(元组)分区时, 先按单字段生成对应 ID再用 "-" 拼接
## 分区目录
- 分区目录命名: PartitionID_MinBlockNum_MaxBlockNum_Level例如 202010_1_1_0
- PartitionID: 分区 ID
- MinBlockNum: 最小数据块编号,**表内全局累加**,从 1 开始
- MaxBlockNum: 最大数据块编号,**表内全局累加**,从 1 开始
- Level: 分区合并次数,从 0 开始
- 不同批次写入的数据,即使分区相同,也会存储在不同目录中
- 后台在默认 10-15 分钟后自动合并分区相同的多个目录,也可以手动执行 optimize 语句
- 合并成功后,旧分区目录被置为非激活状态,在默认 8 分钟后被后台删除
- 合并后新目录的命名规则:
- MinBlockNum: 所有合并目录中的最小 MinBlockNum
- MaxBlockNum: 所有合并目录中的最大 MaxBlockNum
- Level: 所有合并目录中的最大 Level 值并加 1
# 数据索引
- 常驻内存
- 一级索引是稀疏索引,间隔 index_granularity (默认 8192) 行数据生成一条索引记录
- 二级索引又称跳数索引,有数据的聚合信息构建而成,在 CREATE 语句中定义如下:
```sql
INDEX index_name expr TYPE index_type(...) GRANULARITY granularity
-- GRANULARITY 指定一行跳数索引聚合的数据段(index_granularity 区间)的个数
```
- 跳数索引类型
- minmax: 记录一段数据内的最小值和最大值
```sql
INDEX index_name ID TYPE minmax GRANULARITY 5
```
- set: 记录字段或表达式的无重复取值
```sql
INDEX index_name (length(ID)) TYPE set(100) GRANULARITY 5
-- 每个数据段(index_granularity 区间)内最多记录 100 条 set 索引记录
```
- ngrambf_v1: 只支持 String 和 FixedString只能提升 in、notIn、like、equals 和 notEquals 性能
```sql
INDEX index_name (ID, Code) TYPE ngrambf_v1(3, 256, 2, 0) GRANULARITY 5;
-- 3: token 长度,把数据切割成长度为 3 的短语
-- 256: 布隆过滤器大小
-- 2: 哈希函数个数
-- 0: 哈希函数随机种子
```
- tokenbf_v1: ngrambf_v1 变种,按照非 字母和数字 自动分割
```sql
INDEX index_name ID TYPE tokenbf_v1(256, 2, 0) GRANULARITY 5;
-- 注意传参时不需要指定 token 长度
```
# 数据存储
- 按列独立存储
- 默认 LZ4 压缩
- 按照 order by 排序
- 以数据压缩块形式写入 .bin 文件,规则如下:
- 单批次数据 < 64KB继续获取下一批数据
- 64KB <= 单批次数据 <= 1MB直接生成压缩数据块
- 单批次数据 > 1MB按照 1MB 大小截断并生成数据块,剩余数据继续按前面规则执行
# 数据标记
- 使用 LRU 策略缓存
- 每一行标记数据记录的是一个数据片段在 .bin 文件中的读取位置
# 数据写入
- 生成分区目录,合并分区相同的目录
- 按照 index_granularity 索引粒度,生成一级索引、二级索引、数据标记文件和数据压缩文件
# 数据查询
- 借助分区、索引、数据标记来缩小扫描范围
- 如果未指定查询条件或条件未匹配到索引MergeTree 仍可借助数据标记多线程读取压缩数据块
# 数据 TTL
## TTL 机制
- TTL 信息保存在分区目录中的 ttl.txt 中
- 支持的时间单位: SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR
- 触发 TTL 删除过期数据
- 后台分区合并
- merge_with_ttl_timeout 合并频率,默认 86400 秒
- 手动执行 OPTIMIZE 语句
- 合并分区时TTL 全部到期的数据分区不会参与合并
- 控制全局 TTL 合并任务
```sql
-- 启动
SYSTEM START TTL MERGES;
-- 停止
SYSTEM STOP TTL MERGES;
```
## 列级别 TTL
- 到达时间时,列数据被还原为对应数据类型的默认值
- 主键字段不能被声明 TTL
- 声明列级别 TTL
```sql
CREATE TABLE table_name(
id String,
create_time DateTime,
code String TTL create_time + INTERVAL 10 SECOND,
type UInt8 TTL create_time + INTERVAL 16 SECOND
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(create_time)
ORDER BY id;
```
- 修改列级别 TTL
```sql
ALTER TABLE table_name MODIFY COLUMN code String TTL create_time + INTERVAL 1 DAY;
```
## 表级别 TTL
- 到达时间时,删除过期的数据行
- 声明表级别 TTL
```sql
CREATE TABLE table_name(
id String,
create_time DateTime,
code String TTL create_time _ INTERVAL 1 MINUTE,
type UInt8
) ENGINE = MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY create_time
TTL create_time + INTERVAL 1 DAY;
```
- 修改表级别 TTL
```sql
ALTER TABLE table_name MODIFY TTL create_time + INTERVAL 3 DAY;
```
# 存储策略
- 最小移动单元是数据分区
- 三大策略: 默认、JBOD、HOT/COLD
## 默认策略
- 无需配置,所有分区自动保存至 config.xml 中的 path 目录下
## JOB 策略
- 适用于多磁盘无 RAID 场景
- INSERT 或 MERGE 产生的新分区轮询写入各磁盘,类似 RAID0
- 磁盘故障时,丢掉相应数据,需要副本机制保障数据可靠性
## HOT/COLD 策略
- 适用于已挂载不同类型磁盘的场景
- 把磁盘划分到 HOT 和 COLD 两个区域HOT 使用 SSD注重性能CODE 使用 HDD注重经济
- 单个区域内可应用 JBOD 策略
## 配置策略
- 配置示例
```xml
<storage_configuration>
<disks>
<!-- 磁盘名称,全局唯一 -->
<disk_hot_0>
<!-- 存储目录,注意 clickhouse 用户有权限读写该目录 -->
<path>/ch/ssd0</path>
<!-- 磁盘预留空间,选填 -->
<keep_free_space_bytes>1073741824</keep_free_space_bytes>
</disk_hot_0>
<disk_hot_1>
<path>/ch/ssd1<path>
</disk_hot_1>
<disk_cold_0>
<path>/ch/hdd0<path>
<keep_free_space_bytes>2147483648</keep_free_space_bytes>
</disk_cold_0>
<disk_cold_1>
<path>/ch/hdd1<path>
</disk_cold_1>
<disk_cold_2>
<path>/ch/hdd2<path>
</disk_cold_2>
</disks>
<policies>
<!-- 策略名称,全局唯一 -->
<policy_jbod_0>
<volumes>
<!-- 卷名称,全局唯一 -->
<volume_jbod_0>
<!-- 指定该卷内使用的磁盘 -->
<disk>disk_hot_0</disk>
<disk>disk_hot_1</disk>
<!-- 单个 disk 中一个分区的最大存储阈值,选填 -->
<!-- 超出阈值后,该分区的其他数据会写入下一个该卷内下一个 disk -->
<max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
</volume_jbod_0>
</volumes>
</policy_jbod_0>
<policy_hot_cold_0>
<volumes>
<volume_hot_0>
<disk>disk_hot_0</disk>
<disk>disk_hot_1</disk>
</volume_hot_0>
<volume_cold_0>
<disk>disk_cold_0</disk>
<disk>disk_cold_1</disk>
<disk>disk_cold_2</disk>
</volume_cold_0>
</volumes>
<!-- 卷可用空间因子,默认 0.1,选填 -->
<!-- 如果当前卷可用空间小于 20%,则数据会自动写入下一个卷 -->
<move_factor>0.2</move_factor>
</policy_hot_cold_0>
</policies>
</storage_configuration>
```
- clickhouse 用户需要有权限读写各存储目录
- 存储配置不支持动态更新
- 存储磁盘系统表: system.disks
- 存储策略系统表: system.storage_policies
- 移动分区到其他 disk
```sql
ALTER TABLE table_name MOVE PART 'part_name' TO DISK 'disk_name';
```
- 移动分区到其他 volume
```sql
ALTER TABLE table_name MOVE PART 'part_name' TO VOLUME 'volume_name';
```
# ReplacingMergeTree
- 依据 ORDER BY 字段去重
- 合并分区时,**以分区为单位**删除重复数据
- 声明
```sql
ENGINE = ReplacingMergeTree(version_column)
```
- version_column 选填,指定一个 UInt\*、Date 或 DateTime 字段作为版本号
- 未指定 version_column 时,保留同一组重复数据中的最后一行
- 指定 version_column 时,保留同一组重复数据中该字段取值最大的一行
# SummingMergeTree
- 场景: 用户只需要汇总结果,不关心明细
- 依据 ORDER BY 字段聚合
- 合并分区时,触发条件聚合,**以分区为单位**把同一分组下的多行数据汇总成一行
- 声明:
```sql
ENGINE = SummingMergeTree((col1,col2, ...))
```
- col1、col2 选填,不可指定主键,指定被 SUM 汇总的数值类型字段
- 未指定任何汇总字段时,默认汇总所有非主键的数值类型字段
- 非汇总字段保留同组内的第一行数据
- 汇总嵌套字段时,字段名需以 Map 为后缀,默认嵌套字段中第一列作为聚合 Key其他以 \*Key、\*Id、\*Type 未后缀名的列会和第一列组成复合 Key
# AggregatingMergeTree
- 预先计算聚合数据,二进制格式存入表中,空间换时间,可看成是 SummingMergeTree 的*升级版*
- 依据 ORDER BY 字段聚合
- 使用 AggregationFunction 字段类型定义聚合函数和字段
- 分区合并时,触发**以分区为单位**的合并计算
- 非汇总字段保留同组内的第一行数据
- 写数据时调用 \*State 函数,查询时调用 \*Merge 函数
- 一般用作物化视图的表引擎,与普通 MergeTree 搭配使用,示例如下
- 创建明细数据表,俗称底表
```sql
CREATE TABLE table_name(
id String,
city String,
code String,
value Uint32
) ENGINE = MergeTree()
PARTITION BY city
ORDER BY (id, city);
```
- 创建物化视图
```sql
CREATE MATERIALIZED VIEW view_name
ENGINE = AggregatingMergeTree()
PARTITION BY city
ORDER BY (id, city)
AS SELECT
id,
city,
uniqState(code) AS code,
sumState(value) AS value
FROM table_name
GROUP BY id, city;
```
- 使用常规 SQL 面向底表增加数据
- 面向物化视图查询
```sql
SELECT id, sumMerge(value), uniqMerge(code) FROM agg_view GROUP BY id,city;
```
# CollapsingMergeTree
- 以增代删
- 声明
```sql
ENGINE = CollapsingMergeTree(sign)
```
- 定义 sign 标记字段Int8 类型1 代表有效,-1 代表无效
- 依据 ORDER BY 字段作为数据唯一性依据
- 规则
- 如果 sign=1 比 sign=-1 多一行,则保留最后一行 sign=1 的数据
- 如果 sign=-1 比 sign=1 多一行,则保留第一行 sign=-1 的数据
- 如果 sign=-1 和 sign=1 一样多,且最后一行是 sign=1则保留第一行 sign=-1 和最后一行 sign=1 的数据
- 如果 sign=-1 和 sign=1 一样多,且最后一行是 sign=-1则不保留任何数据
- 其他情况打印告警日志
- 合并分区时,触发**以分区为单位**的数据折叠
- 严格要求数据写入顺序,只有先写入 sign=1再写入 sign=-1才能正常折叠
# VersionedCollapsingMergeTree
- 与 CollapsingMergeTree 类似,但对数据写入顺序没有要求
- 声明
```sql
ENGINE = VersionedCollapsingMergeTree(sign, ver)
```
- ver 是 UInt8 类型的版本号字段
- 每个分区内的数据都以 ORDER BY column_name, ver DESC 排序

41
content/post/ch-mysql.md Normal file
View File

@ -0,0 +1,41 @@
---
title: "ClickHouse 表引擎之 MySQL"
date: 2020-10-08T10:15:00+08:00
lastmod: 2020-10-08T10:15:00+08:00
tags: []
categories: ["clickhouse"]
---
# MySQL 表引擎简介
- 可以与 MySQL 数据库中的表建立映射
- 只支持 SELECT 和 INSERT不支持 UPDATE 和 DELETE
# 创建 MySQL 引擎表
- 声明
```sql
ENGINE = MySQL(
'host:port',
'database',
'table',
'user',
'password'
[,
replace_query,
'on_duplicate_clause'
]
)
```
- host:port: mysql 的地址和端口
- database: mysql 数据库名
- table: mysql 表名
- user: mysql 用户名
- password: mysql 密码
- replace_query: 对应 mysql 的 replace into 语法,默认 0不启用
- on_duplicate_clause: 对应 mysql 的 on duplicate key 语法,默认空,如果要使用,需设置 replace_query 为 0
# MySQL 引擎表一般用法
- 在 mysql 中建表
- 在 clickhouse 中创建对应的 MySQL 引擎表
- 在 clickhouse 中创建 MergeTree 引擎的物化视图,从 MySQL 引擎表中读取数据

18
content/post/ch-null.md Normal file
View File

@ -0,0 +1,18 @@
---
title: "ClickHouse 表引擎之 Null"
date: 2020-10-08T19:11:00+08:00
lastmod: 2020-10-08T19:11:00+08:00
tags: []
categories: ["clickhouse"]
---
# Null 表引擎简介
- 类似 /dev/null忽略写入的任何数据查询时返回空表
- 如果物化视图不需要保留源表数据,则可设置源表为 Null 引擎
# 创建 Null 表引擎
- 声明
```sql
ENGINE = Null
```

26
content/post/ch-ops.md Normal file
View File

@ -0,0 +1,26 @@
---
title: "ClickHouse 维护"
date: 2020-10-10T01:30:00+08:00
lastmod: 2020-10-10T01:30:00+08:00
tags: []
categories: ["clickhouse"]
---
# 指标
- system.metrics: 正在执行的概要信息,如正在运行的查询和操作数量
- system.events: 累积概要信息,如总的查询次数或 SELECT 次数
- system.asynchronous_metrics: 后台异步运行的概要信息,如分配内存、队列中的人物数量
# 日志
- system.query: 执行用户、查询语句、执行时间、返回数据量等信息
```xml
<query_log>
...
<query_log>
```
- query_thread_log: 查询语句、执行线程、执行时间、内存使用量
- part_log: MergeTree 系列表引擎的操作类型、表名称、分区信息、执行时间
- text_log: 记录 clickhouse 运行时的终端输出日志
- metric_log: 汇聚 system.metrics 和 system.events

View File

@ -0,0 +1,181 @@
---
title: "ClickHouse 集群"
date: 2020-10-09T22:14:00+08:00
lastmod: 2020-10-09T22:14:00+08:00
tags: []
categories: ["clickhouse"]
---
# 简介
- 一个集群包含多个逻辑分片,每个逻辑分片包含多个副本节点
- 向集群内读写数据时,需依赖 Distributed 引擎表做为代理,实现数据的分发、写入、查询和路由
- ReplicatedMerge 表引擎配合 zookeeper 实现数据的复制
# 集群配置
- 节点分配
```xml
<remote_servers>
<cluster_3s2r> <!-- 集群名称 -->
<shard> <!-- 分片配置 -->
<internal_replication>true</internal_replication> <!-- 使用 ReplicatedMergeTree 引擎复制数据 -->
<weight>1<weight> <!-- 分片权重 -->
<replica>
<host>10.1.4.181</host> <!-- 副本节点的域名/IP -->
<port>9000</port> <!-- 副本节点的端口 -->
</replica>
<replica>
<host>10.1.4.182</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>10.1.4.183</host>
<port>9000</port>
</replica>
<replica>
<host>10.1.4.184</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>10.1.4.185</host>
<port>9000</port>
</replica>
<replica>
<host>10.1.4.186</host>
<port>9000</port>
</replica>
</shard>
</cluster_3s2r>
</remote_servers>
```
- 各节点的宏变量
- 10.0.4.181
```xml
<macros>
<shard>1</shard>
<replica>10.1.4.181</replica>
</macros>
```
- 10.0.4.182
```xml
<macros>
<shard>1</shard>
<replica>10.1.4.182</replica>
</macros>
```
- 10.0.4.183
```xml
<macros>
<shard>2</shard>
<replica>10.1.4.183</replica>
</macros>
```
- 10.0.4.184
```xml
<macros>
<shard>2</shard>
<replica>10.1.4.184</replica>
</macros>
```
- 10.0.4.185
```xml
<macros>
<shard>3</shard>
<replica>10.1.4.185</replica>
</macros>
```
- 10.0.4.186
```xml
<macros>
<shard>3</shard>
<replica>10.1.4.186</replica>
</macros>
```
- Zookeeper
```xml
<zookeeper>
<node index="1">
<host>10.0.4.101</host>
<port>2181</port>
</node>
<node index="2">
<host>10.0.4.102</host>
<port>2181</port>
</node>
<node index="3">
<host>10.0.4.103</host>
<port>2181</port>
</node>
</zookeeper>
```
- system.zookeeper: zookeeper 代理表,可通过 sql 查看 zookeeper 信息
- system.clusters: 集群信息表
# ReplicatedMergeTree 表引擎
- 引入 zookeeper 实现分布式协同zookeeper 本身不涉及表数据传输
- 副本节点是多主架构,可在节点上执行读写操作
- 数据块: 默认 1048576 行(max_insert_block_size)
- 基本基本写入单元
- 原子性: 一个块内的数据,要么都写入成功,要么都失败
- 唯一性: 记录 hash 信息,相同的数据块会被忽略
## 创建 ReplicatedMergeTree 引擎表
- 声明
```sql
CREATE TABLE table_name_local ON CLUSTER cluster_name_2
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/db_name/table_name_local',
'{replica}'
)
```
- table_name_local: 本地表名,推荐以 \_local 为后缀
- cluster_name_2: 在该集群内创建数据库和数据表的分片和副本
- /clickhouse/tables/ 是约定俗成的固定 zookeeper path 路径
- {shard}: 分片编号,从各自节点的宏变量中获取
- db_name: 数据库名
- {replica}: 节点域名/IP从各自节点的宏变量中获取
# Distributed 表引擎
- 又叫分布式表,自身不存储数据,只代理数据分片
## 创建 Distributed 引擎表
- 声明
```sql
CREATE TABLE table_name_all ON CLUSTER cluster_name_1
ENGINE = Distributed(cluster_name_2, db, table, [,sharding_key])
```
- table_name_all: 分布式表名,通常以 \_all 为后缀
- ON CLUSTER: 集群操作
- cluster_name_1: 在该集群内创建分布式表 table_name_all
- cluster_name_2: 数据的分片和副本所在集群
- db: 数据库名
- table_name_local: 数据表名,即前面创建的 ReplicatedMergeTree 引擎表,通常以 \_local 为后缀
- sharding_key: 分片键,可以是整型列字段或返回整型的表达式,决定数据分配到哪些节点中
# 分布式查询
- 分布式表(Distributed)把查询转换为并行的各分片查询
- 汇总各分片的查询结果
## GlOBAL 优化查询
- 场景: 涉及到 JOIN 和 IN 时,可能会放大分布式查询
- GLOBAL 查询过程:
- 提出 IN 子句,发起分布式查询
- 汇总 IN 子句在各分片的查询结果,存入临时表(内存)
- 把这个临时表发送到其他分片节点,**考虑到该表既要内存存储,又要通过网络分发,所以数据量不宜过大**
- 在各分片节点执行完整的 SQL 语句,此时 IN 子句直接使用上一步的临时表
- 使用示例
```sql
SELECT ... WHERE ... AND ... GLOBAL IN (...)
```

192
content/post/ch-search.md Normal file
View File

@ -0,0 +1,192 @@
---
title: "ClickHouse 数据查询"
date: 2020-10-08T19:27:00+08:00
lastmod: 2020-10-08T22:17:00+08:00
tags: []
categories: ["clickhouse"]
---
# 查询注意
- **避免使用 SELECT * 查询**
# WITH
- **WITH 子句只能返回一行数据**
- 定义变量
```sql
WITH 10 AS var_name SELECT ...
```
- 调用函数
```sql
WITH SUM(column_name) AS with_name SELECT ...
```
- 定义子查询
```sql
WITH (
SELECT ...
) AS with_name
SELECt ...
```
- WITH 子句可在子查询中嵌套使用
# FROM
- 支持表、表函数和子查询
- 可用 FINAL 修饰以强制合并,会降低性能,应尽量避免使用
# SAMPLE
- 返回采样数据,减少查询负载,适用于近似查询
- 只能用于 MergeTree 系列引擎表,且声明了 SAMPLE BY 抽样表达式
- 虚拟字段 \_sample_factor 是采样系数
- 不采样
```sql
SELECT ... SAMPLE 0
-- 或
SELECT ... SAMPLE 1
```
- SAMPLE factorfactor 是采样因子,取值 0~1
```sql
SELECT ... SAMPLE 0.1
-- 或者
SELECT ... SAMPLE 1/10
```
- SAMPLE rows采样**近似**行数,必须大于 1
```sql
SELECT ... SAMPLE 10000
```
- SAMPLE factor OFFSET n偏移 n\*100% 的数据量后才开始按 factor 因子采样,取值都在 0~1
```sql
SELECT ... SAMPLE 0.4 OFFSET 0.5
```
# ARRAY JOIN
- 允许在数据表内部,与数组或嵌套字段进行 JOIN 操作,操作时把数组或嵌套字段拆成多行
- 支持 INNER 和 LEFT默认 INNER
```sql
SELECT ... FROM table_name ARRAY JOIN column_name AS alias_name
SELECT ... FROM table_name LEFT ARRAY JOIN column_name AS alias_name
```
# JOIN
## 连接精度
- ALL: 默认,左表的每行数据,在右表中有多行连接匹配,返回右表全部连接数据
- ANY: 左表的每行数据,在右表中有多行连接匹配,返回右表第一行连接数据
- ASOF: 增加模糊连接条件,对应字段必须是整数、浮点数和日期这类有序数据类型
```sql
SELECT ... FROM table_a ASOF INNER JOIN table_b USING(key_1, key_2)
-- key_1 字段是 join keykey_2 是模糊连接条件字段
```
## 连接类型
- INNER: 内连接,返回交集部分
- OUTER: 外链接
- LEFT: 左表数据全部返回,右表匹配则返回,不匹配则填充相应字段的默认值
- RIGHT: 与 LEFT 相反
- FULL: 先 LEFT右表剩下的数据再 RIGHT
- CROSS: 交叉连接,返回笛卡儿积
## JOIN 查询优化
- 左大右小,小表放右侧,右表会被加载到内存中
- JOIN 查询无缓存,应用可考虑实现查询缓存
- 大量维度属性补全时,建议使用字典表代替 JOIN 查询
- USING 语法简写
```sql
SELECT ... FROM table_1 INNTER JOIN table_2 USING key_1
```
# PREWHERE
- 只能用于 MergeTree 系列表引擎
- 与 WHERE 不同之处:
- 只读取 PREWHERE 指定的列字段,条件过滤
- 根据过滤好的数据再读取 SELECT 指定的列字段
- clickhouse 会在合适条件下自动把 WHERE 替换成 PREWHERE
# GROUP BY
- WITH ROLLUP按聚合键从右向左上卷数据基于聚合函数依次生成分组小计和总计
```sql
SELECT table, name, SUM(bytes_on_disk) FROM system.parts
GROUP BY table,name
WITH ROLLUP
ORDER BY table
```
- WITH CUBE基于聚合键之间的所有组合生成小计信息
```sql
SELECT ...
GROUP BY key1,key2,key3, ...
WITH CUBE
...
```
- WITH TOTALS常规聚合完成后增加一行对所有数据的汇总统计
```sql
SELECT ...
GROUP BY key1
WITH TOTALS
...
```
# HAVING
- 必须与 GROUP BY 配合使用,把聚合结果二次过滤
```sql
SELECT ... GROUP BY ... HAVING ...
```
# ORDER BY
- 默认 ASC(升序)
- NULLS LAST默认其他值 -> NaN -> NULL
- NULLS FIRSTNULL -> NaN -> 其他值
# LIMIT BY
- 返回指定分组的最多前 n 行数据
```sql
LIMIT n BY key1,key2 ...
```
- 支持 OFFSET
```sql
LIMIT n OFFSET m BY key1,key2 ...
-- 简写
LIMIT m,n BY key1,key2 ...
```
# LIMIT
- 返回指定的前 n 行数据
```sql
LIMIT n
LIMIT n OFFSET m
LIMIT m,n
```
- 推荐搭配 ORDER BY保证全局顺序
# SELECT
- 查询正则匹配的列字段
```sql
SELECT COLUMNS('^n'), COLUMNS('p') FROM system.databases
```
# DISTINCT
- 去重
- 先 DISTINCT 后 ORDER BY
# UNION ALL
- 联合左右两边的子查询,一并返回结果,可多次声明使用联合多组查询
```sql
SELECT c1, c2 FROM t1 UNION ALL SELECT c3, c4 FROM t2
```
- 两边列字段数量必须一样,类型兼容,查询结果列名以左侧为准
# SQL 执行计划
- 设置日志到 DEBUG 或 TRACE 级别,可查看 SQL 执行日志
- SQL 需真正执行后才有日志,如果查询量大,推荐 LIMIT
- **不要用 SELECT * 查询**
- 尽可能利用索引,避免全表扫描

27
content/post/ch-set.md Normal file
View File

@ -0,0 +1,27 @@
---
title: "ClickHouse 表引擎之 Set"
date: 2020-10-08T17:04:00+08:00
lastmod: 2020-10-08T17:04:00+08:00
tags: []
categories: ["clickhouse"]
---
# Set 表引擎简介
- 数据先写内存,再同步到磁盘,服务重启后全量加载到内存
- 支持 INSERT写入时重复数据被忽略
- 不能直接 SELECT只能作为 IN 查询的右侧条件
# 创建 Set 引擎表
- 声明
```sql
ENGINE = Set()
```
# 使用
- 创建 Set 引擎表
- INSERT 写入数据
- 查询
```sql
SELECT arrayJoin([1,2,3]) AS a WHERE a IN set_table;
```

22
content/post/ch-url.md Normal file
View File

@ -0,0 +1,22 @@
---
title: "ClickHouse 表引擎之 URL"
date: 2020-10-08T19:16:00+08:00
lastmod: 2020-10-08T19:16:00+08:00
tags: []
categories: ["clickhouse"]
---
# URL 表引擎简介
- http 客户端,支持 http 和 https 协议
- SELECT 转换成 GET 请求
- INSERT 转换成 POST 请求
# 创建 URL 表引擎
- 声明
```sql
ENGINE = URL('url', format)
```
- url: 请求远端服务的 url
- format: TSV、CSV、JSONEachRow

View File

@ -0,0 +1,260 @@
---
title: "CentOS7 安装 Cloudera Manager"
date: 2020-08-16T13:48:37+08:00
lastmod: 2020-08-16T18:27:00+08:00
keywords: []
tags: [cloudera cdh]
categories: ["hadoop"]
---
# 环境
角色 | IP | 主机名 | 服务
---- | ---- | ---- | ----
Utility | 192.168.1.100 | cm0.colben.cn | ClouderaManager<br>ClouderaManagerManagementService<br>HiveMetastore
Gateway | 192.168.1.101 | gw0.colben.cn | GatewayConfiguration<br>HiveServer2<br>Zookeeper
Master | 192.168.1.102 | m0.colben.cn | NameNode<br>JournalNode<br>FailoverController<br>YarnResourceManager<br>Zookeeper
Master | 192.168.1.103 | m1.colben.cn | NameNode<br>JournalNode<br>FailoverController<br>YarnResourceManager<br>Zookeeper
Worker | 192.168.1.104 | w0.colben.cn | DataNode<br>NodeManager
Worker | 192.168.1.105 | w0.colben.cn | DataNode<br>NodeManager
Worker | 192.168.1.106 | w0.colben.cn | DataNode<br>NodeManager
# 配置 ssh 免密登陆
- 在 cm0 上配置 ssh 可免密登陆全部服务器
```
ssh-keygen
seq -f'192.168.1.%g' 100 106 | xargs -L1 ssh-copy-id
```
- 这里的**私钥会在后面通过界面增加主机时用到**
# 关闭防火墙和 selinux
- 在全部服务器上关闭防火墙
```
systemctl stop firewalld
systemctl disable firewalld
```
- 在全部服务器上关闭 selinux
```
setenforce 0
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
```
# 配置网络名称
- 在全部服务器上修改 /etc/hosts增加如下解析记录
```
192.168.1.100 cm0.colben.cn cm0
192.168.1.101 gw0.colben.cn gw0
192.168.1.102 m0.colben.cn m0
192.168.1.103 m1.colben.cn m1
192.168.1.104 w0.colben.cn w0
192.168.1.105 w1.colben.cn w1
192.168.1.106 w2.colben.cn w2
```
- 在全部服务器上修改 /etc/sysconfig/network增加各自主机名设置
```
HOSTNAME=XXXX.colben.cn
```
- 在全部服务器上设置各自主机名
```
hostnamectl set-hostname XXXX.colben.cn
```
# 配置时间同步
- 在 cm0 上配置修改 /etc/chrony.conf
```
server ntp.aliyun.com iburst
allow 192.168.1.0/24
```
- 在其他服务器上修改 /etc/chrony.conf
```
server cm0.colben.cn iburst
```
- 在全部服务器上重启 chronyd 服务
```
systemctl restart chronyd
```
# 配置 cloudera manager 内网安装源
- 在 cm0 上安装并启动 httpd 服务
```
yum install httpd
systemctl enable httpd
systemctl start httpd
```
- 在 cm0 上下载 cloudera manager yum 仓库
```
mkdir -p /var/www/html/cloudera-repos/cm6/6.3.1
wget https://archive.cloudera.com/cm6/6.3.1/repo-as-tarball/cm6.3.1-redhat7.tar.gz
tar zxf cm6.3.1-redhat7.tar.gz -C /var/www/html/cloudera-repos/cm6/6.3.1 --strip-components=1
chmod -R ugo+rX /var/www/html/cloudera-repos/cm6
```
- 在 cm0 上下载 cdh yum 仓库(**体积较小,需手动升级**)
```
mkdir -p /var/www/html/cloudera-repos
wget --recursive --no-parent --no-host-directories \
https://archive.cloudera.com/cdh6/6.3.2/redhat7/ -P /var/www/html/cloudera-repos
wget --recursive --no-parent --no-host-directories \
https://archive.cloudera.com/gplextras6/6.3.2/redhat7/ -P /var/www/html/cloudera-repos
chmod -R ugo+rX /var/www/html/cloudera-repos/cdh6
chmod -R ugo+rX /var/www/html/cloudera-repos/gplextras6
```
- 在 cm0 上下载 cdh parcel 仓库(**体积较大,可通过界面操作自动升级**)
```
mkdir -p /var/www/html/cloudera-repos
wget --recursive --no-parent --no-host-directories \
https://archive.cloudera.com/cdh6/6.3.2/parcels/ -P /var/www/html/cloudera-repos
wget --recursive --no-parent --no-host-directories \
https://archive.cloudera.com/gplextras6/6.3.2/parcels/ -P /var/www/html/cloudera-repos
chmod -R ugo+rX /var/www/html/cloudera-repos/cdh6
chmod -R ugo+rX /var/www/html/cloudera-repos/gplextras6
```
- 在 cm0 上创建 cloudera.repo并重建 yum 缓存
```
cat > /etc/yum.repos.d/cloudera.repo <<-EOF
[cloudera-manager]
name=cloudera-manager
baseurl=http://cm0.colben.cn/cloudera-repos/cm6/
enabled=1
gpgcheck=0
EOF
yum clean all
yum makecache fast
```
- 通过界面增加其他主机时cloudera manager 会自动部署该 repo 文件
# 安装 jdk
- 在 cm0 上安装 jdk
```
yum install oracle-j2sdk1.8
```
- 通过界面增加其他主机时,可自动安装 oracle-j2sdk1.8
# 安装 cloudera manager
- 在 cm0 上安装 cloudera-manager
```
yum install cloudera-manager-daemons cloudera-manager-agent cloudera-manager-server
```
# 配置 cloudera manager 数据库
- 在 cm0 上安装 mysql[参考这里](/post/mysql5.7-install/)
- 官方推荐 my.cnf
```
[mysqld]
transaction-isolation = READ-COMMITTED
symbolic-links = 0
sql_mode=STRICT_ALL_TABLES
key_buffer_size = 32M
max_allowed_packet = 32M
thread_stack = 256K
thread_cache_size = 64
query_cache_limit = 8M
query_cache_size = 64M
query_cache_type = 1
max_connections = 600
log_bin=/var/lib/mysql/mysql_binary_log
server_id=1
binlog_format = mixed
read_buffer_size = 2M
read_rnd_buffer_size = 16M
sort_buffer_size = 8M
join_buffer_size = 8M
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 64M
innodb_buffer_pool_size = 4G
innodb_thread_concurrency = 8
innodb_flush_method = O_DIRECT
innodb_log_file_size = 512M
```
- 在 cm0 上启动 mysql
```
systemctl enable mysqld
systemctl start mysqld
```
- 在 cm0 上的 mysql 中创建数据库和用户
```
CREATE DATABASE scm DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE amon DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE rman DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE hue DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE metastore DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE sentry DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE nav DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE navms DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE DATABASE oozie DEFAULT CHARSET utf8 DEFAULT COLLATE utf8_general_ci;
GRANT ALL ON scm.* to scm@'%' identified by 'Pass-1234';
GRANT ALL ON amon.* to amon@'%' identified by 'Pass-1234';
GRANT ALL ON rman.* to rman@'%' identified by 'Pass-1234';
GRANT ALL ON hue.* to hue@'%' identified by 'Pass-1234';
GRANT ALL ON metastore.* to hive@'%' identified by 'Pass-1234';
GRANT ALL ON sentry.* to sentry@'%' identified by 'Pass-1234';
GRANT ALL ON nav.* to nav@'%' identified by 'Pass-1234';
GRANT ALL ON navms.* to navms@'%' identified by 'Pass-1234';
GRANT ALL ON oozie.* to oozie@'%' identified by 'Pass-1234';
```
- 在 cm0 上初始化数据库
```
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql scm scm
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql amon amon
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql rman rman
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql hue hue
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql metastore hive
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql sentry sentry
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql nav nav
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql navms navms
/opt/cloudera/cm/schema/scm_prepare_database.sh mysql oozie oozie
```
- 在全部服务器上安装 mysql connector
```
wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.46.tar.gz
tar zxvf mysql-connector-java-5.1.46.tar.gz
mkdir -p /usr/share/java/
cp mysql-connector-java-5.1.46/mysql-connector-java-5.1.46-bin.jar \
/usr/share/java/mysql-connector-java.jar
```
# 启动 cloudera manager
- 在 cm0 上启动 cloudera manager
```
systemctl start cloudera-scm-server
```
- 日志: /var/log/cloudera-scm-server/cloudera-scm-server.log
- 日志出现如下信息,表示 cloudera-scm-server 启动完成
```
INFO WebServerImpl:com.cloudera.server.cmf.WebServerImpl: Started Jetty server.
```
- 浏览器访问
- 地址: http://cm0.colben.cn:7180/
- 用户: admin
- 密码: admin

280
content/post/configmap.md Normal file
View File

@ -0,0 +1,280 @@
---
title: "ConfigMap 笔记"
date: 2019-12-22T22:04:37+08:00
lastmod: 2019-12-22T22:04:37+08:00
tags: ["kubernetes", "configmap"]
categories: ["container"]
---
# 概述
- ConfigMap 通常用于设置环境变量、设置命令行参数、创建配置文件
- Pod 使用 ConfigMap 前ConfigMap 必须存在,否则 pod 不能启动
- ConfigMap 只能被在同一一个命名空间中的Pod所引用
# 创建 ConfigMap
- 命令如下
```bash
kubectl create configmap <map-name> <data-source>
# 或者
kubectl apply -f <configmap-file.yml>
```
- map-name: ConfigMap 名称
- data-source: 目录、文件或具体值
## 通过目录创建 ConfigMaps
- 命令如下
```bash
kubectl create configmap game-config \
--from-file=https://k8s.io/docs/tasks/configure-pod-container/configmap/kubectl
```
- docs/tasks/configure-pod-container/configmap/kubectl/目录下的文件包括
```bash
ls docs/tasks/configure-pod-container/configmap/kubectl/
```
- 输出如下
```
game.properties
ui.properties
```
- 查看 game-config 信息
```bash
kubectl describe configmaps game-config
# 或者
kubectl get configmaps game-config -o yaml
```
## 通过文件创建 ConfigMaps
- 通过单个文件创建
```bash
kubectl create configmap game-config-2 \
--from-file=https://k8s.io/docs/tasks/configure-pod-container/configmap/kubectl/game.properties
```
- 通过多个文件创建
```bash
kubectl create configmap game-config-3 \
--from-file=https://k8s.io/docs/tasks/configure-pod-container/configmap/kubectl/game.properties \
--from-file=https://k8s.io/docs/tasks/configure-pod-container/configmap/kubectl/ui.properties
```
- 通过文件创建ConfigMap时可以定义文件的键
```bash
kubectl create configmap game-config-4 \
--from-file=game-special-key=https://k8s.io/docs/tasks/configure-pod-container/configmap/kubectl/game.properties
# key 是 "game-special-key"
# value 是 game.properties 文件的内容
```
## 通过具体值创建 ConfigMaps
- 使用 --from-literal 参数定义具体值
```bash
kubectl create configmap special-config \
--from-literal=special.how=very \
--from-literal=special.type=charm
```
# 使用 ConfigMap
## 定义 pod 环境变量
### Pod 环境变量的值来自于单一 ConfigMap
- 在ConfigMap中定义一个环境变量作为键值对
```bash
kubectl create configmap special-config --from-literal=special.how=very
```
- 指派ConfigMap中定义的special.how的值给Pod中SPECIAL_LEVEL_KEY环境变量
```yaml
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image:k8s.gcr.io/busybox
command:["/bin/sh","-c","env"]
env:
# Define the environment variable
- name:SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
name:special-config
# Specify the key associated with the value
key:special.how
restartPolicy:Never
```
- 保存Pod规格的变化Pod将输出SPECIAL_LEVEL_KEY=very
### Pod 环境变量的值来自于多个 ConfigMap
- 创建两个 ConfigMap
```yaml
---
apiVersion:v1
kind:ConfigMap
metadata:
name:special-config
namespace:default
data:
special.how:very
---
apiVersion:v1
kind:ConfigMap
metadata:
name:env-config
namespace:default
data:
log_level:INFO
```
- 在Pod规格中定义环境变量
```yaml
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image:k8s.gcr.io/busybox
command:["/bin/sh","-c","env"]
env:
- name:SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:special.how
- name:LOG_LEVEL
valueFrom:
configMapKeyRef:
name:env-config
key:log_level
restartPolicy:Neverv
```
- 保存变更后的PodPod将会输出SPECIAL_LEVEL_KEY=very和LOG_LEVEL=info
## 在一个ConfigMap中配置的键值对都作为一个Pod的环境变量
- **Kubernetes v1.6+可用**
- 创建包含多个键-值对的ConfigMap
```yaml
apiVersion:v1
kind:ConfigMap
metadata:
name:special-config
namespace:default
data:
SPECIAL_LEVEL:very
SPECIAL_TYPE:charm
```
- 使用envFrom定义所有的ConfigMap数据作为Pod的环境变量。来自于Config的键成为Pod中环境变量的名
```yaml
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image:k8s.gcr.io/busybox
command:["/bin/sh","-c","env"]
envFrom:
- configMapRef:
name:special-config
restartPolicy:Never
```
- Pod的输出包括: SPECIAL_LEVEL=very 和 SPECIAL_TYPE=charm
## 在Pod命令行中使用ConfigMap定义的环境变量
- 在Pod规范的command 中使用$(VAR_NAME) 获取ConfigMap定义的环境变量
```yaml
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image:k8s.gcr.io/busybox
command:["/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)"]
env:
- name:SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:SPECIAL_LEVEL
- name:SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name:special-config
key:SPECIAL_TYPE
restartPolicy:Never
```
- test-container容器的输出: very charm
# 添加ConfigMap数据至存储卷
- 当通过from-file创建的ConfigMap时文件将作为一个键保存在ConfigMap中而此文件的内容将作为值
```bash
apiVersion:v1
kind:ConfigMap
metadata:
name:special-config
namespace:default
data:
special.level:very
special.type:charm
```
## 将ConfigMap中的数据传播到指定目录
- 在Pod的存储卷区域添加ConfigMap的名称
- 这将添加ConfigMap数据到volumeMounts.mountPath指定的目录下(此例为/etc/config)
- command区域将引用保存在ConfigMap中的special.level条目
```bash
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image:k8s.gcr.io/busybox
command:["/bin/sh","-c","ls /etc/config/"]
volumeMounts:
- name:config-volume
mountPath:/etc/config
volumes:
- name:config-volume
configMap:
# Provide the name of the ConfigMap containing the files you want
# to add to the container
name:special-config
restartPolicy:Never
```
- Pod运行时command (“ls /etc/config/”)将输出: special.level special.type
- **如果在/etc/config/目录下存在文件,将不会删除**
## 添加ConfigMap数据至存储卷指定的目录
- 为ConfigMap条目使用path指定文件路径
- 此例中special.level将在config-volume存储卷中被挂接至/etc/config/keys
```yaml
apiVersion:v1
kind:Pod
metadata:
name:dapi-test-pod
spec:
containers:
- name:test-container
image:k8s.gcr.io/busybox
command:["/bin/sh","-c","cat /etc/config/keys"]
volumeMounts:
- name:config-volume
mountPath:/etc/config
volumes:
- name:config-volume
configMap:
name:special-config
items:
- key:special.level
path:keys
restartPolicy:Never
```
- Pod运行时(“cat /etc/config/keys”) 将输出: very
# 参考
- [Kubernetes-配置字典ConfigMap](https://blog.csdn.net/bbwangj/article/details/81776648)

328
content/post/docker.md Normal file
View File

@ -0,0 +1,328 @@
---
title: "Docker 笔记"
date: 2019-10-30T13:29:00+08:00
lastmod: 2021-11-05T11:11:00+08:00
tags: ["docker"]
categories: ["container"]
---
# 安装 docker
## CentOS7 安装 docker-ce
- 配置 yum 源
```bash
curl -Lo /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
#替换成清华源
sed -i 's#download.docker.com#mirrors.tuna.tsinghua.edu.cn/docker-ce#' /etc/yum.repos.d/docker-ce.repo
yum clean all
yum makecache
```
- 安装 docker
```bash
yum install docker-ce
```
- 修改 docker 配置文件,建议选择一个与本地网络不冲突的网段
```bash
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<-EOF
{
"insecure-registries": ["harbor.colben.cn"],
"default-address-pools" : [{"base":"10.110.0.0/16", "size": 24}],
"log-driver": "json-file",
"log-opts": {"max-size":"100m", "max-file":"4"}
}
EOF
```
- 启动 docker
```bash
systemctl start docker
```
## 常用的 linux with systemd 安装 docker
- 下载 docker 二进制文件
```bsah
curl -LO https://download.docker.com/linux/static/stable/x86_64/docker-20.10.10.tgz
```
- 安装
```bash
tar zxf docker-20.10.10.tgz
mv docker/* /usr/bin/
rm -rf docker/ docker-20.10.10.tgz
groupadd -g 10110 docker
```
- 创建 /usr/lib/systemd/system/containerd.service内容如下
```
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=1048576
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
```
- 创建 /usr/lib/systemd/system/container-getty@.service内容如下
```
[Unit]
Description=Container Getty on /dev/pts/%I
Documentation=man:agetty(8) man:machinectl(1)
After=systemd-user-sessions.service plymouth-quit-wait.service
After=rc-local.service getty-pre.target
Before=getty.target
IgnoreOnIsolate=yes
ConditionPathExists=/dev/pts/%I
[Service]
ExecStart=-/sbin/agetty --noclear --keep-baud pts/%I 115200,38400,9600 $TERM
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=pts/%I
TTYPath=/dev/pts/%I
TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes
```
- 创建 /usr/lib/systemd/system/docker.socket内容如下
```
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
```
- 创建 /usr/lib/systemd/system/docker.service内容如下
```
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket containerd.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3
# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
```
- 修改 docker 配置文件,建议选择一个与本地网络不冲突的网段
```bash
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<-EOF
{
"insecure-registries": ["harbor.colben.cn"],
"default-address-pools" : [{"base":"10.110.0.0/16", "size": 24}],
"log-driver": "json-file",
"log-opts": {"max-size":"100m", "max-file":"4"}
}
EOF
```
- 启动 docker
```bash
systemctl start docker
```
# 安装 docker-compose
- 下载 docker-compose
```bash
curl -LO https://github.com/docker/compose/releases/download/v2.1.0/docker-compose-linux-x86_64
```
- 安装
```bash
mv docker-compose-linux-x86_64 /usr/bin/docker-compose
chmod 0755 /usr/bin/docker-compose
```
# 安装 gojq
- 该工具支持平台较多,无依赖,与 jq 命令操作完全一致,可用于替换 jq 命令
- 下载
```bash
curl -LO https://github.com/itchyny/gojq/releases/download/v0.12.5/gojq_v0.12.5_linux_amd64.tar.gz
```
- 安装
```bash
tar zxf gojq_v0.12.5_linux_amd64.tar.gz
mv gojq_v0.12.5_linux_amd64/gojq /usr/bin/
chmod 0755 /usr/bin/gojq
rm -rf gojq_*
```
# 基本命令
- 镜像
```bash
docker pull [选项] [Docker Registry地址]<仓库名>:<标签> #获取镜像
docker images [选项] #列出镜像
docker images -f dangling=true #列出虚悬镜像
docker images -q -f dangling=true | xargs docker rmi #删除全部虚悬镜像
docker commit -m "提交的说明信息" -a "更新的用户信息" <容器ID> [地址]<仓库名>:<标签> #根据现有容器创建镜像
docker build -t="[地址]<仓库名>:<标签>" <Dockerfile 所在的目录> #构建镜像
docker tag <镜像ID> [地址]<仓库名>:<标签> #修改镜像的标签
docker push [地址]<仓库名>:<标签> #上传镜像
docker save -o <本地文件名.tar> [地址]<仓库名>:<标签> #保存镜像到本地文件
docker load < <本地文件名.tar> #把本地文件加载到镜像库
docker rmi <镜像ID> #删除镜像
```
- 容器
```bash
docker run [选项] [地址]<仓库名>:<标签> [命令] #从镜像启动一个容器
docker stop <容器名|容器ID> #终止运行中的容器
docker start <容器名|容器ID> #启动已停止的容器
docker retart <容器名|容器ID> #重新启动运行中的容器
docker ps [-a] #查看(全部)容器信息
docker logs <容器名|容器ID> #获取容器输出信息
docker attach <容器名|容器ID> #进入运行中的容器
docker export <容器ID> > <本地文件名.tar> #导出容器快照到本地文件
cat <本地文件名.tar> | docker import - [地址]<仓库名>:<标签> #从本地文件导入容器快照
docker rm -r <容器名|容器ID> #删除(运行中的)容器
```
- 数据卷
```bash
docker run [选项] -v /webapp [地址]<仓库名>:<标签> [命令] #启动容器时创建一个数据卷挂载到容器的 /webapp 下
docker rm -v <容器名|容器ID> #删除容器时同时删除数据卷
docker run [选项] -v <主机绝对目录>:<容器绝对目录>[:ro] [地址]<仓库名>:<标签> [命令] #启动容器时挂载本地目录到容器指定目录下,默认可读写
docker run [选项] -v <主机文件>:<容器文件>[:ro] [地址]<仓库名>:<标签> [命令] #启动容器时挂载本地文件到容器指定文件,默认可读写
docker inspect <容器名|容器ID> #查看容器信息
docker run [选项] --volumes-from <挂载数据卷的容器名> [地址]<仓库名>:<标签> [命令] #在其他容器中挂载指定容器(不必运行)的数据卷
```
- 备份数据卷
```bash
docker run [选项] --volumes-from <挂载数据卷的容器名> -v $(pwd):/backup [地址]<仓库名>:<标签> tar cvf /backup/backup.tar <数据卷挂载目录> #备份数据卷到主机当前目录的 backup.tar 文件
```
- 恢复数据卷
```bash
docker run [选项] -v <数据卷挂载目录> --name <自定义一个容器名> [地址]<仓库名>:<标签> [命令] #创建一个带空数据卷的容器
docker run [选项] --volumes-from <第一步挂载空数据卷的容器名> -v $(pwd):/backup busybox tar xvf /backup/backup.tar #挂载空数据卷和本机备份目录,解压备份文件
docker run [选项] --volumes-from <第一步挂载空数据卷的容器名> busybox 'ls <数据卷挂载目录>' #查看恢复的数据
```
- 网络
```bash
docker run [选项] -P [地址]<仓库名>:<标签> [命令] #随机映射主机 49000-49900 中的端口到容器开放的端口
docker run [选项] -p <ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort>[/udp] [地址]<仓库名>:<标签> [命令] #映射本机指定tcp(udp)端口到容器指定tcp(udp)端口
docker port <容器名> <容器开放的端口> #查看主机被绑定的地址
docker run [选项] --link <待链接容器名>:<链接别名> [地址]<仓库名>:<标签> [命令] #创建一个链接到其他容器的新容器
```
# Dockerfile
- 井号 "#" 后是注释
- FROM 基础镜像
- MAINTAINER 维护者信息
- RUN shell命令
- ADD 复制本地文件到容器,自动解压 tar 文件,可以增加网络文件
- COPY 复制本地文件到容器,不自动解压,也不可以增加网络文件
- LABEL 为镜像添加元数据
- ENV 设置镜像内环境变量
- USER 容器运行时的用户和用户组
- ONBUILD 镜像触发器
- EXPOSE 向外部开放端口
- CMD 容器启动后运行的程序
# docker 镜像仓库
## 官方 registry
- 直接 docker 启动
```bash
docker run -d \
--name registry \
--net host \
-e "REGISTRY_HTTP_ADDR='0.0.0.0:80'" \
-v /some/path:/var/lib/registry \
registry
```
## VMWare Harbor
- 安装[参考这里](https://goharbor.io/docs/2.0.0/install-config/)
- docker registry 采用 http 协议,客户端提示 “server gave HTTP response to HTTPS client”
```bash
#在客户端 /etc/docker/daemon.json 中增加 insecure-registries 配置
# "insecure-registries":["10.0.2.22:5080"]
#重启客户端的 docker 服务
systemctl restart docker
```
- docker registry 采用 https 协议,客户端提示 "authority unknown ..."
```bash
#在客户端 /etc/docker/ 下创建 registry server 的 domain/ip 目录
mkdir -p /etc/docker/certs.d/10.0.2.22:5080/
#复制 registry server 的 ca.crt (该文件由 openssl 创建密钥时生成)
scp root@10.0.2.22:/opt/harbor/keys/ca.crt /etc/docker/certs.d/10.0.2.22:5080/
#重启客户端的 docker 服务
systemctl restart docker
```

215
content/post/drone.md Normal file
View File

@ -0,0 +1,215 @@
---
title: "Drone 笔记"
date: 2021-02-08T17:03:13+08:00
lastmod: 2021-02-08T21:08:00+08:00
keywords: []
tags: ["drone", "cicd"]
categories: ["dev/ops"]
---
# 环境
- 操作系统 Linux x86_64
- 这里的 drone 是基于 gitea 配置的
- 安装 gitea参考[官方文档](https://docs.gitea.io/zh-cn/install-from-binary/)
- 安装 docker-ce参考[我的 docker 笔记](https://www.colben.cn/post/docker/#%E5%AE%89%E8%A3%85)
# 创建 OAuth2 应用
- 登陆 gitea
- 点击 "个人头像" - "设置" - "应用"
- 在 "管理 OAuth2 应用程序" 中,输入
- 输入应用名称: "drone"
- 重定向URI: "http://<drone 服务器地址>:<drone 服务器端口>/login"
- 点击 "创建应用",在弹出的新页面中
- 记录 "客户端 ID"
- 记录 "客户端密钥"
- 点击 "保存"
# 安装 drone
- 下载 docker 镜像
```bash
docker pull drone/drone
```
- 启动容器
```bash
docker run -d \
--name drone \
-e DRONE_GITEA_SERVER=http://<gitea 服务器地址>:<gitea 服务器端口> \
-e DRONE_GITEA_CLIENT_ID=<客户端 ID> \
-e DRONE_GITEA_CLIENT_SECRET=<客户端密钥> \
-e DRONE_RPC_SECRET=1111aaaa2222bbbb3333cccc4444dddd \
-e DRONE_SERVER_HOST=<drone 服务器地址>:<drone 服务器端口> \
-e DRONE_SERVER_PROTO=http \
-e DRONE_GIT_ALWAYS_AUTH=true \
-p <drone 服务器端口>:80 \
-v <外挂的 drone 数据目录>:/data \
drone/drone
```
- 参考链接[https://docs.drone.io/server/provider/gitea/](https://docs.drone.io/server/provider/gitea/)
# 安装 drone runner
## 安装 docker runner
- 下载 drone-runner-docker 镜像
```bash
docker pull drone/drone-runner-docker
```
- 启动容器
```bash
docker run -d \
--name drone_runner_docker \
-e DRONE_RPC_PROTO=http \
-e DRONE_RPC_HOST=<drone 服务器地址>:<drone 服务器端口> \
-e DRONE_RPC_SECRET=1111aaaa2222bbbb3333cccc4444dddd \
-e DRONE_RUNNER_CAPACITY=10 \
-e DRONE_RUNNER_NAME=< runner 的名字> \
-e DRONE_RUNNER_LABELS=<key1>:<value1> \
-p <runner 端口>:3000 \
-v /var/run/docker.sock:/var/run/docker.sock \
drone/drone-runner-docker
```
- 参考链接[https://docs.drone.io/runner/docker/installation/linux/](https://docs.drone.io/runner/docker/installation/linux/)
## 安装 exec runner
- 下载
```bash
curl -L https://github.com/drone-runners/drone-runner-exec/releases/latest/download/drone_runner_exec_linux_amd64.tar.gz \
| tar zxf -C /usr/local/bin
chmod 0755 /usr/local/bin/drone-runner-exec
```
- 创建配置文件
```bash
cat > /etc/drone-runner-exec/config <<-EOF
DRONE_RPC_PROTO=http
DRONE_RPC_HOST=<drone 服务器地址>:<drone 服务器端口>
DRONE_RPC_SECRET=1111aaaa2222bbbb3333cccc4444dddd
DRONE_HTTP_BIND=:<runner 端口>
DRONE_LOG_FILE=/var/log/drone-runner-exec/log.txt
DRONE_RUNNER_LABELS=<key1>:<value1>
EOF
```
- 创建 systemd service 文件
```bash
cat > /etc/systemd/system/drone-runner-exec.service <<-EOF
[Unit]
Description=Drone Exec Runner
ConditionFileIsExecutable=/usr/local/bin/drone-runner-exec
[Service]
ExecStart=/usr/local/bin/drone-runner-exec "service" "run" "--config" "/etc/drone-runner-exec/config"
StartLimitInterval=5
StartLimitBurst=10
Restart=on-failure
RestartSec=120
[Install]
WantedBy=multi-user.target
EOF
```
- 参考链接[https://docs.drone.io/runner/exec/installation/linux/](https://docs.drone.io/runner/exec/installation/linux/)
# 使用 drone
- 登陆 drone: http://<drone 服务器地址>:<drone 服务器端口>,此时会跳转到 gitea 登陆界面
- 登陆成功后,浏览器返回 drone 首页,这里会显示我们创建/参与的 git 项目
- 选择一个项目,点击对应的 "ACTIVATE"drone 会打开该项目的 "SETTINGS" 页面,这里一般无需设置,默认即可
- 在该项目的 "ACTIVITY FEED" 页面会显示每次项目提交后触发的 CI/CD 流程
- 编辑该项目代码,在项目根目录下创建文件 .drone.yml内容如下
- docker pipeline 示例,详细参考[https://docs.drone.io/pipeline/docker/overview/](https://docs.drone.io/pipeline/docker/overview/)
```yaml
---
kind: pipeline
type: docker
name: default
steps:
- name: greeting
image: golang:1.12
commands:
- go build
- go test
node:
<key1>: <value1>
```
- exec pipeline 示例,详情参考[https://docs.drone.io/pipeline/exec/overview/](https://docs.drone.io/pipeline/exec/overview/)
```yaml
---
kind: pipeline
type: exec
name: default
platform:
os: linux
arch: amd64
steps:
- name: greeting
commands:
- echo hello world
node:
<key1>: <value1>
```
- 其他 pipeline 参考[https://docs.drone.io/pipeline/overview/](https://docs.drone.io/pipeline/overview/)
# 适配 sonarqube
- 下载镜像
```bash
docker pull sonarqube
```
- 启动 sonarqube 容器
```bash
docker run -d \
--name sonarqube \
-p <sonarqube 服务器端口>:9000 \
-v sonarqube_data:/opt/sonarqube/data \
-v sonarqube_extension:/opt/sonarqube/extensions \
-v sonarqube_log:/opt/sonarqube/logs \
sonarqube
```
- 登陆 sonarquebe: http://<sonarqube 服务器地址>:<sonarqube 服务器端口>,创建用户,获取 token
- 在 gitea 对应项目根目录下创建 .drone.yml内容如下
```yaml
kind: pipeline
type: docker
name: 代码分析
steps:
- name: 代码分析
image: aosapps/drone-sonar-plugin
settings:
sonar_host: http://<sonarqube 服务器地址>:<sonarqube 服务器端口>
sonar_token: <sonarqube 用户 token>
node:
role: sonarqube
```
- 在 gitea 对应项目根目录下创建 sonar-project.properties内容如下
```
sonar.projectKey={项目名称}
sonar.sources=.
```
- 提交代码,在 drone 中对应项目的 "ACTIVITY FEED" 页面下查看 pipeline 执行过程
- pipeline 执行完成后,浏览器打开 http://<sonarqube 服务器地址>:<sonarqube 服务器端口>,即可查看刚检测完成的项目
- sonarqube pipeline 参考[https://hub.docker.com/r/aosapps/drone-sonar-plugin](https://hub.docker.com/r/aosapps/drone-sonar-plugin)
- sonarqube 配置参考[https://docs.sonarqube.org/latest/analysis/analysis-parameters/](https://docs.sonarqube.org/latest/analysis/analysis-parameters/)

View File

@ -0,0 +1,187 @@
---
title: "Elasticsearch 笔记"
date: 2019-10-30T11:49:53+08:00
lastmod: 2019-10-30T11:49:53+08:00
tags: ["elasticsearch"]
categories: ["database"]
---
# 索引
- 查看某节点的全部索引
```bash
curl http://127.0.0.1:9200/_cat/indices?v
```
- 新建 index
```bash
curl -X PUT http://127.0.0.1:9200/index_name
```
- 删除 index
```bash
curl -X DELETE http://127.0.0.1:9200/index_name
```
# 记录
- 新增记录(指定记录id)
```bash
curl -X PUT -H "Content-Type: application/json" http://127.0.0.1:9200/index_name/doc_id -d '
{
"aa": "11",
"bb": "22"
}'
```
- 新增记录(不指定记录id)
```bash
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/index_name -d '
{
"aa": "11",
"bb": "22"
}'
```
- 查看记录
```bash
curl http://127.0.0.1:9200/index_name/doc_id?pretty=true
```
- 删除记录
```bash
curl -X DELETE http://127.0.0.1:9200/index_name/doc_id
```
- 更新记录
```bash
curl -X PUT -H "Content-Type: application/json" http://127.0.0.1:9200/index_name/doc_id -d '
{
"aa": "33",
"bb": "44"
}'
```
# 查询
- 查询所有记录
```bash
curl http://127.0.0.1:9200/index_name/_search
```
- 查询匹配
```bash
curl -H "Content-Type: application/json" http://127.0.0.1:9200/index_name/_search -d '
{
"query": {"match": {"key_name": "value_pattern"}}
}'
```
- 从位置2(默认0)开始查询8(默认10)条记录
```bash
curl -H "Content-Type: application/json" http://127.0.0.1:9200/index_name/_search -d '
{
"query": {"match": {"key_name": "value_pattern"}},
"from": 2,
"size": 8
}'
```
- 逻辑 or 查询
```bash
curl -H "Content-Type: application/json" http://127.0.0.1:9200/index_name/_search -d '
{
"query": {"match": {"key_name": "value_pattern_1 value_pattern_2"}}
}'
```
- 逻辑 and 查询
```bash
curl -H "Content-Type: application/json" http://127.0.0.1:9200/index_name/_search -d '
{
"query": {
"bool": {
"must": [
{"match": {"key_name": "value_pattern_1"}},
{"match": {"key_name": "value_pattern_2"}}
]
}
}
}'
```
- 区间查询
```bash
set -euo pipefail
export START_TIME="$(date +%s -d $1)"
export END_TIME="$(date +%s -d $2)"
curl -s -H "Content-Type: application/json" -o result.txt \
http://127.0.0.1:9200/wangmei_raw/_search?pretty -d @- <<EOF
{
"_source": [
"spider_name",
"spider_time",
"media_name",
"publish_time"
],
"query": {
"bool": {
"filter": {
"range": {
"spider_time": {
"gt": $START_TIME,
"lte": $END_TIME
}
}
}
}
},
"size": 10000
}
EOF
```
# Kibana
- lucene 正则查询
```
#查询包含10000-99999毫秒的 message 字段
{ "regexp": { "message": "[0-9]{5}ms" } }
```
- Dev tool 模拟 pipeline
```
POST _ingest/pipeline/_simulate
{
"pipeline" : {
"description": "",
"processors": [
{
"grok": {
"field": "message",
"patterns": [
"",
""
],
"ignore_missing": true,
"ignore_failure": true
}
}
]
},
"docs" : [
{
"_source": {
"message": ""
}
},
{
"_source": {
"message": ""
}
}
]
}
```
# pipeline
- 查看已有的 pipeline
```bash
curl http://127.0.0.1:9200/_ingest/pipeline?pretty=true
# 指定 nginx-access
curl http://127.0.0.1:9200/_ingest/pipeline/nginx-access?pretty=true
```
- [Mysql 慢查询日志](https://git.colben.cn/colben/myfilebeat/raw/master/pipelines/mysql-slow.json)
- [Secure 登陆日志](https://git.colben.cn/colben/myfilebeat/raw/master/pipelines/secure-login.json)
- [Nginx access 日志](https://git.colben.cn/colben/myfilebeat/raw/master/pipelines/nginx-access.json)
# filebeat
- [常用配置](https://git.colben.cn/colben/myfilebeat/raw/master/filebeat.yml)
- [收割 secure 日志](https://git.colben.cn/colben/myfilebeat/raw/master/prospectors.d/secure.yml)
- [收割 mysql 慢查询日志和错误日志](https://git.colben.cn/colben/myfilebeat/raw/master/prospectors.d/mysql.yml)
- [收割 nginx access 日志](https://git.colben.cn/colben/myfilebeat/raw/master/prospectors.d/nginx.yml)

137
content/post/es-install.md Normal file
View File

@ -0,0 +1,137 @@
---
title: "CentOS7 安装 elasticsearch 集群"
date: 2019-10-30T01:19:09+08:00
lastmod: 2019-10-30T01:19:09+08:00
keywords: []
tags: ["elasticsearch", "centos"]
categories: ["database"]
---
# 环境
主机名 | IP | 操作系统 | ES 版本
---- | ---- | ---- | ----
es227 | 192.168.1.227 | CentOS7.5 | 6.5.4
es228 | 192.168.1.228 | CentOS7.5 | 6.5.4
es229 | 192.168.1.229 | CentOS7.5 | 6.5.4
- 下载 [elasticsearch-6.5.4.tar.gz](https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.tar.gz)
# 各节点初始配置
- 关闭 selinux、防火墙
- 部署 java 运行环境
- 创建 elastic 用户
```
useradd -m elastic
```
- 创建数据目录
```
cd /var/lib
mkdir elasticsearch
chown elastic.elastic elasticsearch
```
- 创建日志目录
```
cd /var/log
mkdir -p elasticsearch
chown elastic.elastic elasticsearch
```
- 增加 sysctl.conf 配置,执行 sysctl -p 生效
```
vm.max_map_count = 262144
```
- 增加 /etc/security/limits.conf 配置
```
elastic soft nofile 65536
elastic hard nofile 65536
elastic soft memlock unlimited
elastic hard memlock unlimited
```
# 部署 ELASTICSEARCH
- 登陆 es227下载 elasticsearch解压至 /opt/ 下
- 修改 elasticsearch 目录的权限
```
chown -R elastic.elastic /opt/elasticsearch
```
- 修改 jvm 参数文件 /opt/elasticsearch/config/jvm.options
- 修改 /opt/elsaticsearch/config/elasticsearch.yml
```
cluster.name: TEST_ES_CLUSTER
node.name: es227
network.host: 192.168.1.227
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
bootstrap.memory_lock: true
discovery.zen.ping.unicast.hosts: ["192.168.1.227:9300", "192.168.1.228:9300", "192.168.1.229:9300"]
discovery.zen.minimum_master_nodes: 2
gateway.recover_after_nodes: 2
```
- 打包 elasticsearch 目录,复制到 es228 和 es229 上,并修改 elasticsearch.yml
```
# es228
node.name: es228
network.host: 192.168.1.228
# es229
node.name: es229
network.host: 192.168.1.229
```
# 启动集群(两种启动方式)
- 直接启动二进制
- 在每个节点上启动 elasticsearch 服务
```bash
su - elastic -c '/opt/elasticsearch/bin/elasticsearch -d'
```
- systemd 启动
- 创建文件 /usr/lib/systemd/system/elasticsearch.service内容如下
```
[Unit]
Description=ElasticSearch
Requires=network.service
After=network.service
[Service]
User=elastic
Group=elastic
LimitNOFILE=65536
LimitMEMLOCK=infinity
Environment=JAVA_HOME=/opt/jre
ExecStart=/opt/elasticsearch/bin/elasticsearch
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
```
- 启动 elasticsearch 服务
```bash
systemctl daemon-reload
systemctl start elasticsearch
```
# 查看集群状态
- 查看集群节点状态
```
# 查看节点状态
curl http://192.168.1.228:9200/_cat/nodes?pretty
# 查看集群状态
curl http://192.168.1.228:9200/_cluster/state?pretty
```
# 安装分词插件
- 登陆 es227下载插件 [elasticsearch-analysis-ik-6.5.4.zip](https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip) 至根目录下
- 复制该文件至 es228 和 es229 的根目录下
- 每个节点上安装
```
su - elastic
/opt/elasticsearch/bin/elasticsearch-plugin install file:///elasticsearch-analysis-ik-6.5.4.zip
```
- 配置远程扩展字典时,出现 java.net.SocketPermission 拒绝连接,此时需配置 jre 策略
```
# vim /opt/jre/lib/security/java.policy在最后一个 "}" 前追加下面一行
permission java.net.SocketPermission "*:*","accept,connect,resolve";
```

256
content/post/firewalld.md Normal file
View File

@ -0,0 +1,256 @@
---
title: "Firewalld 笔记"
date: 2019-10-30T13:01:37+08:00
lastmod: 2019-10-30T13:01:37+08:00
tags: ["firwalld"]
categories: ["network"]
---
# 区域(zone)
- 查看支持的 zone
```bash
firewall-cmd --get-zones [--permanent]
```
- zone 定义
- 丢弃(drop) 任何接收的网络数据包都被丢弃,没有任何回复。仅能有发送出去的网络连接。
- 限制(block) 任何接收的网络连接都被 IPv4 的 icmp-host-prohibited 信息和 IPv6 的 icmp6-adm-prohibited 信息所拒绝。
- 公共(public) 在公共区域内使用,不能相信网络内的其他计算机不会对您的计算机造成危害,只能接收经过选取的连接。
- 外部(external) 特别是为路由器启用了伪装功能的外部网。您不能信任来自网络的其他计算,不能相信它们不会对您的计算机造成危害,只能接收经过选择的连接。
- 非军事区(dmz) 用于您的非军事区内的电脑,此区域内可公开访问,可以有限地进入您的内部网络,仅仅接收经过选择的连接。
- 工作(work) 用于工作区。您可以基本相信网络内的其他电脑不会危害您的电脑。仅仅接收经过选择的连接。
- 家庭(home) 用于家庭网络。您可以基本信任网络内的其他计算机不会危害您的计算机。仅仅接收经过选择的连接。
- 内部(internal) 用于内部网络。您可以基本上信任网络内的其他计算机不会威胁您的计算机。仅仅接受经过选择的连接。
- 信任(trusted) 可接受所有的网络连接。
- 指定其中一个区域为默认区域是可行的。当接口连接加入了 NetworkManager它们就被分配为默认区域。安装时firewalld 里的默认区域被设定为公共区域。
- 判断请求使用的 zone
- source源地址优先级最高
- interface接收请求的网卡
- 默认 zone优先级最低
- 查看默认的 zone
```bash
firewall-cmd --get-default-zone
```
- 设置默认的 zone
```bash
firewall-cmd --set-default-zone=public
```
- 查看活动的 zone
```bash
firewall-cmd --get-active-zones
```
- 查看指定 zone 下的规则
```bash
firewall-cmd [--zone=<zone>] --list-all
```
# 源地址(source)
- 列出指定zone的所有绑定的source地址
```bash
firewall-cmd [--permanent] [--zone=zone] --list-sources
```
- 查询指定zone是否跟指定source地址进行了绑定
```bash
firewall-cmd [--permanent] [--zone=zone] --query-source=ip[/mask]
```
- 用于将一个source地址绑定到指定的zone只可绑定一次第二次绑定到不同的zone会报错
```bash
firewall-cmd [--permanent] [--zone=zone] --add-source=ip[/mask]
```
- 改变source地址所绑定的zone如果原来没有绑定则进行绑定
```bash
firewall-cmd [--permanent] [--zone=zone] --change-source=ip[/mask]
```
- 删除source地址跟zone的绑定
```bash
firewall-cmd [--permanent] [--zone=zone] --remove-source=ip[/mask]
```
# 网卡(interface)
- 获取网卡所在的 zone
```bash
firewall-cmd --get-zone-of-interface=<interface>
```
- 增加网卡到 zone
```bash
firewall-cmd [--zone=<zone>] --add-interface=<interface>
```
- 修改网卡到 zone
```bash
firewall-cmd [--zone=<zone>] --change-interface=<interface>
```
- 从 zone 中删除网卡
```bash
firewall-cmd [--zone=<zone>] --remove-interface=<interface>
```
- 查看 zone 中是否包含某网卡
```bash
firewall-cmd [--zone=<zone>] --query-interface=<interface>
```
# target
- 默认可以取四个值: default、ACCEPT、%%REJECT%%、DROP
- 查看 taget
```bash
firewall-cmd --permanent [--zone=zone] --get-target
```
- 设置 target
```bash
firewall-cmd --permanent [--zone=zone] --set-target=target
```
- **必须使用参数 --permanent**,而且使用 firewall-cmd 命令不能直接生效,需 reload
# 服务(service)
- 查看支持的 service
```bash
firewall-cmd --get-services [--permanent]
```
- 查看 zone 启动的 service
```bash
firewall-cmd [--zone=<zone>] --list-services
```
- 在 zone 中启动 service
```bash
firewall-cmd [--zone=<zone>] --add-service=<service> \
[ --permanent | --timeout=<seconds> ]
```
- 禁用 zone 中的 service
```bash
firewall-cmd [--zone=<zone>] --remove-service=<service> [--permanent]
```
- 查看 zone 中是否启动 service
```bash
firewall-cmd [--zone=<zone>] --query-service=<service>
```
# 端口和协议组合
- 查看配置的全部端口规则
```bash
firewall-cmd [--permanent] [--zone=zone] --list-ports
```
- 启动 zone 中指定协议的端口
```bash
firewall-cmd [--zone=<zone>] --add-port=<port>[-<port>]/<protocol> \
[ --permanent | --timeout=<seconds> ]
```
- 禁用 zone 中指定协议的端口
```bash
firewall-cmd [--zone=<zone>] --remove-port=<port>[-<port>]/<protocol> [--permanent]
```
- 查看 zone 中指定协议的端口
```bash
firewall-cmd [--zone=<zone>] --query-port=<port>[-<port>]/<protocol> [--permanent]
```
# ICMP
- 查看支持的 icmp 类型
```bash
firewall-cmd --get-icmptypes [--permanent]
```
- 查看全部 icmp 阻塞规则
```bash
firewall-cmd [--permanent] [--zone=zone] --list-icmp-blocks
```
- 启动 zone 中的 icmp 阻塞
```bash
firewall-cmd [--zone=<zone>] --add-icmp-block=<icmptype> \
[ --permanent | --timeout=seconds ]
```
- 禁用 zone 中的 icmp 阻塞
```bash
firewall-cmd [--zone=<zone>] --remove-icmp-block=<icmptype> [--permanent]
```
- 查询 zone 的 icmp 阻塞
```bash
firewall-cmd [--zone=<zone>] --query-icmp-block=<icmptype> [--permanent]
```
# IPV4 源地址转换
- 启动 zone 中 ipv4 源地址转换
```bash
firewall-cmd [--zone=<zone>] --add-masquerade \
[ --permanent | --timeout=seconds ]
```
- 禁用 zone 中 ipv4 源地址转换
```bash
firewall-cmd [--zone=<zone>] --remove-masquerade [--permanent]
```
- 查看 zone 中 ipv4 源地址转换
```bash
firewall-cmd [--zone=<zone>] --query-masquerade [--permanent]
```
# 端口转发
- 查看全部端口转发规则
```bash
firewall-cmd [--permanent] [--zone=zone] --list-forward-ports
```
- 启动 zone 中端口转发
```bash
firewall-cmd [--zone=<zone>] --add-forward-port=port=<port>[-<port>]:proto=<protocol> \
{ :toport=<port>[-<port>] | :toaddr=<address> | :toport=<port>[-<port>]:toaddr=<address> } \
[ --permanent | --timeout=seconds ]
```
- 禁用 zone 中端口转发
```bash
firewall-cmd [--zone=<zone>] --remove-forward-port=port=<port>[-<port>]:proto=<protocol> \
{ :toport=<port>[-<port>] | :toaddr=<address> | :toport=<port>[-<port>]:toaddr=<address> } \
[--permanent]
```
- 查看 zone 中端口转发
```bash
firewall-cmd [--zone=<zone>] --query-forward-port=port=<port>[-<port>]:proto=<protocol> \
{ :toport=<port>[-<port>] | :toaddr=<address> | :toport=<port>[-<port>]:toaddr=<address> } \
[--permanent]
```
# Rich Rules
- 通用结构
```bash
firewall-cmd [--zone=<zone>] [ --permanent | --timeout=seconds ] \
<--add|--remove>-rich-rule='rule [family=<ipv4|ipv6> \
source address=<address[/mask]> [invert=<True|False>] \
destination address=<address[/mask]> [invert=<True|False>] \
service name=<service> \
port port=<port>[-<port>] \
protocol=<protocol> \
icmp-block name=<icmptype> \
masquerade \
forward-port port=<port>[-<port>] protocol=<protocol> to-port=<port>[-<port>] to-address=<address> \
log [prefix=<prefix text>] [level=<log level>] [limit value=<rate/duration>] \
accept|reject [type=<reject type>]|drop'
```
- 查看全部 rich rule
```bash
firewall-cmd [--permanent] [--zone=zone] --list-rich-rules
```
- 具体参数解释见系统 man 手册
```bash
man firewalld.richlanguage 5
```
# 应急模式(panic)
- 启动 panic即断网
```bash
firewall-cmd --panic-on
```
- 关闭 panic即联网
```bash
firewall-cmd --panic-off
```
- 查询应急模式
```bash
firewall-cmd --query-panic
```
# 重新载入(reload)
- 重新载入防火墙,不中断用户连接
```bash
firewall-cmd --reload
```
- 重新载入防火墙并中断用户连接
```bash
firewall-cmd --complete-reload
```
# 备注
- 参数 --timeout 是让规则生效一段时间,过期自动删除,不能与 --permanent 一起使用

186
content/post/ftp.md Normal file
View File

@ -0,0 +1,186 @@
---
title: "Ftp 笔记"
date: 2019-10-30T17:48:02+08:00
lastmod: 2019-10-31T21:49:00+08:00
tags: ["ftp", "vsftp"]
categories: ["storage"]
---
# 环境
- CentOS7
- vsftpd
- 关闭 selinux
# 安装 vsftpd 服务
```bash
yum install vsftpd
```
# 常用客户端
- ftp
- lftp
- curl
# 主动模式
- 建立控制命令连接
- 客户端连接服务端 21 号端口
- 建立数据传送连接
- 客户端在本地监听一个端口(大于 1024 ),并通过 PORT 命令通知服务端
- 服务端从 20 端口连接客户端正在监听的端口,向客户端发送数据
- 相关配置
```ini
# 开启主动模式
pasv_enable = no
```
# 被动模式
- 建立控制命令连接
- 客户端连接服务端 21 号端口
- 建立数据传送连接
- 服务端在本地再次监听一个端口(大于 1024),并通过 PASV 命令通知客户端
- 客户端连接服务端新监听的端口,下载服务端数据
- 相关配置
```ini
# 开启被动模式
pasv_enable = yes
# 数据连接可以使用的端口范围的最大端口0 表示任意端口默认值为0
pasv_min_port=30000
# 数据连接可以使用的端口范围的最小端口0 表示任意端口默认值为0
pasv_max_port=30999
```
# 匿名用户配置
```ini
# 控制是否允许匿名用户登入
# 匿名用户使用的登陆名为 ftp 或 anonymous口令为空
# 匿名用户不能离开匿名用户家目录/var/ftp且只能下载不能上传
anonymous_enable=YES/NO(YES)
# 匿名登入时,不会询问密码
no_anon_password=YES/NO(NO)
# 定义匿名登入的使用者名称默认值为ftp
ftp_username=ftp
# 是否允许登陆用户有写权限,属于全局设置
write_enable=YES/NO(YES)
# 使用匿名登入时,所登入的目录,默认值为/var/ftp
# 注意ftp目录不能是777的权限属性即匿名用户的家目录不能有777的权限
anon_root=/var/ftp
# 是否允许匿名者有上传文件(非目录)的权限
# 只有在write_enable=YES时此项才有效
# 匿名用户必须要有对上层目录的写入权
anon_upload_enable=YES/NO(NO)
# 是否允许匿名者下载可阅读的档案
anon_world_readable_only=YES/NO(YES)
# 是否允许匿名者有新增目录的权限
# 只有在write_enable=YES时此项才有效
# 匿名用户必须要有对上层目录的写入权
anon_mkdir_write_enable=YES/NO(NO)
# 是否允许匿名入者拥有其他权限,譬如删除或者重命名
# 如果anon_upload_enable=NO则匿名用户不能上传文件但可以删除或者重命名已经存在的文件
# 如果anon_mkdir_write_enable=NO则匿名用户不能上传或者新建文件夹但可以删除或者重命名已经存在的目录
anon_other_write_enable=YES/NO(NO)
# 是否改变匿名用户上传文件(非目录)的属主
chown_uploads=YES/NO(NO)
# 设置匿名用户上传文件(非目录)的属主名
# 建议不要设置为root
chown_username=username
# 设置匿名登入者新增或上传档案时的 umask 值,默认值为 077
anon_umask=077
```
# 配置
## 常用配置
```ini
#允许匿名用户登陆
anonymous_enable=YES
#允许本地用户登陆
local_enable=YES
#允许登陆用户写可访问的目录或文件
write_enable=YES
#指定用户登陆后直接进入系统的/mnt目录
local_root=/mnt
chroot_list_enable=YES
#限定登陆用户可访问的目录只有自己的家目录或指定的local_root目录
chroot_list_file=/etc/vsftpd/chroot_list
```
## 允许 vsftpd 匿名用户上传和下载
- 创建匿名用户登陆目录
```bash
mkdir -p /var/ftp/pub
chown -R ftp.ftp /var/ftp/pub
chmod o+w /var/ftp/pub
```
- 修改 vsftpd.conf
```ini
允许匿名用户登录FTP
anonymous_enable=YES
#设置匿名用户的登录目录(如需要,需自己添加并修改)
anon_root=/var/ftp/pub
#打开匿名用户的上传权限
anon_upload_enable=YES
#打开匿名用户创建目录的权限
anon_mkdir_write_enable=YES
#打开匿名用户删除和重命名的权限(如需要,需自己添加)
anon_other_write_enable=YES
anon_umask=022
```
## 本地用户登陆
- 修改 vsftpd.conf
```
# 不允许匿名用户登入
anonymous_enable=no
# 允许本地用户登入
local_enable=YES
# 当本地用户登入时,将被更换到定义的目录下
# 默认值为各用户的家目录
local_root=/home/username
# 是否允许登陆用户有写权限
# 属于全局设置默认值为YES。
write_enable=YES/NO(YES)
# 本地用户新增档案时的 umask 值默认值为077
local_umask=022
# 本地用户上传档案后的档案权限
# 与chmod所使用的数值相同默认值为0666
file_open_mode=0755
# 指定用户列表文件中的用户不允许切换到上级目录
chroot_local_user=YES
```
## 创建 ftp 专用账户
- 创建用户 ftpuser1
```bash
useradd -s /sbin/nologin ftpuser1
passwd ftpuser1
```
- 修改 vsftpd.conf
```ini
anonymous_enable=no
local_enable=YES
local_root=/home/ftpuser
write_enable=YES
local_umask=022
file_open_mode=0755
chroot_local_user=YES
```
# 参考
- [vsftpd 详细配置](http://vsftpd.beasts.org/vsftpd_conf.html)

114
content/post/git-http.md Normal file
View File

@ -0,0 +1,114 @@
---
title: "搭建 Git http 服务"
date: 2019-10-30T17:35:56+08:00
lastmod: 2019-10-30T17:35:56+08:00
tags: ["git", "nginx", "http", "fcgiwrap", "spawn-fcgi"]
categories: ["dev/ops"]
---
# 环境
- Centos/Redhat 6
- 安装好 git
# 安装 fcgiwrap
- 参考 https://github.com/gnosek/fcgiwrap
![](/img/150546_2jE9_2298475.png)
# 安装 spawn-fcgi
- 参考 https://github.com/lighttpd/spawn-fcgi
![](/img/150655_jGEp_2298475.png)
# 编辑 spawn-fcgi/sbin/fcgiwrap 开机启动脚本:
```bash
#! /bin/sh
DESC="fcgiwrap daemon"
DEAMON=/opt/spawn-fcgi/bin/spawn-fcgi
PIDFILE=/tmp/spawn-fcgi.pid
# fcgiwrap socket
FCGI_SOCKET=/tmp/fcgiwrap.socket
# fcgiwrap 可执行文件
FCGI_PROGRAM=/opt/fcgiwrap/sbin/fcgiwrap
# fcgiwrap 执行的用户和用户组
FCGI_USER=nobody
FCGI_GROUP=nobody
FCGI_EXTRA_OPTIONS="-M 0770"
OPTIONS="-u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -S $FCGI_EXTRA_OPTIONS -F 1 -P $PIDFILE -- $FCGI_PROGRAM"
do_start() {
$DEAMON $OPTIONS || echo -n "$DESC already running"
}
do_stop() {
kill -INT `cat $PIDFILE` || echo -n "$DESC not running"
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
do_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
do_stop
echo "."
;;
restart)
echo -n "Restarting $DESC: $NAME"
do_stop
do_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
exit 3
;;
esac
exit 0
```
# 启动 fcgiwrap
```bash
chmod 0755 /opt/spawn-fcgi/sbin/fcgiwrap
/opt/spawn-fcgi/sbin/fcgiwrap start
```
# 安装 nginx
- 参考 http://nginx.org/en/download.html启动 nginx
# 在 nginx 前端目录 html 下创建 git 仓库目录 nginx/html/git/
```bash
mkdir /opt/nginx/html/git/
chown nobody.nobody /opt/nginx/html/git/ -R
```
# 配置 nginx 的 git 服务
```nginx
# 在 server section 中添加 git
location ~ /git(/.*) {
gzip off;
fastcgi_pass unix:/tmp/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param GIT_PROJECT_ROOT /opt/nginx/html/git;
fastcgi_param PATH_INFO $1;
fastcgi_param REMOTE_USER $remote_user;
client_max_body_size 500m;
}
```
# 重新加载配置文件
```bash
/opt/nginx/sbin/nginx -s reload
```
# 测试在仓库目录下新建一个空repo
```bash
cd /opt/nginx/html/git/
git init --bare test-repo
chown nobody.nobody test-repo -R
cd test-repo
git config http.reveivepack true
```
# 完成
- 在另一台服务器中可以顺利的进行 clone、push 及 pull 等操作。

119
content/post/gnome.md Normal file
View File

@ -0,0 +1,119 @@
---
title: "Gnome 笔记"
date: 2019-10-30T11:34:41+08:00
lastmod: 2020-03-14T16:10:00+08:00
tags: ["gnome", "desktop", "桌面"]
categories: ["os"]
---
# 常用设置
```bash
# 关闭左上角热响应
gsettings set org.gnome.desktop.interface enable-hot-corners false
# 缩放系统字体
gsettings set org.gnome.desktop.interface text-scaling-factor 1.5
# monospace 字体
gsettings set org.gnome.desktop.interface monospace-font-name 'YaHei Consolas Hybrid 15'
# gtk 主题
gsettings set org.gnome.desktop.interface gtk-theme 'Vertex-Dark'
# gnome-shell 主题
gsettings set org.gnome.shell.extensions.user-theme name 'Vertex'
# 图标主题
gsettings set org.gnome.desktop.interface icon-theme 'Faenza'
# 调整 gnome3 桌面(包括 gdm )放大级别
# 0 系统自动缩放
# n > 0 放大 n 倍
gsettings set org.gnome.desktop.interface scaling-factor 1
# 启用用户扩展
gsettings set org.gnome.shell disable-user-extensions false
gsettings set org.gnome.shell enabled-extensions "['user-theme@gnome-shell-extensions.gcampax.github.com', 'workspace-indicator@gnome-shell-extensions.gcampax.github.com', 'dash-to-panel@jderose9.github.com']"
# 工作区
gsettings set org.gnome.mutter dynamic-workspaces false
gsettings set org.gnome.desktop.wm.preferences num-workspaces 4
gsettings set org.gnome.desktop.wm.preferences workspace-names "['乾坤', '巽震', '坎离', '艮兑']"
# 窗口按钮
gsettings set org.gnome.desktop.wm.preferences button-layout 'appmenu:minimize,maximize,close'
```
# 在 "活动" 中创建 "文件夹"
```bash
# 创建文件夹
gsettings set org.gnome.desktop.app-folders folder-children "['Office','VirtualBox']"
# 指定文件夹名字
gsettings set org.gnome.desktop.app-folders.folder:/org/gnome/desktop/app-folders/folders/Office/ name "Office"
gsettings set org.gnome.desktop.app-folders.folder:/org/gnome/desktop/app-folders/folders/VirtualBox/ name "VirtualBox"
# 指定文件夹包含的应用类别
gsettings set org.gnome.desktop.app-folders.folder:/org/gnome/desktop/app-folders/folders/Office/ categories "['Office']"
gsettings set org.gnome.desktop.app-folders.folder:/org/gnome/desktop/app-folders/folders/VirtualBox/ categories "['Emulator']"
```
# 快捷键
```bash
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 "[]"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-last "[]"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-up "['<Super>Up']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-down "['<Super>Down']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Super>Left']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right "['<Super>Right']"
gsettings set org.gnome.desktop.wm.keybindings switch-applications "[]"
gsettings set org.gnome.desktop.wm.keybindings switch-applications-backward "[]"
gsettings set org.gnome.desktop.wm.keybindings switch-windows "['<Alt>Tab']"
gsettings set org.gnome.desktop.wm.keybindings switch-windows-backward "['<Shift><Alt>Tab']"
gsettings set org.gnome.shell.window-switcher current-workspace-only true
gsettings set org.gnome.shell.window-switcher app-icon-mode both
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-down "['<Alt><Super>Down']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-up "['<Alt><Super>Up']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-last "[]"
gsettings set org.gnome.desktop.wm.keybindings move-to-monitor-up "[]"
gsettings set org.gnome.desktop.wm.keybindings move-to-monitor-right "[]"
gsettings set org.gnome.desktop.wm.keybindings move-to-monitor-left "[]"
gsettings set org.gnome.desktop.wm.keybindings move-to-monitor-down "[]"
gsettings set org.gnome.desktop.wm.keybindings show-desktop "['<Super>d']"
gsettings set org.gnome.desktop.wm.keybindings toggle-maximized "['<Primary><Super>Up']"
gsettings set org.gnome.desktop.wm.keybindings minimize "['<Primary><Super>Down']"
gsettings set org.gnome.desktop.wm.keybindings maximize "[]"
```
# 在 CentOS6 下安装 gnome 桌面
```bash
yum groupinstall 'X Window System'
yum groupinstall Desktop
sed -i '/^id/id:5:initdefault:' /etc/inittab
```
# 在 CentOS7 下安装 gnome3 桌面
```bash
yum groupinstall 'X Window System'
yum groupinstall 'Gnome Desktop'
systemctl set-default graphical.target
systemctl enable gdm
# 创建一个可登陆的普通用户
```
# 在 gdm 中隐藏用户名
- 修改文件/etc/gdm/gdm.schemas找到这一段
```xml
<schema>
<key>greeter/Exclude</key>
<signature>s</signature>
<default>bin,root, daemon,adm,lp,sync,shutdown,halt,mail,news,uucp,operator,
nobody,nobody4,noaccess,postgres,pvm,rpm,nfsnobody,pcap</default>
</schema>
```
- 将用户名添加在<default></default>之间即可,用逗号隔开,保存退出即可。

92
content/post/grub.md Normal file
View File

@ -0,0 +1,92 @@
---
title: "Grub 笔记"
date: 2019-10-30T17:39:58+08:00
lastmod: 2019-10-30T17:39:58+08:00
tags: ["grub"]
categories: ["OS"]
---
# 启动 archlinux 镜像 64位系统
```
menuentry "Archlinux-ISO-x86-64" --class iso {
set isofile=""
set partition=""
loopback loop (hd0,$partition)$isofile
linux (loop)/arch/boot/x86_64/vmlinuz archisolabel=ARCH_ISO_X86-64 img_dev=/dev/sda$partition img_loop=$isofile earlymodules=loop
initrd (loop)/arch/boot/x86_64/archiso.img
}
```
# 启动 archlinux 镜像 32位系统
```bash
menuentry "Archlinux-ISO-i686" --class iso {
set isofile=""
set partition="2"
loopback loop (hd0,$partition)$isofile
linux (loop)/arch/boot/i686/vmlinuz archisolabel=ARCH_ISO_I686 img_dev=/dev/sda$partition img_loop=$isofile earlymodules=loop
initrd (loop)/arch/boot/i686/archiso.img
}
```
# 启动 ubuntu 镜像
```bash
menuentry "ubuntu-ISO" {
set isofile=""
loopback loop (hd0,1)$isofile
linux (loop)/casper/vmlinuz.efi boot=casper iso-scan/filename=$isofile quiet noeject noprompt splash --
initrd (loop)/casper/initrd.lz
}
```
# 启动安装在第一块硬盘第一个mbr分区的 win7 系统
```bash
menuentry "Microsoft Windows Vista/7/8/8.1/10 BIOS-MBR" {
insmod part_msdos
insmod ntfs
insmod search_fs_uuid
insmod ntldr
#"9AB0287EB028634D" 是 win7 系统分区的 uuid
search --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 9AB0287EB028634D
ntldr /bootmgr
}
```
# 启动安装在第一块硬盘的第一个gpt分区的 Win10 EFI
```bash
menuentry "Microsoft Windows 10" {
insmod part_gpt
insmod fat
insmod search_fs_uuid
insmod chain
#"0007-C871" 是 win10 EFI 分区的 uuid
search --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1 0007-C871
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
```
# 关机
```bash
menuentry "System shutdown" {
echo "System shutting down..."
halt
}
```
# 重启
```bash
menuentry "System restart" {
echo "System rebooting..."
reboot
}
```
# UEFI 配置
```bash
menuentry "Firmware setup" {
fwsetup
}
```
# 详细使用参考
- [GRUB-ArchWiki](https://wiki.archlinux.org/index.php/GRUB)

175
content/post/haproxy.md Normal file
View File

@ -0,0 +1,175 @@
---
title: "Haproxy 笔记"
date: 2019-10-30T11:40:20+08:00
lastmod: 2019-10-30T11:40:20+08:00
tags: ["haproxy", "高可用", "负载均衡"]
categories: ["ha/lb"]
---
# CentOS7 下安装
- CentOS7 自带的 haproxy 版本太低,这里通过 cheese 源安装最新版本
- 安装 cheese repo详细参考[这里](http://www.nosuchhost.net/~cheese/fedora/packages/epel-7/x86_64/cheese-release.html)
```bash
wget http://www.nosuchhost.net/~cheese/fedora/packages/epel-7/x86_64/cheese-release-7-1.noarch.rpm
rpm -Uvh cheese-release-7-1.noarch.rpm
```
- 安装 haproxy
```bash
yum install haproxy
```
- 修改 sysctl.conf
```bash
cat >> /etc/sysctl.conf <<-END
net.ipv4.ip_forward=1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 8
END
sysctl -p
```
- 禁用 selinux
```bash
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
setenforce 0
```
# 全局配置
```
global
log 127.0.0.1 local2 info
chroot /var/lib/haproxy # 如果需要外部检查脚本,则需注释该行
#external-check # 如果需要外部检查脚本,则取消注释
pidfile /var/run/haproxy.pid
maxconn 102400
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
```
# 默认配置
```
defaults
log global
option dontlognull
option redispatch
option abortonclose
timeout check 8s
```
# tcp 连接多个 ceph-radosgw
```
frontend ceph-radosgw
bind *:7480
timeout client 8s
default_backend ceph-radosgw
backend ceph-radosgw
mode tcp
balance roundrobin
timeout connect 8s
timeout server 8s
retries 2
#option external-check
#external-check command /var/lib/haproxy/health_check.sh
server cpeh240 10.9.10.234:7480 check
server ceph241 10.9.10.235:7480 check
server ceph243 10.9.10.236:7480 check
```
# tcp 连接 mysql galera cluster
```
frontend mysql
bind *:3306
timeout client 1800s
default_backend mysql
backend mysql
balance source
option tcpka
timeout connect 8s
timeout server 1800s
retries 2
server mysql231 10.9.10.231:3306 check inter 4s
server mysql232 10.9.10.232:3306 check inter 4s
server mysql233 10.9.10.233:3306 check inter 4s
```
# tcp 连接 redis 主库
```
frontend redis
bind *:6379
timeout client 1800s
default_backend redis
backend redis
balance roundrobin
timeout connect 8s
timeout server 1800s
retries 2
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis87 10.1.14.87:6379 check inter 4s
server redis88 10.1.14.88:6379 check inter 4s
server redis89 10.1.14.89:6379 check inter 4s
```
# 状态页面
```
listen admin_stats
bind 0.0.0.0:10080
mode http
maxconn 100
timeout client 1m
timeout connect 4s
timeout server 4s
stats refresh 30s
stats uri /
stats auth username:password
stats realm haproxy for private user, enter username/password
stats hide-version
```
# 通过 rsyslog 生成日志
```bash
sed -i -e '/ModLoad imudp/s/^#//' \
-e '/UDPServerRun 514/s/^#//' /etc/rsyslog.conf
cat > /etc/rsyslog.d/haproxy.conf <<EOF
# haproxy log
template(name="HaproxyTime" type="list"){
property(name="timereported" dateformat="year")
constant(value="-")
property(name="timereported" dateformat="month")
constant(value="-")
property(name="timereported" dateformat="day")
constant(value=" ")
property(name="timereported" dateformat="hour")
constant(value=":")
property(name="timereported" dateformat="minute")
constant(value=":")
property(name="timereported" dateformat="second")
constant(value=" ")
property(name="msg" droplastlf="on")
constant(value="\n")
}
template(name="DynFile" type="list"){
constant(value="/var/log/haproxy/haproxy-")
property(name="timereported" dateformat="year")
property(name="timereported" dateformat="month")
property(name="timereported" dateformat="day")
constant(value=".log")
}
local2.* action(type="omfile" dynaFile="DynFile" template="HaproxyTime")
EOF
systemctl restart rsyslog
systemctl restart haproxy
```
# 参考
- [详解地址](http://blog.haohtml.com/archives/7959)
- [官网](https://www.haproxy.com/documentation/hapee/1-5r2/traffic-management/health-checking/)

1055
content/post/hcnp.md Normal file

File diff suppressed because it is too large Load Diff

65
content/post/httpd.md Normal file
View File

@ -0,0 +1,65 @@
---
title: "Httpd 笔记"
date: 2019-10-30T11:28:36+08:00
lastmod: 2019-10-30T11:28:36+08:00
tags: ["httpd"]
categories: ["web"]
---
# CentOS7 安装
```bash
yum install httpd
```
# 支持 SVN
- 安装 svn 模块
```bash
yum install mod_dav_svn subversion
```
- 建立 svn 库 test_prj
```bash
mkdir -p /mnt/vdb1/svn_repos/test_prj
svnadmin create /mnt/vdb1/svn_repos/test_prj
```
- 编辑 test_prj 下 conf 目录中的 authz 和 passwd 文件,配置权限
- 启动 svn
```bash
svnserve -d -r /mnt/vdb1/svn_repos/
#客户端测试
svn checkout svn://{ip}/test_prj
```
- 编辑 /etc/httpd/conf.modules.d/10-subversion.conf追加如下
```xml
<Location /test_prj/>
DAV svn
SVNListParentPath off
SVNPath /mnt/vdb1/svn_repos/test_prj/
#Satisfy Any
AuthzSVNAccessFile /mnt/vdb1/svn_repos/test_prj/conf/authz
Require valid-user
</Location>
```
- 增加 apache 用户读写 test_prj 目录的权限
```bash
usermod -a -G root apache
chmod -R g+w /mnt/vdb1/svn_repos/
```
- 重启 httpd 服务
```bash
systemctl restart httpd
```
# Basic HTTP 认证
- 生成密码文件(用户名是admin密码是123456)
```bash
htpasswd -c -m /etc/httpd/httpd.auth admin # 按提示输入密码
```
- 在 Location 中配置如下
```xml
<Location />
AuthType Basic
AuthName "提示信息"
AuthUserFile /etc/httpd/httpd.auth
</Location>
```

33
content/post/ip.md Normal file
View File

@ -0,0 +1,33 @@
---
title: "IP 地址分类及内网 IP"
date: 2019-10-29T18:49:31+08:00
lastmod: 2019-10-29T18:49:31+08:00
keywords: []
description: ""
tags: ["ip"]
categories: ["network"]
---
# 私有 IP
- A类: 10.0.0.110.255.255.254
- B类: 172.16.0.1172.31.255.254
- C类: 192.168.0.1192.168.255.254
# 地址分类
- A类: 一个A类IP地址仅使用第一个8位位组表示网络地址。剩下的3个8位位组表示主机地址。A类地址的第一个位总为0这一点在数学上限制了A类地址的范围小于 127,127是64+32+16+8+4+2+1的和。最左边位表示128在这里空缺。因此仅有127个可能的A类网络。A类地址后面的24位(3个点-十进制数)表示可能的主机地址A类网络地址的范围从1.0.0.0到126.0.0.0。注意只有第一个8位位组表示网络地址剩余的3个8位位组用于表示第一个8位位组所表示网络中惟一的主机地址当用于描述网络时这些位置为0。注意技术上讲127.0.0.0 也是一个A类地址但是它已被保留作闭环look back 测试之用而不能分配给一个网络。每一个A类地址能支持16777214个不同的主机地址这个数是由2的24次方再减去2得到的。减2是必要的因为 IP把全0保留为表示网络而全1表示网络内的广播地址。其中10.0.0.0 至10.255.255.255保留,作为局域网地址使用。
- B类: 设计B类地址的目的是支持中到大型的网络。B类网络地址范围从128.1.0.0到191.254.0.0。B 类地址蕴含的数学逻辑是相当简单的。一个B类IP地址使用两个8位位组表示网络号另外两个8位位组表示主机号。B类地址的第1个8位位组的前两位总置为 10剩下的6位既可以是0也可以是1这样就限制其范围小于等于191由128+32+16+8+4+2+1得到。最后的16位( 2个8位位组)标识可能的主机地址。每一个B类地址能支持64534 个惟一的主机地址这个数由2的16次方减2得到。B类网络仅有16382个。其中172.16.0.0至172.31.255.255保留作为局域网地址使用。
- C类: C类地址用于支持大量的小型网络。这类地址可以认为与A类地址正好相反。A类地址使用第一个8位位组表示网络号剩下的3个表示主机号而C类地址使用三个8位位组表示网络地址仅用一个8位位组表示主机号。C类地址的前3位数为110前两位和为192(128+64)这形成了C类地址空间的下界。第三位等于十进制数32,这一位为0限制了地址空间的上界。不能使用第三位限制了此8位位组的最大值为255-32等于223。因此C类网络地址范围从 192.0.1.0 至223.255.254.0。最后一个8位位组用于主机寻址。每一个C类地址理论上可支持最大256个主机地址(0255)但是仅有254个可用因为0和255不是有效的主机地址。可以有2097150个不同的C类网络地址。其中192.168.0.0至192.168.255.255保留作为局域网地址使用。
- D类: D类地址用于在IP网络中的组播( multicasting ,又称为多目广播)。D类地址的前4位恒为1110 预置前3位为1意味着D类地址开始于128+64+32等于224。第4位为0意味着D类地址的最大值为128+64+32+8+4+2+1为239因此D类地址空间的范围从224.0.0.0到239. 255. 255.254。
- E类: E类地址保留作研究之用。因此Internet上没有可用的E类地址。E类地址的前4位恒为1因此有效的地址范围从240.0.0.0 至255.255.255.255。
- 总的来说ip地址分类由第一个八位组的值来确定。任何一个0到127 间的网络地址均是一个A类地址。任何一个128到191间的网络地址是一个B类地址。任何一个192到223 间的网络地址是一个C类地址。任何一个第一个八位组在224到239 间的网络地址是一个组播地址即D类地址。E类保留。
# 特殊 IP
- 127.0.0.0: 127是一个保留地址该地址是指电脑本身主要作用是预留下作为测试使用用于网络软件测试以及本地机进程间通 信。在Windows系统下该地址还有一个别名叫“localhost”无论是哪个程序一旦使用该地址发送数据协议软件会立即返回不进行任何网 络传输,除非出错,包含该网络号的分组是不能够出现在任何网络上的。
- 10.x.x.x、172.16.x.x172.31.x.x、192.168.x.x: 私有地址这些地址被大量用于企业内部网络中。一些宽带路由器也往往使用192.168.1.1作为缺省地址。私有网络由于不与外部互连,因而可能使 用随意的IP地址。保留这样的地址供其使用是为了避免以后接入公网时引起地址混乱。使用私有地址的私有网络在接入Internet时要使用地址翻译 (nat)将私有地址翻译成公用合法地址。在Internet上这类地址是不能出现的。
- 0.0.0.0: 严格意义上来 说0.0.0.0已经不是真正意义上的IP地址了。它表示的是这样一个集合所有不清楚的主机和目的网络。这里的不清楚是指在本机的路由表里没有特定条 目指明如何到达。对本机来说它就是一个收容所所有不认识的三无人员一律送进去。如果你在网络设置中设置了缺省网关那么Windows系统就会自动 产生一个目地址为0.0.0.0的缺省路由。若IP地址全为0也就是0.0.0.0则这个IP地址在IP数据报中只能用作源IP地址这发生在当设备启动时但又不知道自己的IP地址情况下。在使 用DHCP分配IP地址的网络环境中这样的地址是很常见的。用户主机为了获得一个可用的IP地址就给DHCP服务器发送IP分组并用这样的地址作为 源地址目的地址为255.255.255.255因为主机这时还不知道DHCP服务器的IP地址
- 255.255.255.255: 受限制的广播地址,对本机来说,这个地址指本网段内(同一 个广播域)的所有主机该地址用于主机配置过程中IP数据包的目的地址这时主机可能还不知道它所在网络的网络掩码甚至连它的IP地址也还不知道。在任 何情况下,路由器都会禁止转发目的地址为受限的广播地址的数据包,这样的数据包仅会出现在本地网络中。
- 224.0.0.1: 组播地址注意它和广播的区别。从224.0.0.0到239.255.255.255都是这样的地址。224.0.0.1特指所有主 机224.0.0.2特指所有路由器。这样的地址多用于一些特定的程序以及多媒体程序。如果你的主机开启了IRDP(Internet路由发现协议使 用组播功能)功能,那么你的主机路由表中应该有这样一条路由。
- 169.254.*.*: 如果你的主机使用了DHCP功能自动获 得一个IP地址那么当你的DHCP服务器发生故障或响应时间太长而超出系统规定的一个时间Windows系统会为你分配这样一个地址。如果你发现你的 主机IP地址是个诸如此类的地址很不幸十有八九是你的网络不能正常运行了。
- 直接广播地址: 一个网络中的最后一个地址为直接广播地址也就是HostID全为1的地址。主机使用这种地址把一个IP数据报发送到本地网段的所有设备上路由器会转发这种数据报到特定网络上的所有主机。**注意这个地址在IP数据报中只能作为目的地址。另外直接广播地址使一个网段中可分配给设备的地址数减少了1个**。
- NetID为0的IP地址: 当某个主机向同一网段上的其他主机发送报文时就可以使用这样的地址分组也不会被路由器转发。比如12.12.12.0/24这个网络中的一台主机12.12.12.2/24在与同一网络中的另一台主机12.12.12.8/24通信时目的地址可以是0.0.0.8。

32
content/post/ipv6.md Normal file
View File

@ -0,0 +1,32 @@
---
title: "Ipv6 笔记"
date: 2019-10-29T21:07:06+08:00
lastmod: 2019-10-29T21:07:06+08:00
keywords: []
tags: ["ipv6", "centos"]
categories: ["network"]
---
# CentOS7 禁用 ipv6
## 方法1
- 编辑 /etc/sysctl.conf增加如下内容
```
net.ipv6.conf.all.disable_ipv6 =1
net.ipv6.conf.default.disable_ipv6 =1
```
- 如果你想要为特定的网卡禁止IPv6比如对于enp0s3添加下面的行
```
net.ipv6.conf.enp0s3.disable_ipv6 =1
```
- 生效
```bash
sysctl -p
```
## 方法2
- 执行下面命令
```bash
echo 1>/proc/sys/net/ipv6/conf/all/disable_ipv6
echo 1>/proc/sys/net/ipv6/conf/default/disable_ipv6
```

159
content/post/k3s-install.md Normal file
View File

@ -0,0 +1,159 @@
---
title: "CentOS7 安装 K3S"
date: 2020-09-25T14:21:00+08:00
lastmod: 2020-09-25T14:21:00+08:00
keywords: []
tags: ["rancher", "k3s"]
categories: ["container"]
---
# 环境
角色 | 主机名 | 操作系统 | 软件
---- | ---- | ---- | ----
数据库 | - | - | docker-ce 19.03
k3s server | k3s-server0 | CentOS7.8 | docker-ce 19.03, k3s v1.18.9
k3s server | k3s-server1 | CentOS7.8 | docker-ce 19.03, k3s v1.18.9
k3s agent | k3s-agent0 | CentOS7.8 | docker-ce 19.03, k3s v1.18.9
k3s agent | k3s-agent1 | CentOS7.8 | docker-ce 19.03, k3s v1.18.9
- **全部服务器关闭 firewalld、selinux 和 swap设置时间同步**
- **全部 k3s 服务器(除了数据库)必须设置唯一主机名**
# 安装数据库
- 在数据库服务器上执行如下操作
- 启动 docker 容器
```bash
docker run -d \
--name mariadb \
-p 3306:3306 \
-v /data/mariadb/binlog:/var/lib/mysql-bin \
-v /data/mariadb/db:/var/lib/mysql \
-v /data/mariadb/log:/var/log/mysql \
harbor.colben.cn/general/alpine-mariadb
```
- 创建 k3s 数据库
```bash
docker exec mariadb mysql -e "
CREATE DATABASE k3s DEFAULT CHARSET UTF8MB4;
CREATE USER k3s@'%' IDENTIFIED BY 'Password_1234';
GRANT ALL ON k3s.* TO k3s@'%';
FLUSH PRIVILEGES;
"
```
- 生产环境建议配置 mysql 主从高可用,参考[MariaDB 主从复制](/post/mariadb-replication/)
# 安装 k3s server
- 在每台 k3s server 服务器上执行如下操作
- 下载并安装 k3s
```bash
cd /usr/local/bin/
curl -LO https://github.com/rancher/k3s/releases/download/v1.18.9%2Bk3s1/k3s
chmod 0755 k3s
ln -s k3s kubectl
```
- 创建 systemd 服务文件 /etc/systemd/system/k3s-server.service内容如下
```ini
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
KillMode=process
Delegate=yes
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
SuccessExitStatus=1
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
server \
--docker \
--datastore-endpoint 'mysql://k3s:Password_1234@tcp({mysql 地址}:{mysql 端口})/k3s' \
--disable 'coredns,servicelb,traefik,local-storage,metrics-server' \
--pause-image 'harbor.colben.cn/k3s/pause:3.2'
```
- 重载 systemd 系统服务,启动 k3s-server 服务
```bash
systemctl daemon-reload
systemctl start k3s-server
```
- 获取 token 信息(同一集群内各 server 上该文件完全一样),该信息用于 agent 连接
```bash
cat /var/lib/rancher/k3s/server/token
```
- 多个 k3s-server 服务可通过 keepalived 配置高可用,参考[keepalived 笔记](/post/keepalived/)
# 安装 k3s agent
- 在每台 k3s agent 服务器上执行如下操作
- 下载并安装 k3s
```bash
cd /usr/local/bin/
curl -LO https://github.com/rancher/k3s/releases/download/v1.18.9%2Bk3s1/k3s
chmod 0755 k3s
```
- 创建 systemd 服务文件 /etc/systemd/system/k3s-agent.service内容如下
```ini
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
KillMode=process
Delegate=yes
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
SuccessExitStatus=1
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
agent \
--docker \
--server 'https://{任一 server 地址或 server 高可用地址}:6443' \
--pause-image 'harbor.boyachain.cn:20443/k3s/pause:3.2' \
--token '{server token 信息}'
```
- 重载 systemd 系统服务,启动 k3s-agent 服务
```bash
systemctl daemon-reload
systemctl start k3s-agent
```
# 查看节点信息
- 在任一 k3s server 服务器上执行如下操作
- 查看节点信息
```bash
kubectl get nodes
```
# 注意事项
- k3s 内部 ssl 证书有效期一年,可在到期前重启 k3s 集群轮换证书

276
content/post/k8s-coredns.md Normal file
View File

@ -0,0 +1,276 @@
---
title: "K8s 部署 Coredns 组件"
date: 2019-10-30T01:06:56+08:00
lastmod: 2020-02-10T14:36:00+08:00
keywords: []
tags: ["kubernetes", "k8s", "coredns"]
categories: ["container"]
---
# 环境
- [二进制部署的 kubernetes v1.17.2 集群](https://colben.cn/post/k8s-install/)
- coreDNS 1.6.6
# 生成 service account 文件
- 创建 0.coredns-sa.yml
```bash
cat > 0.coredns-sa.yml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system
EOF
```
# 生成 rbac 文件
- 创建 1.coredns-rbac.yml
```bash
curl > 1.coredns-rbac.yml <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
rules:
- apiGroups:
- ""
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
- kind: ServiceAccount
name: coredns
namespace: kube-system
EOF
```
# 生成 configmap 文件
- 创建 2.coredns-configmap.yml
```bash
cat > 2.coredns-configmap.yml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local 10.10.9.0/24 {
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
EOF
```
- 这里的 10.10.9.0/24 应与 kube-apiserver 配置文件中的 service-cluster-ip-range 一致
- 这里的 cluster.local 应与 kubelet 配置文件中的 clusterDomain 一致
# 生成 deployment 文件
- 创建 3.coredns-deployment.yml
```bash
cat > 3.coredns-deployment.yml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/name: "CoreDNS"
spec:
# replicas: not specified here:
# 1. Default is 1.
# 2. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
priorityClassName: system-cluster-critical
serviceAccountName: coredns
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
nodeSelector:
beta.kubernetes.io/os: linux
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values: ["kube-dns"]
topologyKey: kubernetes.io/hostname
containers:
- name: coredns
image: coredns/coredns:1.6.6
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
args: [ "-conf", "/etc/coredns/Corefile" ]
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- all
readOnlyRootFilesystem: true
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
dnsPolicy: Default
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
EOF
```
- coredns/coredns:1.2.2 该镜像可以提前导入本地局域网中的私有 docker 仓库中
- 查看 k8s 对应的 coredns 版本,参考 [coredns](https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md)
# 生成 service 文件
- 创建 4.coredns-service.yml
```bash
cat > 4.coredns-service.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "CoreDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.10.9.2
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
- name: metrics
port: 9153
protocol: TCP
EOF
```
- 这里的 clusterIP 需与 kubelet 配置文件中的 clusterDNS 一致
# 部署到 kubernetes 中
- 使用 kubectl 直接应用
```bash
kubectl apply -f 0.coredns-sa.yml
kubectl apply -f 1.coredns-rbac.yml
kubectl apply -f 2.coredns-configmap.yml
kubectl apply -f 3.coredns-deployment.yml
kubectl apply -f 4.coredns-service.yml
```
# 查看 coredns 状态
- 查看 service 状态
```bash
kubectl get svc -n kube-system
```
- service 地址应是之前指定的 clusterIP(10.10.9.2)
- 查看 coredns pods 状态
```bash
kubectl get pods -n kube-system
```
- 正常时都是 running
- 查看 coredns pods 输出
```bash
kubectl logs <pod_name> -n kube-system
```
# 参考
- [coredns 部署](https://github.com/coredns/deployment/tree/master/kubernetes)

832
content/post/k8s-install.md Normal file
View File

@ -0,0 +1,832 @@
---
title: "K8s 二进制安装"
date: 2019-10-30T01:09:48+08:00
lastmod: 2020-02-03T11:43:30+08:00
keywords: []
tags: ["kubernetes", "k8s", "二进制"]
categories: ["container"]
---
# 环境
角色 | 主机名 | 内网 IP | 集群 IP | 操作系统 | 服务 | 执行目录
---- | ---- | ---- | ---- | ---- | ---- | ----
部署机 k8s-master | master120 | 10.0.4.120 | - | CentOS | kube-apiserver kube-scheduler kube-controller-manager | /opt/kubernetes/
etcd-node | etcd121 | 10.0.4.121 | 10.10.10.121 | CentOS | etcd | /opt/etcd/
etcd-node | etcd122 | 10.0.4.122 | 10.10.10.122 | CentOS | etcd | /opt/etcd/
etcd-node | etcd123 | 10.0.4.123 | 10.10.10.123 | CentOS | etcd | /opt/etcd/
k8s-node | node124 | 10.0.4.124 | - | CentOS | docker flannel kubelet kube-proxy | /opt/kubernetes/
k8s-node | node125 | 10.0.4.125 | - | CentOS | docker flannel kubelet kube-proxy | /opt/kubernetes/
k8s-node | node126 | 10.0.4.126 | - | CentOS | docker flannel kubelet kube-proxy | /opt/kubernetes/
- 全部服务器关闭 firewalld 和 selinux禁用 swap部署机(master120)可免密 ssh 登陆其他服务器
- 软件版本
- CentOS: 7.7
- etcd: 3.3.18
- docker: ce-19.03.5
- flannel: 0.11.0
- kubernetes: 1.17.2
- k8s牵扯到多个网段这里说明下
- 10.0.4.0/24 该网段是服务器物理网卡 IP 地址段,通过该地址访问互联网
- 10.10.10.0/24 该网段是杜撰的,但也配置在服务器物理网卡上,用于 etcd 集群节点间通信,与 k8s 集群无关
- 10.10.9.0/24 该网段是杜撰的,分配 k8s service 的 clusterIP
- 172.17.0.0/24 该网段是杜撰的,是 docker 网桥自带网段,也是 flannel 提供的网段,实现不同节点间的容器互通
- 172.16.0.0/24 该网段是杜撰的,是 k8s pod 的 IP 地址区间,用于区别流量来源
# 部署 etcd 集群
- 在部署机(master120)上操作下面步骤
- 创建 etcd 部署目录
```bash
mkdir /home/deploy/etcd/{bin,cfg,ssl} -p
mkdir /home/deploy/ssl/etcd -p
```
- 安装 cfssl 工具
```bash
curl -o /usr/local/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
curl -o /usr/local/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
curl -o /usr/local/bin/cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod 0755 /usr/local/bin/cfssl*
```
- 创建 ca-config.json 文件
```bash
cat > /home/deploy/ssl/etcd/ca-config.json <<< '
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"etcd": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
'
```
- 创建 ca-csr.json 文件
```bash
cat > /home/deploy/ssl/etcd/ca-csr.json <<< '
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
'
```
- 创建 server-csr.json 文件
```bash
# 注意修改 "10.0.4.*" 和 "10.10.10.*" 为自己环境地址
cat > /home/deploy/ssl/etcd/server-csr.json <<< '
{
"CN": "etcd",
"hosts": [
"10.0.4.121",
"10.0.4.122",
"10.0.4.123",
"10.10.10.121",
"10.10.10.122",
"10.10.10.123",
"127.0.0.1"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
}
]
}
'
```
- 生成证书
```bash
cd /home/deploy/ssl/etcd/
# 生成 ca.pem ca-key.pem
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
# 生成 server.pem server-key.pem
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=etcd \
server-csr.json | cfssljson -bare server
# 复制证书到部署目录
scp *.pem /home/deploy/etcd/ssl/
```
- 下载 etcd 二进制包
```bash
cd /home/deploy/
curl -L -O https://github.com/etcd-io/etcd/releases/download/v3.3.18/etcd-v3.3.18-linux-amd64.tar.gz
tar zxf etcd-v3.3.18-linux-amd64.tar.gz
scp etcd-v3.3.18-linux-amd64/{etcd,etcdctl} etcd/bin/
```
- 创建 etcd 配置文件
```bash
# 这里的 etcd 虚拟机都有两个网卡,一个用于提供服务,另一个用于集群通信
# 注意修改 "10.0.4.*" 和 "10.10.10.*" 为自己环境地址
cat > /home/deploy/etcd/cfg/etcd <<<'
# [Member]
ETCD_NAME="etcdXXX"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://10.10.10.XXX:2380"
ETCD_LISTEN_CLIENT_URLS="https://10.0.4.XXX:2379"
# [Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://10.10.10.XXX:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://10.0.4.XXX:2379"
ETCD_INITIAL_CLUSTER="etcd121=https://10.10.10.121:2380,etcd122=https://10.10.10.122:2380,etcd123=https://10.10.10.123:2380"
ETCD_INITIAL_CLUSTER_TOKEN="fucking-etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
'
```
- 创建 etcd.service
```bash
cat > /home/deploy/etcd.service <<<'
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=/opt/etcd/cfg/etcd
ExecStart=/opt/etcd/bin/etcd \
--name=${ETCD_NAME} \
--data-dir=${ETCD_DATA_DIR} \
--listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
--advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--initial-cluster=${ETCD_INITIAL_CLUSTER} \
--initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \
--initial-cluster-state=${ETCD_INITIAL_CLUSTER_STATE} \
--cert-file=/opt/etcd/ssl/server.pem \
--key-file=/opt/etcd/ssl/server-key.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem \
--peer-key-file=/opt/etcd/ssl/server-key.pem \
--trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/opt/etcd/ssl/ca.pem
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
'
```
- 部署到远程三个 etcd 节点(etcd121、etcd122、etcd123)
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
cd /home/deploy
for id in $(seq 121 123); do
ip="10.0.4.$id"
scp -r etcd $ip:/opt/
ssh $ip "sed -i 's/XXX/$id/g' /opt/etcd/cfg/etcd"
scp etcd.service $ip:/usr/lib/systemd/system/
systemctl -H $ip daemon-reload
systemctl -H $ip enable etcd
done
```
- 启动三个 etcd 节点的 etcd 服务
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
for ip in $(seq -f'10.0.4.%g' 121 123); do
systemctl -H $ip start etcd
done
```
- 查看 etcd 集群状态
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
cd /home/deploy/etcd/ssl
../bin/etcdctl \
--ca-file=ca.pem \
--cert-file=server.pem \
--key-file=server-key.pem \
--endpoints="https://10.0.4.121:2379" \
cluster-health
```
# 安装 Docker
- 在每个 k8s node 服务器(node124、node125、node126)上操作下面步骤
- 安装 docker-ce[参考这里](https://my.oschina.net/colben/blog/1505141#h1_2)
# 部署 Flannel 网络
- 在部署机(master120)上操作下面步骤
- 创建 flannel 部署目录
```bash
cd /home/deploy
mkdir flannel/{bin,cfg,ssl} -p
# 复制 etcd 证书到 flannel 证书目录下
rm -rf flannel/ssl/etcd && scp -r etcd/ssl flannel/ssl/etcd
```
- 连接 etcd写入预定义的子网段
```bash
# 这里的预定义字段是 "172.17.0.0/16",推荐用这个,与 docker 原生网段一致
# 注意修改 "10.0.4.*" 为自己环境地址
cd /home/deploy/etcd/ssl
../bin/etcdctl \
--ca-file=ca.pem \
--cert-file=server.pem \
--key-file=server-key.pem \
--endpoints="https://10.0.4.122:2379" \
set /coreos.com/network/config '{"Network": "172.17.0.0/16", "Backend": {"Type": "vxlan"}}'
```
- 获取 flannel 二进制包
```bash
cd /home/deploy
curl -L -O https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
tar zxf flannel-v0.11.0-linux-amd64.tar.gz
scp flanneld mk-docker-opts.sh flannel/bin/
```
- 创建 flannel 配置文件
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
cat > /home/deploy/flannel/cfg/flanneld <<< '
FLANNEL_OPTIONS=" \
--etcd-endpoints=https://10.0.4.121:2379,https://10.0.4.122:2379,https://10.0.4.123:2379 \
-etcd-cafile=/opt/kubernetes/ssl/etcd/ca.pem \
-etcd-certfile=/opt/kubernetes/ssl/etcd/server.pem \
-etcd-keyfile=/opt/kubernetes/ssl/etcd/server-key.pem \
"
'
```
- 创建 flanneld.service
```bash
cat > /home/deploy/flanneld.service <<< '
[Unit]
Description=Flanneld overlay address etcd agent
After=network-online.target network.target
Before=docker.service
[Service]
Type=notify
EnvironmentFile=/opt/kubernetes/cfg/flanneld
ExecStart=/opt/kubernetes/bin/flanneld --ip-masq $FLANNEL_OPTIONS
ExecStartPost=/opt/kubernetes/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/subnet.env
Restart=on-failure
[Install]
WantedBy=multi-user.target
'
```
- 修改 docker.service用于从指定的子网段启动 docker
```bash
# 关键在 "EnvironmentFile=/run/flannel/subnet.env"
# 该文件就是 flanneld 服务生成的 docker 参数
# 这里仅作记录,具体实现已移到下一步的部署脚本中
```
- 部署到远程三个 k8s node 节点(node124、node125、node126)
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
cd /home/deploy
for ip in $(seq -f'10.0.4.%g' 124 126); do
systemctl -H $ip stop docker
ssh $ip "mkdir /opt/kubernetes"
scp -r flannel/* $ip:/opt/kubernetes/
scp flanneld.service $ip:/usr/lib/systemd/system/
ssh $ip 'sed -i \
-e "/^Type/aEnvironmentFile=/run/flannel/subnet.env" \
-e "/^ExecStart/s/$/\$DOCKER_NETWORK_OPTIONS/" \
/usr/lib/systemd/system/docker.service \
'
systemctl -H $ip daemon-reload
systemctl -H $ip enable flanneld
done
```
- 启动三个 k8s node 节点的 flanneld 和 docker 服务
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
for ip in $(seq -f'10.0.4.%g' 124 126); do
systemctl -H $ip start flanneld
systemctl -H $ip start docker
done
```
- 启动完成后,不同节点的 docker0 网卡 ip 互通
# 部署 k8s master 节点
- 部署前确保前面的 etcd 集群、flannel 网络和 docker 都是正常的
- 在部署机(master120即当前节点)上操作下面步骤
- 创建 master 部署目录
```bash
cd /home/deploy
mkdir master/{bin,cfg,ssl} -p
mkdir ssl/master -p
# 复制 etcd 证书到 master 证书目录下
rm -rf master/ssl/etcd && scp -r etcd/ssl master/ssl/etcd
```
- 创建 ca-config.json 文件
```bash
cat > /home/deploy/ssl/master/ca-config.json <<< '
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
'
```
- 创建 ca-csr.json 文件
```bash
cat > /home/deploy/ssl/master/ca-csr.json <<< '
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
}
'
```
- 创建 kube-apiserver-csr.json 文件
```bash
# 这里的 10.10.9.1 是 kubernetes service 的集群地址
# 该地址默认是下文中的 service-cluster-ip-range 网段的第一个 ip
# dns 组件会用到
# 注意修改 "10.0.4.*" 为自己环境地址
cat > /home/deploy/ssl/master/kube-apiserver-csr.json <<< '
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"10.0.4.120",
"10.10.9.1",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
'
```
- 创建 kube-proxy-csr.json 文件
```bash
cat > /home/deploy/ssl/master/kube-proxy-csr.json <<< '
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
'
```
- 生成证书
```bash
cd /home/deploy/ssl/master
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-apiserver-csr.json | cfssljson -bare kube-apiserver
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
# 复制证书到部署目录
scp *.pem /home/deploy/master/ssl/
```
- 获取 kubernetes 二进制包
```bash
cd /home/deploy
curl -L -O https://dl.k8s.io/v1.17.2/kubernetes-server-linux-amd64.tar.gz
tar zxf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
scp kube-apiserver kube-scheduler kube-controller-manager kubectl /home/deploy/master/bin/
```
- 创建 token 文件
```bash
# 第一个字符串随机写的,看心情 ……
echo '1111222233334444aaaabbbbccccdddd,kubelet-bootstrap,10001,"system:kubelet-bootstrap"' > /home/deploy/master/cfg/token.csv
```
- 创建 kube-apiserver 配置文件
```bash
# 这里的 service-cluster-ip-range 是 k8s service 地址区间,提供一个与现有网络不通的网段
# 注意修改 "10.0.4.*" 为自己环境地址
cat > /home/deploy/master/cfg/kube-apiserver <<< '
KUBE_APISERVER_OPTS=" \
--logtostderr=true \
--v=4 \
--etcd-servers=https://10.0.4.121:2379,https://10.0.4.122:2379,https://10.0.4.123:2379 \
--bind-address=10.0.4.120 \
--secure-port=6443 \
--advertise-address=10.0.4.120 \
--allow-privileged=true \
--service-cluster-ip-range=10.10.9.0/24 \
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota,NodeRestriction \
--authorization-mode=RBAC,Node \
--enable-bootstrap-token-auth \
--token-auth-file=/opt/kubernetes/cfg/token.csv \
--service-node-port-range=30000-50000 \
--tls-cert-file=/opt/kubernetes/ssl/kube-apiserver.pem \
--tls-private-key-file=/opt/kubernetes/ssl/kube-apiserver-key.pem \
--client-ca-file=/opt/kubernetes/ssl/ca.pem \
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
--etcd-cafile=/opt/kubernetes/ssl/etcd/ca.pem \
--etcd-certfile=/opt/kubernetes/ssl/etcd/server.pem \
--etcd-keyfile=/opt/kubernetes/ssl/etcd/server-key.pem \
"
'
```
- 创建 kube-apiserver.service 文件
```bash
cat > /home/deploy/kube-apiserver.service <<< '
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-apiserver
ExecStart=/opt/kubernetes/bin/kube-apiserver $KUBE_APISERVER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
'
```
- 创建 kube-scheduler 配置文件
```bash
cat > /home/deploy/master/cfg/kube-scheduler <<< '
KUBE_SCHEDULER_OPTS=" \
--logtostderr=true \
--v=4 \
--master=127.0.0.1:8080 \
--leader-elect \
"
'
```
- 创建 kube-scheduler.service
```bash
cat > /home/deploy/kube-scheduler.service <<< '
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-scheduler
ExecStart=/opt/kubernetes/bin/kube-scheduler $KUBE_SCHEDULER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
'
```
- 创建 kube-controller-mananger 配置文件
```bash
# 注意这里设置了 cluster-name 为 "my_k8s_cluster"
# 这个名字在后面会用到
# 这里的 service-cluster-ip-range 是 k8s service 地址区间,与之前配置的网段相同
cat > /home/deploy/master/cfg/kube-controller-manager <<< '
KUBE_CONTROLLER_MANAGER_OPTS=" \
--logtostderr=true \
--v=4 \
--master=127.0.0.1:8080 \
--leader-elect=true \
--address=127.0.0.1 \
--service-cluster-ip-range=10.10.9.0/24 \
--cluster-name=my_k8s_cluster \
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \
--root-ca-file=/opt/kubernetes/ssl/ca.pem \
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \
"
'
```
- 创建 kube-controller-manager.service
```bash
cat > /home/deploy/kube-controller-manager.service <<< '
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-controller-manager
ExecStart=/opt/kubernetes/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
'
```
- 部署到执行目录
```bash
cd /home/deploy
mkdir /opt/kubernetes
scp -r master/* /opt/kubernetes/
scp kube-apiserver.service kube-scheduler.service kube-controller-manager.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable kube-apiserver kube-scheduler kube-controller-manager
ln -sf /opt/kubernetes/bin/kubectl /usr/local/bin/
```
- 启动 k8s master 各组件
```bash
systemctl start kube-apiserver
systemctl start kube-scheduler
systemctl start kube-controller-manager
```
- 查看集群各组件状态
```bash
kubectl get cs
```
# 部署 k8s node 节点
- 在部署机(master120)上操作下面步骤
- 创建 node 部署目录
```bash
cd /home/deploy
mkdir node/{bin,cfg,ssl} -p
scp kubernetes/server/bin/{kubelet,kube-proxy} node/bin/
```
- 将kubelet-bootstrap用户绑定到系统集群角色
```bash
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
```
- 生成 bootstrap.kubeconfig 文件
```bash
export BOOTSTRAP_TOKEN=1111222233334444aaaabbbbccccdddd
export KUBE_APISERVER="https://10.0.4.120:6443"
cd /home/deploy/master/ssl
# 设置集群参数,这里的指定的集群就是前面设置的 "my_k8s_cluster"
kubectl config set-cluster my_k8s_cluster \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=/home/deploy/node/cfg/bootstrap.kubeconfig
# 设置客户端认证参数
kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=/home/deploy/node/cfg/bootstrap.kubeconfig
# 设置上下文参数
kubectl config set-context default \
--cluster=my_k8s_cluster \
--user=kubelet-bootstrap \
--kubeconfig=/home/deploy/node/cfg/bootstrap.kubeconfig
# 设置默认上下文
kubectl config use-context default --kubeconfig=/home/deploy/node/cfg/bootstrap.kubeconfig
```
- 生成 kube-proxy.kubeconfig 文件
```bash
export KUBE_APISERVER="https://10.0.4.120:6443"
cd /home/deploy/master/ssl
# 设置集群参数,这里的指定的集群就是前面设置的 "my_k8s_cluster"
kubectl config set-cluster my_k8s_cluster \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=/home/deploy/node/cfg/kube-proxy.kubeconfig
kubectl config set-credentials kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=/home/deploy/node/cfg/kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=my_k8s_cluster \
--user=kube-proxy \
--kubeconfig=/home/deploy/node/cfg/kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=/home/deploy/node/cfg/kube-proxy.kubeconfig
```
- 创建 kubelet 配置文件
```bash
# --kubeconfig 指定 kubeconfig 文件位置,会自动生成
# --cert-dir 颁发证书待存放位置
# 注意修改 "10.0.4.*" 为自己环境地址
# 这里保留 "XXX",后面部署命令会统一替换
cat > /home/deploy/node/cfg/kubelet <<< '
KUBELET_OPTS=" \
--logtostderr=true \
--v=4 \
--hostname-override=10.0.4.XXX \
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
--config=/opt/kubernetes/cfg/kubelet.config \
--cert-dir=/opt/kubernetes/ssl \
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0 \
"
'
# registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0 该镜像可以提前导入本地局域网中的私有 docker 仓库中
```
- 创建 kubelet.config 配置文件
```bash
# 这里的 clusterDNS 是 DNS service 的集群地址,这里分配 10.10.9.2
# 注意修改 "10.0.4.*" 为自己环境地址
# 这里保留 "XXX",后面部署命令会统一替换
cat > /home/deploy/node/cfg/kubelet.config <<< '
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 10.0.4.XXX
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS: ["10.10.9.2"]
clusterDomain: cluster.local.
failSwapOn: false
authentication:
anonymous:
enabled: true
'
```
- 创建 kubelet.service
```bash
cat > /home/deploy/kubelet.service <<< '
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet
ExecStart=/opt/kubernetes/bin/kubelet $KUBELET_OPTS
Restart=on-failure
KillMode=process
[Install]
WantedBy=multi-user.target
'
```
- 创建 kube-proxy 配置文件
```bash
# 这里的 cluster-cidr 是 pod ip 地址区间
# 注意修改 "10.0.4.*" 为自己环境地址
# 这里保留 "XXX",后面部署命令会统一替换
cat > /home/deploy/node/cfg/kube-proxy <<< '
KUBE_PROXY_OPTS=" \
--logtostderr=true \
--v=4 \
--hostname-override=10.0.4.XXX \
--cluster-cidr=172.16.0.0/16 \
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig \
"
'
```
- 创建 kube-proxy.service
```bash
cat > /home/deploy/kube-proxy.service <<< '
[Unit]
Description=Kubernetes Proxy
After=network.target
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-proxy
ExecStart=/opt/kubernetes/bin/kube-proxy $KUBE_PROXY_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
'
```
- 部署到远程三个 k8s node 节点(node124、node125、node126)
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
cd /home/deploy
for id in $(seq 124 126); do
ip="10.0.4.$id"
scp -r node/* $ip:/opt/kubernetes/
ssh $ip "sed -i 's/XXX/$id/g' /opt/kubernetes/cfg/kubelet"
ssh $ip "sed -i 's/XXX/$id/g' /opt/kubernetes/cfg/kubelet.config"
ssh $ip "sed -i 's/XXX/$id/g' /opt/kubernetes/cfg/kube-proxy"
scp kubelet.service kube-proxy.service $ip:/usr/lib/systemd/system/
systemctl -H $ip daemon-reload
systemctl -H $ip enable kubelet kube-proxy
done
```
- 启动三个 k8s node 节点的 kubelet 和 kube-proxy 服务
```bash
# 注意修改 "10.0.4.*" 为自己环境地址
for ip in $(seq -f'10.0.4.%g' 124 126); do
systemctl -H $ip start kubelet
systemctl -H $ip start kube-proxy
done
```
- 审批 node 加入集群
```bash
kubectl get csr
# "XXXX" 上一命令输出的 NAME 列
kubectl certificate approve XXXX
kubectl get node
```
- 查看集群状态
```bash
kubectl get node
kubectl get cs
```
# 部署其他组件
- [coreDNS](https://colben.cn/post/k8s-coredns/)
# 运行一个测试示例
- 暂无

View File

@ -0,0 +1,104 @@
---
title: "CentOS7 安装 Kafka 集群"
date: 2019-10-30T01:22:25+08:00
lastmod: 2019-10-30T01:22:25+08:00
keywords: []
tags: ["kafka", "centos"]
categories: ["MQ"]
---
# 环境
主机名 | IP | 操作系统 | kafka 版本
---- | ---- | ---- | ----
kafka224 | 192.168.1.224 | CentOS7.5 | 2.12
kafka225 | 192.168.1.225 | CentOS7.5 | 2.12
kafka226 | 192.168.1.226 | CentOS7.5 | 2.12
- 下载 [kafka_2.12-2.1.0.tgz](http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.1.0/kafka_2.12-2.1.0.tgz)
- zookeeper 连接: 192.168.1.221:2181,192.168.1.222:2181,192.168.1.223:2181
# 各节点初始配置
- 关闭 selinux、防火墙
- 部署 java 运行环境
- 创建数据目录
```
mkdir -p /var/lib/kafka
```
- 创建日志目录
```
mkdir -p /var/log/kafka
```
# 部署 kafka
- 登陆 kafka224下载 kafka解压至 /opt/ 下
- 修改日志目录
```
cd /opt/kafka/
rm -rf logs && ln -s /var/log/kafka logs
```
- 修改 /opt/kafka/config/server.properties
```
broker.id=224
listeners=PLAINTEXT://192.168.1.224:9092
log.dirs=/var/lib/kafka
zookeeper.connect=192.168.1.221:2181,192.168.1.222:2181,192.168.1.223:2181
```
- 启动脚本(/opt/kafka/bin/kafka-server-start.sh)太繁琐,我精简了下
```bash
#!/bin/bash
base_dir=$(dirname $0)
if [ "x$KAFKA_LOG4J_OPTS" = "x" ]; then
export KAFKA_LOG4J_OPTS="-Dlog4j.configuration=file:$base_dir/../config/log4j.properties"
fi
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
# jvm 堆内存根据实际情况修改
export KAFKA_HEAP_OPTS="-Xmx2G -Xms2G"
# 开启 jmx
export JMX_PORT=1099
fi
EXTRA_ARGS=${EXTRA_ARGS-'-name kafkaServer -loggc'}
EXTRA_ARGS="-daemon "$EXTRA_ARGS
exec $base_dir/kafka-run-class.sh $EXTRA_ARGS kafka.Kafka "$base_dir/../config/server.properties"
```
- 打包 kafka 目录,复制到 kafka225 和 kafka226 上,并修改 server.properties
```
# kafka225
broker.id=225
listeners=PLAINTEXT://192.168.1.225:9092
# kafka226
broker.id=226
listeners=PLAINTEXT://192.168.1.226:9092
```
# 启动集群(两种启动方式)
- 直接启动二进制
- 在每个节点上启动 kafka 服务
```bash
/opt/kafka/bin/kafka-server-start.sh
```
- systemd 启动
- 创建 /usr/lib/systemd/system/kafka.service
```
[Unit]
Description=Kafka
Requires=network.service
After=network.service
[Service]
Environment=JAVA_HOME=/opt/jre
ExecStart=/opt/kafka/bin/kafka-server-start.sh
ExecStop=/opt/kafka/bin/kafka-server-stop.sh
Type=forking
KillMode=none
[Install]
WantedBy=multi-user.target
```
- 启动 kafka 服务
```bash
systemctl daemon-reload
systemctl start kafka
```

View File

@ -0,0 +1,195 @@
---
title: "Keepalived 基础"
date: 2019-10-30T11:26:18+08:00
lastmod: 2019-10-30T11:26:18+08:00
tags: ["keepalived"]
categories: ["ha/lb"]
---
# VRRP 简介
- VRRP通过一种竞选协议动态地将路由任务交给LAN中**虚拟路由器**中的某台**VRRP路由器**
- VRRP路由器是一台实现了VRRP协议(运行VRRPD程序)的物理路由器
- 虚拟路由器是由多台VRRP物理路由器组成的逻辑路由器对外看起来就像一台路由器
- 虚拟路由器中只有一台MASTER物理路由器工作其他都是BACKUP
- MASTER路由器一直发送VRRP广播MASTER不可用后(BACKUP收不到广播)其余BACKUP会根据优先级竞选出一台MASTER
- MASTER拥有虚拟路由器IP地址及其它路由配置
# 全局配置
- 全局定义
```
global_defs {
notification_email {
admin@exammple.com #keepalived发生事件时通知该email
...
}
notification_email_from admin@example.com
smtp_server 127.0.0.1 #smtp服务器
smtp_connect_timeout 30
router_id my_hostname #机器标识
default_interface eth0 #设置静态地址默认绑定的端口默认是eth0
vrrp_mcast_group4 #VRRP 的组播IPV4地址默认224.0.0.18
vrrp_mcast_group6 #VRRP 的组播IPV4地址默认ff02::12
vrrp_version 2|3 #设置默认的VRRP版本默认是2
script_user <username> [groupname] #设置运行脚本默认用户和组如果没有指定则默认用户为keepalived_script(需要该用户存在)否则为root用户默认groupname同username
enable_script_security #如果脚本路径的任一部分对于非root用户来说都具有可写权限则不会以root身份运行脚本
}
```
- 静态地址和路由,不随 vrrpd instance 的开/关变化
```
static_ipaddress {
$ip/$mask dev $interface #ip命令规则
...
}
static_routes {
$dest_ip/$dest_mask via $dest_gateway dev $interface #ip命令规则
...
}
```
- 一般服务器都配置了网络信息,所以通常无需配置静态地址和路由,如果不指定 dev则使用 default_interface
# VRRPD 配置
- VRRP检查脚本(vrrp_script)
```
vrrp_script <SCRIPT_NAME> {
scrip "/path/to/script-file" #可执行的脚本的绝对路径
interval <INTEGER> #脚本执行的间隔单位是秒默认为1s
timeout <INTEGER> #指定在多少秒后,脚本被认为执行失败
weight <-254 --- 254> #调整优先级默认为2
#如果脚本执行成功(退出状态码为0)weight大于0则priority增加
#如果脚本执行失败(退出状态码为非0)weight小于0则priority减少
#其他情况下priority不变
rise <INTEGER> #执行成功多少次才认为是成功
fall <INTEGER> #执行失败多少次才认为失败
user <USERNAME> [GROUPNAME] #运行脚本的用户和组
init_fail #假设脚本初始状态是失败状态
}
```
- VRRP同步组(sync group)
```
vrrp_sync_group VG_1 {
group {
inside_network #实例名
...
}
notify_master /path/to/master.sh #切换到master时执行该脚本
notify_backup /path/to/backup.sh #切换到backup时执行该脚本
notify_fault /path/to/fault.sh #出错时执行该脚本
notify /path/to/notify.sh #该脚本会在notify_*脚本后执行默认3个参数:$1(GROUP|INSTANCE),$2(group或instance名字),$3(MASTER|BACKUP|FAULT)
smtp_alert #发送邮件通知
}
```
- VRRP实例(instance)配置
```
vrrp_instance inside_network {
state MASTER #初始状态
interface eth0 #绑定的网卡
dont_track_primary #忽略VRRP的interface错误(默认不设置)
track_interface { #这里的任一网卡出现问题都会进入FAULT状态
eth0
eth1 weight <-254 - 254>
...
}
track_script { #这里的任一脚本返回码非0都会进入FAULT状态
<SCRIPT_NAME>
<SCRIPT_NAME> weight <-254-254>
...
}
mcast_src_ip <IPADDR> #多播包发送源地址默认网卡当前ip
garp_master_delay 10 #切换到MASTER后延迟arp请求
virtual_router_id 1 #VRID标记(0..255)
priority 100 #高优先级竞选为MASTERMASTER高于BACKUP至少50
advert_int 1 #检查间隔默认1秒
authentication {
auth_type PASS #密码认证
auth_pass 1111
}
virtual_ipaddress { #漂移地址符合ip命令规则
$vip/$vmask dev $interface
...
}
virtual_routes { #随地址一同漂移的路由符合ip命令规则
$dest_ip/$dest_mask via $dest_gateway dev $interface
...
}
nopreempt #BACKUP配置,且优先级比其他高
preempt_delay 300 #抢占延迟默认5分钟
debug #Debug级别
lvs_sync_daemon_interface #lvn syncd绑定的网卡
}
```
# LVS配置(不涉及lvs时无需下面配置)
- 虚拟主机组
```
virtual_server_group <STRING> {
#VIP VPORT
<IPADDR> <PORT>
<IPADDR> <PORT>
...
fwmark <INT>
}
```
- 虚拟主机3中配置
```
#virtual_server IP port
#virtual_server fwmark int
#virtual_server group string
virtual_server 192.168.1.229 80 { #配置一个virtual server
delay_loop 3 #每隔3秒检查一次RealServer是否可用
lb_algo rr|wrr|lc|wlc|lblc|sh|dh #LVS调度算法
lb_kind NAT|DR|TUN #LVS集群模式
persistence_timeout 120 #同一个客户端IP在120秒内分到同一个RealServer
persistence_granularity <NETMASK> #会话保持粒度默认255.255.255.255即根据每个客户端IP做会话保持
protocol TCP #协议
ha_suspend
virtualhost <string> #HTTP_GET健康检查时使用的HOST}
sorry_server <IPADDR> <PORT> #所有RS失效后连接该备用机
real_server <IPADDR> <PORT> {
weight 1 #默认1,0失效
inhibit_on_failure #健康检查失败后将weight置0,不从IPVS中删除
notify_up <STRING> #检测到service up后执行的脚本
notify_down <STRING> #检测到service down后执行的脚本
#检查方式HTTP_GET|SSL_GET|TCP_CHECK
HTTP_GET|SSL_GET {
url {
path /
digest <STRING> #SSL检查返回的摘要信息
status_code 200 #HTTP检查返回的状态码
}
connect_port 80 #检查端口
bindto <IPADDR> #使用该地址发送健康检查
connect_timeout #连接超时时间
nb_get_retry 3 #重连次数
delay_before_retry 2 #重连间隔(秒)
}
TCP_CHECK {
connect_port 80
bindto <IPADDR>
connect_timeout 4
}
}
}
```
# 配置日志文件
- 修改服务启动参数
```bash
sed -i '/^KEEPALIVED_OPTIONS/d' /etc/sysconfig/keepalived
echo 'KEEPALIVED_OPTIONS="-D -d -S 2"' >> /etc/sysconfig/keepalived
```
- 修改 rsyslog 配置文件
```bash
echo "local2.* /var/log/keepalived.log" >> /etc/rsyslog.conf
```
- 重启 rsyslog 服务
```bash
systemctl restart rsyslog
```
- 重启 keepalived 服务
```bash
systemctl restart keepalived
```
# 其他参考
- [详细解释](https://blog.csdn.net/wos1002/article/details/56483325)

285
content/post/keepalived.md Normal file
View File

@ -0,0 +1,285 @@
---
title: "Keepalived 笔记"
date: 2019-10-30T11:22:03+08:00
lastmod: 2019-10-30T11:22:03+08:00
tags: ["keepalived", "高可用", "负载均衡"]
categories: ["ha/lb"]
---
# 两个 haproxy 不抢占
- 环境
- haproxy 服务器
- haproxy101: 10.1.1.101
- haproxy102: 10.1.1.102
- 虚拟地址
- ip: 10.1.1.100
- 在全部 haproxy 服务器上安装 keepalived
```bash
yum install keepalived
```
- 在全部 haproxy 服务器上配置 haproxy 和 keepalived 自启动
```bash
systemctl enable haproxy
systemctl enable keepalived
```
- MASTER/BACKUP 完整配置
```
global_defs {
router_id haproxy101 #BACKUP 这里是 haproxy102
script_user root
enable_script_security
}
vrrp_script chk_haproxy {
script "/usr/bin/systemctl status haproxy"
interval 2
weight 0
fall 2
rise 2
}
vrrp_instance VI_1 {
state BACKUP #MASTER 和 BACKUP 这里都是 BACKUP
virtual_router_id 1
priority 150 #BACKUP 这里是 100
advert_int 2
nopreempt #BACKUP 优先级低,需注释此行
interface eth0
track_script {
chk_haproxy
}
authentication {
auth_type PASS
auth_pass 1011100
}
virtual_ipaddress {
10.1.1.100/24 dev eth0
}
}
```
# 两个 LVS-DR 调度器不抢占均衡后端 MySQL 和 Ceph 负载
- 环境
- keepalived 服务器
- ka101: 10.1.1.101
- ka102: 10.1.1.102
- 虚拟地址
- ip: 10.1.1.100
- mysqld 服务器
- mysql103: 10.1.1.103
- mysql104: 10.1.1.104
- mysql105: 10.1.1.105
- ceph-radosgw 服务器
- ceph106: 10.1.1.106
- ceph107: 10.1.1.107
- ceph108: 10.1.1.108
- 在全部 keepalived 服务器上安装 keepalived
```bash
yum install keepalived
```
- 在全部 keepalived 服务器上配置 keepalived 自启动
```bash
systemctl enable keepalived
```
- MASTER/BACKUP 完整配置
- 全局和实例配置
```
global_defs {
router_id keepalive101 #BACKUP 配置 keepalive102
}
vrrp_instance V1_1 {
state BACKUP #BACKUP 也配置 BACKUP
interface eth0
virtual_router_id 1
priority 150 #BACKUP 配置 100
advert_int 1
nopreempt #BACKUP 优先级低,需注释此行
authentication {
auth_type PASS
auth_pass 1011100
}
virtual_ipaddress {
10.1.1.100/24 dev eth0
}
}
```
- LVS 均衡 mysql galera cluser 负载
```
virtual_server 10.1.1.100 3306 {
delay_loop 16
lb_algo sh
lb_kind DR
protocol TCP
real_server 10.1.1.103 3306 {
weight 1
TCP_CHECK {
connect_timeout 4
delay_before_retry 2
connect_port 3306
}
}
real_server 10.1.1.104 3306 {
weight 1
TCP_CHECK {
connect_timeout 4
delay_before_retry 2
connect_port 3306
}
}
real_server 10.1.1.105 3306 {
weight 1
TCP_CHECK {
connect_timeout 4
delay_before_retry 2
connect_port 3306
}
}
}
```
- LVS 均衡 ceph radosgw 负载
```
virtual_server 10.1.1.100 7480 {
delay_loop 16
lb_algo sh
lb_kind DR
protocol TCP
real_server 10.1.1.106 7480 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 8
nb_get_retry 2
delay_before_retry 2
connect_port 7480
}
}
real_server 10.1.1.107 7480 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 8
nb_get_retry 2
delay_before_retry 2
connect_port 7480
}
}
real_server 10.1.1.108 7480 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 8
nb_get_retry 2
delay_before_retry 2
connect_port 7480
}
}
}
```
- 在全部 mysql 和 ceph-radosgw 服务器上配置虚拟 ip
```bash
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
ip addr add 10.1.1.100/32 brd 10.1.1.100 dev lo
ip route add 10.1.1.100 dev lo
```
# 不抢占自动切换两台 Redis 主从状态
- 环境
- Redis 服务器
- redis101: 10.1.1.101
- redis102: 10.1.1.102
- 虚拟地址
- ip: 10.1.1.100
- 在全部 redis 服务器上安装 keepalived
```bash
yum install keepalived
```
- 在全部 redis 服务器上配置 redis 和 keepalived 自启动
```bash
systemctl enable redis
systemctl enable keepalived
```
- MASTER/BACKUP 完整配置
```
global_defs {
router_id redis101 #BACKUP 这里是 redis102
script_user root
enable_script_security
}
vrrp_script chk_redis {
script "/usr/bin/systemctl status redis"
interval 2
weight 0
fall 2
rise 2
}
vrrp_instance VI_1 {
state BACKUP #MASTER 和 BACKUP 这里都是 BACKUP
virtual_router_id 51
priority 150 #BACKUP 这里是 100
advert_int 1
nopreempt #BACKUP 优先级低,需注释此行
interface eth0
notify_master /etc/keepalived/scripts/master.sh
notify_backup /etc/keepalived/scripts/backup.sh
track_script {
chk_redis
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
10.1.1.100/24 dev eth0
}
}
```
- 在全部 redis 服务器上创建 /etc/keepalived/scripts/master.sh 脚本,内容如下
```bash
#!/bin/bash
#
/usr/bin/sed -i '/^slaveof/d' /etc/redis.conf
/usr/bin/systemctl restart redis
```
- 在 redis101 上创建 /etc/keepalived/scripts/backup.sh 脚本,内容如下
```bash
#!/bin/bash
#
/usr/bin/sed -i '/^slaveof/d' /etc/redis.conf
echo 'slaveof 10.1.1.102 6379' >> /etc/redis.conf
/usr/bin/systemctl restart redis
```
- 在 redis102 上创建 /etc/keepalived/scripts/backup.sh 脚本,内容如下
```bash
#!/bin/bash
#
/usr/bin/sed -i '/^slaveof/d' /etc/redis.conf
echo 'slaveof 10.1.1.101 6379' >> /etc/redis.conf
/usr/bin/systemctl restart redis
```
- 在全部 redis 服务器上赋予脚本可执行权限
```bash
chmod 0755 /etc/keepalived/scripts/*.sh
```
- 修改 redis 配置
```
requirepass redis_password
maxclients 1000
maxmemory 4294967296
maxmemory-policy volatile-lru
```
- 在全部 redis 服务器上启动 redis 和 keepalived 服务
```bash
systemctl start redis
systemctl start keepalived
```

View File

@ -0,0 +1,208 @@
---
title: "Kickstart 安装 CentOS7"
date: 2019-10-29T21:00:25+08:00
lastmod: 2019-10-29T21:00:25+08:00
keywords: []
tags: ["kickstart", "centos"]
categories: ["os"]
---
# 环境
- CentOS7.6
- genisoimage 1.1.11
- CentOS-7-x86_64-Minimal-1810.iso
# 复制 iso 内容到本地磁盘
```bash
mount -o loop CentOS-7-x86_64-Minimal-1810.iso /mnt/
mkdir -p /home/iso/centos7
cd /mnt && cp -af * .* /home/iso/centos7/
```
# 创建 isolinux/ks.cfg
- mbr 启动,/home/iso/centos7/isolinux/ks.cfg 内容如下
```
# Install OS instead of upgrade
install
# Reboot after installation
reboot
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use graphical install
graphical
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=cn --xlayouts='cn'
# System language
lang zh_CN.UTF-8
# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled
# Network information
#network --bootproto=dhcp --device=eth0 --onboot=off --ipv6=auto --no-activate
#network --hostname=localhost.localdomain
# Root password(111111)
rootpw --iscrypted $6$kD.hMvv5nCY8a/SM$Gnmb4zspkuyL75BP2Gj.1SGUaWBugXkd/zMFhoDndp9CSi8VP7R5JP7rfWzL4y7fy8crH3ryDT4PFkKCc7/xM.
# System services
services --enabled="chronyd"
# System timezone
timezone Asia/Shanghai --isUtc
# Clear the Master Boot Record
zerombr
# System bootloader configuration
bootloader --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --none --initlabel
# Disk partitioning information
part /boot --fstype="xfs" --ondisk=sda --size=512
part / --fstype="xfs" --ondisk=sda --grow --size=1
%packages
@^minimal
@core
chrony
%end
%post
lsblk > /root/lsblk
%end
%addon com_redhat_kdump --disable --reserve-mb='auto'
%end
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
```
- efi 启动,/home/iso/centos7/isolinux/ks.cfg 内容如下
```
# Install OS instead of upgrade
install
# Reboot after installation
reboot
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use graphical install
graphical
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=cn --xlayouts='cn'
# System language
lang zh_CN.UTF-8
# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled
# Network information
#network --bootproto=dhcp --device=eth0 --onboot=off --ipv6=auto --no-activate
#network --hostname=localhost.localdomain
# Root password(111111)
rootpw --iscrypted $6$kD.hMvv5nCY8a/SM$Gnmb4zspkuyL75BP2Gj.1SGUaWBugXkd/zMFhoDndp9CSi8VP7R5JP7rfWzL4y7fy8crH3ryDT4PFkKCc7/xM.
# System services
services --enabled="chronyd"
# System timezone
timezone Asia/Shanghai --isUtc
# Clear the Master Boot Record
zerombr
# System bootloader configuration
bootloader --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --none --initlabel
# Disk partitioning information
part /boot --fstype="xfs" --ondisk=sda --size=512
part /boot/efi --fstype="xfs" --ondisk=sda --size=512
part / --fstype="xfs" --ondisk=sda --grow --size=1
%packages
@^minimal
@core
chrony
%end
%post
%end
%addon com_redhat_kdump --disable --reserve-mb='auto'
%end
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
```
# 修改启动项文件
- mbr 启动,只需修改 isolinux/isolinux.cfg
- 删除 "label check" 下的 "menu default" 一行
- 在 "label linux" 一行上方添加如下内容
```
label auto
menu label ^Auto install CentOS 7
menu default
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=CentOS7 inst.ks=cdrom:/isolinux/ks.cfg quiet
```
- efi 启动,只需修改 EFI/BOOT/grub.cfg
- 修改第一行
```
set default="0"
```
- 在 "### BEGIN /etc/grub.d/10_linux ###" 一行下添加如下内容
```
menuentry 'Auto Install CentOS 7' --class fedora --class gnu-linux --class gnu --class os {
linuxefi /images/pxeboot/vmlinuz inst.ks=cdrom:/isolinux/ks.cfg inst.stage2=hd:LABEL=CentOS7 quiet
initrdefi /images/pxeboot/initrd.img
}
```
# 生成 ISO 镜像
- mbr 启动,执行如下命令
```bash
genisoimage -v -R -J -T -V CentOS7 \
-b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-cache-inodes \
-joliet-long \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-o /home/centos7.iso \
/home/iso/centos7
```
- efi 启动,执行如下命令
```bash
genisoimage -v -R -J -T -V CentOS7 \
-b images/efiboot.img \
-c isolinux/boot.cat \
-cache-inodes \
-joliet-long \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-o /home/centos7-efi.iso \
/home/iso/centos7
```
# 参考
- [https://boke.wsfnk.com/archives/382.html](https://boke.wsfnk.com/archives/382.html)

163
content/post/kubeadm.md Normal file
View File

@ -0,0 +1,163 @@
---
title: "Kubeadm"
date: 2019-10-30T11:19:06+08:00
lastmod: 2019-10-30T11:19:06+08:00
tags: ["kubernetes", "k8s", "kubeadm"]
categories: ["container"]
---
# kubeadm 安装 kubernetes
### 全部服务器配置
IP 地址 | 主机名 | 操作系统 | 内存 | swap | 硬盘 | Internet | firewalld | selinux | /etc/hosts 增加行
--------- | -------- | -------- | ---- | ---- | ---- | -------- | --------- | ------- | ------------------
10.0.2.80 | master80 | CentOS7 | 4GB | 关闭 | 20GB | 可达 | 关闭 | 关闭 | 127.0.0.1 master80
10.0.2.81 | node81 | CentOS7 | 2GB | 关闭 | 20GB | 可达 | 关闭 | 关闭 | 127.0.0.1 node81
10.0.2.82 | node82 | CentOS7 | 2GB | 关闭 | 20GB | 可达 | 关闭 | 关闭 | 127.0.0.1 node82
- 确认各服务器工作网卡的 MAC 和 UUID 均不相同
```bash
#Ovirt 从模板创建虚拟机可忽略此步骤
#不确定时可参考如下命令
rm -rf /etc/udev/rules.d/70-*
sed -i -e '/HWADDR/d' -e '/UUID/d' /etc/sysconfig/network-scripts/ifcfg-{eth,enp}*
```
- 配置好 IP确认各服务器网络互连且可连互联网
```bash
#10.0.2.80
sed -i 's/10.0.2.127/10.0.2.80/' /etc/sysconfig/network-scripts/ifcfg-eth0
#10.0.2.81
sed -i 's/10.0.2.127/10.0.2.81/' /etc/sysconfig/network-scripts/ifcfg-eth0
#10.0.2.82
sed -i 's/10.0.2.127/10.0.2.82/' /etc/sysconfig/network-scripts/ifcfg-eth0
```
- 关闭各服务器的防火墙
```bash
systemctl stop firewalld
systemctl disable firewalld
```
- 关闭各服务器的 selinux
```bash
setenforce 0
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
```
- 关闭各服务器的 swap
```bash
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
```
- 安装 ebtables 和 ethtool
```bash
yum install ebtables ethtool
```
- 配置各服务器的 hostname
```bash
#10.0.2.80
hostnamectl set-hostname master80
echo '127.0.0.1 master80' >> /etc/hosts
#10.0.2.81
hostnamectl set-hostname node81
echo '127.0.0.1 node81' >> /etc/hosts
#10.0.2.82
hostnamectl set-hostname node82
echo '127.0.0.1 node82' >> /etc/hosts
```
- 重启各服务器
```bash
reboot
```
### 安装 docker
- 各服务器安装 docker
```bash
yum install docker
```
- 各服务器配置 iptables 转发
```bash
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
```
- 各服务器配置 docker 本地仓库(可选)
```bash
cat <<EOF > /etc/docker/daemon.json
{
"insecure-registries":["10.0.16.125:5080"]
}
EOF
```
- 各服务器启动 docker
```bash
systemctl enable docker && systemctl start docker
```
### 安装 kubernetes
- 各服务器配置 kubernetes yum 源
```bash
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
```
- 各服务器安装 kubeadm
```bash
yum install -y kubelet kubeadm kubectl
```
- 各服务器启动 kubelet
```bash
systemctl enable kubelet && systemctl start kubelet
```
### 在 master80 服务器上安装 kubernetes master 服务组件
- 初始化 kubeadm
```bash
kubeadm init --pod-network-cidr=192.168.0.0/16 --token-ttl 0
mkdir -p /root/.kube
cp -i /etc/kubernetes/admin.conf /root/.kube/config
#记录下输出的最后一行,类似如下
#kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
```
- 安装 Calico 网络插件
```bash
kubectl apply -f http://docs.projectcalico.org/v2.4/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml
```
### 加入其他节点
- 在 node81 和 node82 服务器上执行以下命令,即 master80 服务器 'kuberadm init' 命令的最后一行输出
```bash
kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
```
- 在 master80 服务器查看节点和 pod 情况
```bash
kubectl get pods --all-namespaces
kubectl get nodes
```

View File

@ -0,0 +1,84 @@
---
title: "Letsencrypt 笔记"
date: 2021-11-06T20:52:00+08:00
lastmod: 2021-11-06T20:52:00+08:00
keywords: []
tags: ["letsencrypt", "certbot", "ssl"]
categories: ["web"]
---
# 安装 certbot
- 在 alpine linux 中安装 certbot
```bash
apk add --no-cache certbot openssl
```
- 注册
```bash
certbot register --register-unsafely-without-email --agree-tos
```
# 普通域名证书
- 申请 ssl 证书,有效期 90 天
```bash
certbot certonly -n -d x.x.com --standalone
# 证书文件生成到 /etc/letsencrypt/live/x.x.com/ 下
# 参数 -d 可以使用多次来指定多个域名,也可以在一个 -d 参数中使用逗号分隔多个域名
# 参数 --cert-name 可以指定证书文件的父级目录名字(替换默认的 x.x.com)
```
- 续签 ssl 证书
```bash
cerbot renew --force-renewal
```
- 生成 2048 位的交换密钥文件
```bash
openssl dhparam -out /etc/letsencrypt/dhparam.pem 2048
```
# 通配域名证书
- 申请 ssl 证书,有效期 90 天
```bash
certbot certonly --manual -d '*.x.com' \
--preferred-challenges dns \
--server https://acme-v02.api.letsencrypt.org/directory
# 证书文件生成到 /etc/letsencrypt/live/x.com/ 下
# 参数 --cert-name 可以指定证书文件的父级目录名字(替换默认的 x.com)
```
- 续签 ssl 证书,使用 certonly 子命令指定域名单独更新
```bash
certbot certonly --force-renewal --manual -d '*.x.com' \
--preferred-challenges dns \
--server https://acme-v02.api.letsencrypt.org/directory
```
- 生成 2048 位的交换密钥文件
```bash
openssl dhparam -out /etc/letsencrypt/dhparam.pem 2048
```
# 使用证书
- nginx 配置 ssl
```
server {
listen 443 ssl;
server_name x.x.x;
ssl_certificate /etc/letsencrypt/live/x.x.x/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/x.x.x/privkey.pem;
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_prefer_server_ciphers off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_dhparam /etc/letsencrypt/dhparam.pem;
location / {
return 404;
}
}
```

View File

@ -0,0 +1,188 @@
---
title: "Linux 硬盘随机读写"
date: 2019-10-29T21:29:26+08:00
lastmod: 2019-10-29T21:29:26+08:00
keywords: []
tags: ["linux", "随机读", "随机写"]
categories: ["storage"]
---
# 前言
- 随机写会导致磁头不停地换道,造成效率的极大降低
- 顺序写磁头几乎不用换道,或者换道的时间很短
# fio 介绍
- fio的输出报告中的几个关键指标:
- slat: 是指从 I/O 提交到实际执行 I/O 的时长Submission latency
- clat: 是指从 I/O 提交到 I/O 完成的时长Completion latency
- lat: 指的是从 fio 创建 I/O 到 I/O 完成的总时长
- bw : 吞吐量
- iops: 每秒 I/O 的次数
# 同步写测试
### 同步随机写
- 使用strace工具查看系统调用
```bash
strace -f -tt -o /tmp/randwrite.log -D fio -name=randwrite -rw=randwrite \
-direct=1 -bs=4k -size=1G -numjobs=1 -group_reporting -filename=/tmp/test.db
```
- 提取关键信息
```
root@wilson-ubuntu:~# strace -f -tt -o /tmp/randwrite.log -D fio -name=randwrite -rw=randwrite \
> -direct=1 -bs=4k -size=1G -numjobs=1 -group_reporting -filename=/tmp/test.db
randwrite: (g=0): rw=randwrite, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=1
fio-2.2.10
Starting 1 process
...
randwrite: (groupid=0, jobs=1): err= 0: pid=26882: Wed Aug 14 10:39:02 2019
write: io=1024.0MB, bw=52526KB/s, iops=13131, runt= 19963msec
clat (usec): min=42, max=18620, avg=56.15, stdev=164.79
lat (usec): min=42, max=18620, avg=56.39, stdev=164.79
...
bw (KB /s): min=50648, max=55208, per=99.96%, avg=52506.03, stdev=1055.83
...
Run status group 0 (all jobs):
WRITE: io=1024.0MB, aggrb=52525KB/s, minb=52525KB/s, maxb=52525KB/s, mint=19963msec, maxt=19963msec
Disk stats (read/write):
...
sda: ios=0/262177, merge=0/25, ticks=0/7500, in_queue=7476, util=36.05%
```
- 重点关注的信息
- clat: 平均时长56ms左右
- lat: 平均时长56ms左右
- bw: 吞吐量大概在52M左右
- 内核调用信息随机读每一次写入之前都要通过lseek去定位当前的文件偏移量
```
root@wilson-ubuntu:~# more /tmp/randwrite.log
...
26882 10:38:41.919904 lseek(3, 665198592, SEEK_SET) = 665198592
26882 10:38:41.919920 write(3, "\220\240@\6\371\341\277>\0\200\36\31\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.919969 lseek(3, 4313088, SEEK_SET) = 4313088
26882 10:38:41.919985 write(3, "\220\240@\6\371\341\277>\0\200\36\31\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920032 lseek(3, 455880704, SEEK_SET) = 455880704
26882 10:38:41.920048 write(3, "\220\240@\6\371\341\277>\0\200\36\31\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920096 lseek(3, 338862080, SEEK_SET) = 338862080
26882 10:38:41.920112 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920161 lseek(3, 739086336, SEEK_SET) = 739086336
26882 10:38:41.920177 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920229 lseek(3, 848175104, SEEK_SET) = 848175104
26882 10:38:41.920245 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920296 lseek(3, 1060147200, SEEK_SET) = 1060147200
26882 10:38:41.920312 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920362 lseek(3, 863690752, SEEK_SET) = 863690752
26882 10:38:41.920377 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920428 lseek(3, 279457792, SEEK_SET) = 279457792
26882 10:38:41.920444 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920492 lseek(3, 271794176, SEEK_SET) = 271794176
26882 10:38:41.920508 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920558 lseek(3, 1067864064, SEEK_SET) = 1067864064
26882 10:38:41.920573 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
...
```
### 同步顺序写
- 测试顺序写
```bash
strace -f -tt -o /tmp/write.log -D fio -name=write -rw=write \
-direct=1 -bs=4k -size=1G -numjobs=1 -group_reporting -filename=/tmp/test.db
```
- 可以看到吞吐量提升至70M左右
```
write: (g=0): rw=write, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=1
fio-2.2.10
Starting 1 process
Jobs: 1 (f=1): [W(1)] [100.0% done] [0KB/70432KB/0KB /s] [0/17.7K/0 iops] [eta 00m:00s]
write: (groupid=0, jobs=1): err= 0: pid=27005: Wed Aug 14 10:53:02 2019
write: io=1024.0MB, bw=70238KB/s, iops=17559, runt= 14929msec
clat (usec): min=43, max=7464, avg=55.95, stdev=56.24
lat (usec): min=43, max=7465, avg=56.15, stdev=56.25
...
bw (KB /s): min=67304, max=72008, per=99.98%, avg=70225.38, stdev=1266.88
...
Run status group 0 (all jobs):
WRITE: io=1024.0MB, aggrb=70237KB/s, minb=70237KB/s, maxb=70237KB/s, mint=14929msec, maxt=14929msec
Disk stats (read/write):
...
sda: ios=0/262162, merge=0/10, ticks=0/6948, in_queue=6932, util=46.49%
```
- 内核调用
```
root@wilson-ubuntu:~# more /tmp/write.log
...
27046 10:54:28.194508 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\360\t\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194568 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194627 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194687 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194747 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194807 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194868 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194928 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194988 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195049 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195110 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195197 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195262 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195330 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195426 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195497 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195567 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195637 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195704 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195757 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195807 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195859 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195910 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195961 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196012 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196062 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196112 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196162 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196213 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196265 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196314 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196363 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196414 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196472 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196524 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196573 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
...
```
- 顺序读不需要反复定位文件偏移量,所以能够专注于写操作
# 异步顺序写
- 前面 fio 的测试报告中没有发现slat那是由于上述都是同步操作对同步 I/O 来说,由于 I/O 提交和 I/O 完成是一个动作,所以 slat 实际上就是 I/O 完成的时间
- 异步顺序写测试命令
```bash
# 同步顺序写的命令添加 -ioengine=libaio
fio -name=write -rw=write -ioengine=libaio -direct=1 -bs=4k -size=1G -numjobs=1 -group_reporting -filename=/tmp/test.db
```
- slat指标出现lat 近似等于 slat + clat 之和avg平均值并且换成异步io之后吞吐量得到了极大的提升120M左右
```
write: (g=0): rw=write, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=1
fio-2.2.10
Starting 1 process
Jobs: 1 (f=1): [W(1)] [100.0% done] [0KB/119.3MB/0KB /s] [0/30.6K/0 iops] [eta 00m:00s]
write: (groupid=0, jobs=1): err= 0: pid=27258: Wed Aug 14 11:14:36 2019
write: io=1024.0MB, bw=120443KB/s, iops=30110, runt= 8706msec
slat (usec): min=3, max=70, avg= 4.31, stdev= 1.56
clat (usec): min=0, max=8967, avg=28.13, stdev=55.68
lat (usec): min=22, max=8976, avg=32.53, stdev=55.72
...
bw (KB /s): min=118480, max=122880, per=100.00%, avg=120467.29, stdev=1525.68
...
Run status group 0 (all jobs):
WRITE: io=1024.0MB, aggrb=120442KB/s, minb=120442KB/s, maxb=120442KB/s, mint=8706msec, maxt=8706msec
Disk stats (read/write):
...
sda: ios=0/262147, merge=0/1, ticks=0/6576, in_queue=6568, util=74.32%
```
# 参考
- [https://www.linuxidc.com/Linux/2019-08/160097.htm](https://www.linuxidc.com/Linux/2019-08/160097.htm)

198
content/post/lvm.md Normal file
View File

@ -0,0 +1,198 @@
---
title: "Lvm 笔记"
date: 2019-10-29T21:44:02+08:00
lastmod: 2019-10-29T21:44:02+08:00
keywords: []
tags: ["lvm"]
categories: ["storage"]
---
# LVM 一览
![lvm一览](/img/lvm.jpg "lvm一览")
# LVM 结构
- PE 物理扩展
- PV 物理卷,在设备起始处放置一个标签,包括 uuidlvm 配置元数据位置以及剩余空间
- PV 可以由分区创建,也可以直接用磁盘创建
- VG 卷组
- LV 逻辑卷
- Linear 线性卷
- Stripe 条带卷
- RAID raid 逻辑卷
- Mirror 镜像卷
- Thinly-Provision 精简配置逻辑卷
- Snapshot 快照卷
- Thinly-Provisioned Snapshot 精简配置快照卷
- Cache 缓存卷
# LVM 相关命令
## PV
- pvchange 更改物理卷属性
- pvck 检查物理卷元数据
- pvcreate 初始化磁盘或分区以供lvm使用
- pvdisplay 显示物理卷的属性
- pvmove 移动物理Exent
- pvremove 删除物理卷
- pvresize 调整lvm2使用的磁盘或分区的大小
- pvs 报告有关物理卷的信息
- pvscan 扫描物理卷的所有磁盘
## VG
- vgcfgbackup 备份卷组描述符区域
- vgcfgrestore 恢复卷组描述符区域
- vgchange 更改卷组的属性
- vgck 检查卷组元数据
- vgconvert 转换卷组元数据格式
- vgcreate 创建卷组
- vgdisplay 显示卷组的属性
- vgexport 使卷组对系统不了解(这是个什么)
- vgextend 将物理卷添加到卷组
- vgimportclone 导入并重命名重复的卷组(例如硬件快照)
- vgmerge 合并两个卷组
- vgmknodes 重新创建卷组目录和逻辑卷特殊文件
- vgreduce 通过删除一个或多个物理卷来减少卷组将物理卷踢出VG
- vgremove 删除卷组
- vgrename 重命名卷组
- vgs 报告有关卷组信息
- vgscan 扫描卷组的所有磁盘并重建高速缓存
- vgsplit 将卷组拆分为两个,通过移动整个物理卷将任何逻辑卷从一个卷组移动到另一个卷组
## LV
- lvchange 更改逻辑卷属性
- lvconvert 将逻辑卷从线性转换为镜像或快照
- lvcreate 将现有卷组中创建逻辑卷
- lvdisplay 显示逻辑卷的属性
- lvextend 扩展逻辑卷的大小
- lvmconfig 在加载lvm.conf和任何其他配置文件后显示配置信息
- lvmdiskscan 扫描lvm2可见的所有设备
- lvmdump 创建lvm2信息转储以用于诊断目的
- lvreduce 减少逻辑卷的大小
- lvremove 删除逻辑卷
- lvrename 重命名逻辑卷
- lvresize 调整逻辑卷大小
- lvs 报告有关逻辑卷的信息
- lvscan 扫描所有的逻辑卷
# 创建 LVM
- 将磁盘创建为 pv物理卷其实物理磁盘被条带化为 pv划成了一个一个的 pe默认每个 pe 大小是 4MB
- 创建 vg其实它是一个空间池不同PV加入同一 vg
- 创建 lv组成 lv 的 pe 可能来自不同的物理磁盘
- 格式化 lv挂载使用
# PV 管理
- 制作 pv
```bash
pvcreate /dev/sdb1
```
- 删除 pv(需先踢出 vg)
```bash
pvremote /dev/sdb1
```
# VG 管理
- 制作 vg
```bash
# vgcreate vg_name 磁盘设备或分区
vgcreate datavg /dev/sdb1
vgcreate datavg /dev/sdb1 /dev/sdb2
# -s 指定pe的大小为16M默认不指定是4M
vgcreate -s 16M datavg2 /dev/sdb3
```
- 从 vg 中移除缺失的磁盘
```bash
vgreduce --removemissing datavg
vgreduce --removemissing datavg --force # 强制移除
```
- 扩展 vg 空间
```bash
vgextend datavg /dev/sdb3 /dev/sdc
```
- 踢出 vg 中的某个成员
```bash
vgreduce datavg /dev/sdb3
```
- 删除 vg
```bash
vgremove VG
```
- 重命名 vg
```bash
vgrename xxxx-vgid-xxxx-xxxx new_name
```
# LV 管理
- 制作 lv
```bash
# -n lv_name-L lv_sizedatavg(vg name)
lvcreate -n lvdata1 -L 1.5G datavg
```
- 激活修复后的逻辑卷
```bash
lvchange -ay /dev/datavg/lvdata1
lvchange -ay /dev/datavg/lvdata1 -K # 强制激活
```
- 创建 lvm 快照
```bash
# 数据一致性备份
# 先做一个快照,冻结当前系统,这样快照里面的内容可暂时保持不变
# 系统本身继续运行,通过重新挂载备份快照卷,实现不中断服务备份。
lvcreate -s -n kuaizhao01 -L 100M /dev/datavg/lvdata1
```
- 删除 lv
```bash
lvremove /dev/mapper/VG-mylv
```
- 扩大一个 lv
- 用vgdisplay查看vg还有多少空余空间
- 扩充逻辑卷
```bash
lvextend -L +1G /dev/VG/LV01
# -r 表示在扩展的同时也更新文件系统,不是所有的发行版本都支持
lvextend -L +1G /dev/VG/LV01 -r
```
- 扩充操作后df -h 发现大小并没有变,需更新文件系统
```bash
# 不同文件系统更新的命令不一样
e2fsck -f /dev/datavg/lvdata1 # ext4 文件系统,检查 lv 的文件系统
resize2fs /dev/VG/LV01 # ext4 文件系统命令,该命令后面接 lv 的设备名就行
xfs_growfs /nas # xfs 文件系统,该命令后面直接跟的是挂载点
```
- 更新文件系统后df -h 正常
- 缩小一个 lv
- umount 卸载
- 缩小文件系统
```bash
resize2fs /dev/VG/LV01 2G
```
- 缩小 lv
```bash
lvreduce -L -1G /dev/VG/LV01
```
- 查看 lvsmount 挂载
# lvm 灾难恢复
- 场景: 三块盘做 lvm现有一物理盘损坏将剩下两块放到其他linux服务器上
- 恢复步骤
- 查看磁盘信息lvm信息确认能查到lvm相关信息找到VG组的名字
```bash
pvs
lvs
vgs
fidsk
blkid
```
- 删除 lvm 信息中损坏的磁盘角色,强制提出故障磁盘
```bash
vgreduce --removemissing VG_name
```
- 强制激活 vg 组
```bash
vgchange -ay
```
- 强制激活 lvm
```bash
lvchange -ay /dev/VG_name
```
- 挂载

44
content/post/lvs.md Normal file
View File

@ -0,0 +1,44 @@
---
title: "Lvs 笔记"
date: 2019-10-30T12:55:50+08:00
lastmod: 2019-10-30T12:55:50+08:00
tags: ["lvs", "负载均衡"]
categories: ["ha/lb"]
---
# 环境
角色 | 地址
---- | ----
负载分配服务器 | 192.168.1.209
tomcat 服务器1 | 192.168.1.207
tomcat 服务器2 | 192.168.1.208
VIP | 192.168.1.250
# LVS-DR
- 配置负载分配服务器(192.168.1.209)
```bash
#在与 tomcat 服务器连通的网卡(eth0)上配置虚拟 IP(192.168.1.250)
ip addr add 192.168.1.250/32 brd 192.168.1.250 dev eth0
ip route add 192.168.1.250 dev eth0
#开启转发
echo 1 > /proc/sys/net/ipv4/ip_forward
#安装 ipvsadm
yum install ipvsadm
ipvsadm -C
ipvsadm -A -t 192.168.1.250:80 -s rr
ipvsadm -a -t 192.168.1.250:80 -r 192.168.1.207:80 -g
ipvsadm -a -t 192.168.1.250:80 -r 192.168.1.208:80 -g
```
- 在两台 tomcat 服务器上都做如下配置
```bash
#禁用 arp 响应
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
#添加虚拟 IP
ip addr add 192.168.1.250/32 brd 192.168.1.250 dev lo
ip route add 192.168.1.250 dev lo
#在个人浏览器中访问 http://192.168.1.250/webapp/
```

1750
content/post/makefile.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
---
title: "CentOS 安装官方编译的 Mariadb 10.1 二进制通用包"
date: 2019-10-30T17:53:33+08:00
lastmod: 2019-10-30T17:53:33+08:00
tags: ["centos", "mariadb", "二进制"]
categories: ["database"]
---
环境centos 5.4/6.2/6.5/7.2 x64
1、下载官方编译好的 linux 通用安装包,解压之自定义目录(如/opt
```bash
# rhel 7 地址:
wget https://mirrors.tuna.tsinghua.edu.cn/mariadb//mariadb-10.1.19/bintar-linux-glibc_214-x86_64/mariadb-10.1.19-linux-glibc_214-x86_64.tar.gz
# rhel 5/6 地址:
wget https://mirrors.tuna.tsinghua.edu.cn/mariadb//mariadb-10.1.19/bintar-linux-x86_64/mariadb-10.1.19-linux-x86_64.tar.gz
tar zxf mariadb-10.1.19-linux*-x86_64.tar.gz -C /opt/
cd /opt;mv mariadb-10.1.19-linux* mariadb
```
2、创建服务文件和配置文件创建日志目录
```
cd /opt/mariadb
mv support_files/my-large.cnf ./my.cnf
mv support_files/mysql.server ./mysqld
mkdir -p log
```
3、修改服务文件 mysqld
```
vim /opt/mariadb/mysqld
# 在打开的文件中修改开头的basedir和datadirdatadir是数据库文件目录建议指定一个大分区中的目录
basedir=/opt/mariadb
datadir=/mnt/sdb1/mariadb_db
# 修改开头的lockdir和lock-file-path
lockdir='/opt/mariadb/log'
lock-file-path="$lockdir/mysql.lock"
```
4、修改配置文件 /opt/mariadb/my.cnf
```
[mysqld]
datadir=/mnt/sdb1/mariadb_db
log-error=/opt/mariadb/log/error.log
pid-file=/opt/mariadb/log/mysql.pid
user = mysql
#port = 3306
socket = /tmp/mysql.sock
skip-networking # 取消监听端口,适合本地数据库使用
skip-name-resolve # 取消域名解析
max-connections = 3000
max-connect-errors = 1000
#如果系统中存在 /etc/my.cnf 且不可写, 可以在 /opt/mariadb/my.cnf 中重新设置冲突项。
```
5、修改数据库程序数据目录的权限:
```bash
chown mysql.mysql /opt/mariadb/ -R
chown mysql.mysql /mnt/sdb1/mariadb_db/ -R
```
6、安装数据库
```bash
/opt/mariadb/scripts/mysql_install_db --basedir=/opt/mariadb --datadir=/mnt/sdb1/mariadb_db --user=mysql
```
7、根据提示修改mariadb的root帐号密码禁用root登陆删除匿名用户及test库
```bash
# 启动 mariadb
/opt/mariadb/mysqld start
# 修改 root 密码
/opt/mariadb/bin/mysqladmin -u root password '12345678'
# 安全设置
/opt/mariadb/bin/mysql_secure_install --basedir=/opt/mariadb
```
8、增加系统动态库配置
```bash
echo '/opt/mariadb/lib' >> /etc/ld.so.conf
ldconfig
```

View File

@ -0,0 +1,144 @@
---
title: "CentOS7 部署 Mariadb Galera 集群"
date: 2019-10-30T14:01:06+08:00
lastmod: 2019-10-30T14:01:06+08:00
tags: ["mariadb", "galera"]
categories: ["database"]
---
# 环境
cpu | mem | hostname | public ip | cluster ip | CentOS | MariaDB
---- | ---- | ---- | ---- | ---- | ---- | ----
双核 | 2GB | mariadb_1 | 10.0.0.231 | 10.10.10.1 | 7.5 | 10.1.33
双核 | 2GB | mariadb_2 | 10.0.0.232 | 10.10.10.2 | 7.5 | 10.1.33
双核 | 2GB | mariadb_3 | 10.0.0.233 | 10.10.10.3 | 7.5 | 10.1.33
# 安装数据库
### 离线安装
- [下载 rpm](http://yum.mariadb.org/10.1/centos7-amd64/rpms/)
- MariaDB-10.1.33-centos7-x86_64-client.rpm
- MariaDB-10.1.33-centos7-x86_64-common.rpm
- MariaDB-10.1.33-centos7-x86_64-server.rpm
- MariaDB-10.1.33-centos7-x86_64-shared.rpm
- galera-25.3.23-1.rhel7.el7.centos.x86_64.rpm
- jemalloc-3.6.0-1.el7.x86_64.rpm
- 安装 rpm
```bash
yum erase mariadb-libs
rpm -ivh *.rpm
```
- 安装后会自动执行数据库初始化脚本,如果未执行,可手动运行
```bash
mysql_install_db --user=mysql
```
### yum 安装
- 创建 MariaDB-10.1 的 yum 源文件(就近选择一个)
```bash
#官方
cat > /etc/yum.repos.d/MariaDB.repo <<-END
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
END
#中科大
cat > /etc/yum.repos.d/MariaDB.repo <<-END
[mariadb]
name = MariaDB
baseurl = https://mirrors.ustc.edu.cn/mariadb/yum/10.1/centos7-amd64
gpgkey=https://mirrors.ustc.edu.cn/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck=1
END
#上海大学
cat > /etc/yum.repos.d/MariaDB.repo <<-END
[mariadb]
name = MariaDB
baseurl = https://mirrors.shu.edu.cn/mariadb/yum/10.1/centos7-amd64
gpgkey=https://mirrors.shu.edu.cn/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck=1
END
```
- 安装 MariaDB
```bash
yum install MariaDB-client MariaDB-server
# galera_4 会作为依赖自动安装
```
# 启动server
```bash
systemctl start mariadb
```
# 安全设置
- 设置root账户密码推荐
```bash
mysqladmin -u root password 'password'
```
- 数据库安全设置(推荐)
```bash
mysql_secure_installation
```
# 配置Galera Cluster
- 修改/etc/my.cnf.d/server.cnf如下
```
[server]
innodb-flush-log-at-trx-commit=0
innodb-buffer-pool-size=1024M #一半内存
innodb-autoinc-lock-mode=2
default-storage-engine=InnoDB
#
[mysqld]
#
[galera]
wsrep-on=ON
wsrep-provider = /usr/lib64/galera/libgalera_smm.so
wsrep-provider-options="gcache.dir=/var/lib/gcache;gcache.size=1G;gcache.recover=yes;pc.recovery=TRUE"
wsrep-cluster-name="mariadb_galera_cluster"
wsrep-cluster-address = "gcomm://10.10.10.1,10.10.10.2,10.10.10.3"
wsrep-node-name = mariadb_1 #当前节点名字
wsrep-node-address = 10.10.10.1 #当前节点地址
binlog-format=ROW
wsrep-slave-threads=2
wsrep-sst-method=rsync
#wsrep-auto-increment-control=OFF #只通过一个节点做增删改时使用
#
[embedded]
#
[mariadb]
#
[mariadb-10.1]
```
# 停止 server
```bash
systemctl stop mariadb
```
# 启动集群
- 启动 galera cluster
```bash
mysqld --wsrep-new-cluster --user=mysql
```
- 查看集群状态
```sql
show status like 'wsrep_%';
```
- 在剩余两台服务器启动 server向集群中添加节点
```bash
systemctl start mariadb
```
- 再次查看集群状态
```sql
show status like 'wsrep_%';
```
# 注意事项
- 防火墙开放 3306、4444 和 4567 端口
- 关闭 selinux
- 集群关闭时,/var/lib/mysql/grastate.dat 文件中 safe_to_bootstrap 项为 1 的节点服务器是最后关闭的数据库,数据最全,所以下次集群启动时应从这台节点服务器启动

View File

@ -0,0 +1,130 @@
---
title: "MariaDB 主从复制"
date: 2020-04-13T18:00:00+08:00
lastmod: 2020-04-13T18:00:00+08:00
tags: ["mariadb", "master", "slave", "gtid", "replication", "同步"]
categories: ["database"]
---
# 环境
- mariadb 主服务器centos7.8192.168.1.141
- mariadb 主服务器centos7.8192.168.1.142
- mariadb 从服务器centos7.8192.168.1.143
- 忽略系统数据库: information_schema, mysql, performance_schema
# 在两个主服务器上创建用于备份的用户 replicator
```sql
grant replication slave on *.* to 'replicator'@'%' identified by 'password';
flush privileges;
```
# 在两个主服务器上修改 my.cnf
```
# 唯一 ID
# 192.168.1.141 配置
server-id = 141
# 192.168.1.142 配置
server-id = 142
read-only = 0
# binlog
# MariaDB 默认已开启 GTID
log-bin = /var/lib/mysql-bin/master
binlog-format = row
sync_binlog = 1
expire-logs-days = 3
gtid-strict-mode = ON
# relay log
replicate-wild-ignore-table = information_schema.%
replicate-wild-ignore-table = init_sql.%
replicate-wild-ignore-table = mysql.%
replicate-wild-ignore-table = performance_schema.%
relay-log = /var/lib/mysql-bin/slave
relay-log-recovery = TRUE
# 复制线程数不超过 cpu 核数
slave-parallel-threads = 4
# 双主或多主互备时,可能会用到以下配置
# 自增主键初始值,与其他互备服务器一致
#auto-increment-offset =
# 自增主键等差值,与其他互备服务器均不一致
#auto-increment-increment =
# 该环境中,双主配合 keepalived 实现高可用,无需配置自增
```
# 开启互主同步
```sql
-- 在 192.168.1.141 上启动 mariadb配置同步 192.168.1.142:
change master to master_host = '192.168.1.142',
master_port = 3306,
master_user = 'replicator',
master_password = 'password',
master_use_gtid = slave_pos;
-- 在 192.168.1.142 上启动 mariadb配置同步 192.168.1.141:
change master to master_host = '192.168.1.141',
master_port = 3306,
master_user = 'replicator',
master_password = 'password',
master_use_gtid = slave_pos;
```
# 在两个主服务器上启动 slave ,查看 slave 状态
```sql
start slave;
-- 查看 slave 状态
show slave status\G
-- 如果看到
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- 则表示 slave 开启成功!
```
# 在从服务器上编辑 my.cnf
```
# 唯一 ID
server-id = 143
# 从服务器只做查询,无增删改
read-only = 1
# 忽略的数据表
#replicate-ignore-table = db1.t1
replicate-wild-ignore-table = information_schema.%
replicate-wild-ignore-table = init_sql.%
replicate-wild-ignore-table = mysql.%
replicate-wild-ignore-table = performance_schema.%
relay-log = /var/log/mysql-bin/slave
slave-parallel-threads = 4
```
# 开启同步
```sql
change master 'db141' to master_host = '192.168.1.141',
master_port = 3306,
master_user = 'replicator',
master_password = 'password',
master_use_gtid = slave_pos;
change master 'db142' to master_host = '192.168.1.142',
master_port = 3306,
master_user = 'replicator',
master_password = 'password',
master_use_gtid = slave_pos;
```
# 在从服务器上启动 slave ,查看 slave 状态
```sql
start all slaves;
-- 在从服务器上查看 slave 状态
show all slaves status\G
-- 如果看到
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- 则表示 slave 开启成功!
```
# 参考
- [MariaDB 复制](https://mariadb.com/kb/en/standard-replication/)
- [MariaDB 多源复制](https://mariadb.com/kb/en/multi-source-replication/)

210
content/post/minio.md Normal file
View File

@ -0,0 +1,210 @@
---
title: "Minio 笔记"
date: 2021-10-17T00:48:00+08:00
lastmod: 2021-10-17T00:48:00+08:00
keywords: []
tags: ["minio"]
categories: ["storage"]
---
# 部署单节点分布式存储
## 环境
- 服务器 IP: 192.168.1.10
- 自定义域名: X.X.X
## 安装 minio
- 下载
```bash
curl -L -o /usr/local/bin/minio https://dl.min.io/server/minio/release/linux-amd64/minio
curl -L -o /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc
chmod 0755 /usr/local/bin/{minio,mc}
```
- 修改 hosts增加自定义域名解析
```
192.168.1.10 X.X.X
```
- 创建四个目录,用于存储 minio 数据
```bash
mkdir -p /minio/{1,2,3,4}
```
- 创建 /etc/systemd/system/minio.service内容如下
```ini
[Unit]
Description=MinIO
After=network.service
Wants=network.service
[Service]
Environment=MINIO_ROOT_USER=XXX
Environment=MINIO_ROOT_PASSWORD=XXXXXXXX
ExecStart=/usr/local/bin/minio server \
--console-address ":9001" \
http://X.X.X:9000/minio/{1...4}
#Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
```
## 启动 minio
- 配置开机自动启动
```bash
systemctl daemon-reload
systemctl enable minio
```
- 启动 minio
```bash
systemctl start monio
```
# 部署多节点分布式存储
## 环境
自定义域名 | 网卡 IP | 硬盘槽 | 数据分区
---- | ---- | ---- | ----
X1.X.X | eth0: 192.168.1.11<br>eth1:10.0.0.11 | 8 个 | /dev/sdb1, /dev/sdc1<br>/dev/sdd1, /dev/sde1
X2.X.X | eth0: 192.168.1.12<br>eth1:10.0.0.12 | 8 个 | /dev/sdb1, /dev/sdc1<br>/dev/sdd1, /dev/sde1
X3.X.X | eth0: 192.168.1.13<br>eth1:10.0.0.13 | 8 个 | /dev/sdb1, /dev/sdc1<br>/dev/sdd1, /dev/sde1
X4.X.X | eth0: 192.168.1.14<br>eth1:10.0.0.14 | 8 个 | /dev/sdb1, /dev/sdc1<br>/dev/sdd1, /dev/sde1
- eth0 用于接收 api 请求
- eth1 用于集群内部通信
- 每台服务器有 8 个硬盘槽,这里先各用 4 个组成 server pool运行 minio 集群
- 每台服务器剩下的 4 个硬盘槽用于后面的扩容操作
## 挂载数据分区
- 在全部服务器上执行如下操作
- 挂载硬盘
```bash
mkdir -p /mnt/minio{1,2,3,4}
mount /dev/sdb1 /mnt/minio1
mount /dev/sdc1 /mnt/minio2
mount /dev/sdd1 /mnt/minio3
mount /dev/sde1 /mnt/minio4
```
- 建议在 fstab 中配置开机自动挂载
## 安装 minio
- 在全部服务器上执行如下操作
- 下载
```bash
curl -L -o /usr/local/bin/minio https://dl.min.io/server/minio/release/linux-amd64/minio
curl -L -o /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc
chmod 0755 /usr/local/bin/{minio,mc}
```
- 修改 hosts增加自定义域名解析**注意这里是集群通信,要用 eth1 网卡 ip**
```
10.0.0.11 X1.X.X
10.0.0.12 X2.X.X
10.0.0.13 X3.X.X
10.0.0.14 X4.X.X
```
- 创建 /etc/systemd/system/minio.service内容如下
```ini
[Unit]
Description=MinIO
After=network.service
Wants=network.service
[Service]
Environment=MINIO_ROOT_USER=XXX
Environment=MINIO_ROOT_PASSWORD=XXXXXXXX
ExecStart=/usr/local/bin/minio server \
--console-address ":9001" \
http://X{1...4}.X.X:9000/mnt/minio{1...4}
#Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
```
## 启动 minio
- 在全部服务器上执行如下操作
- 配置开机自动启动
```bash
systemctl daemon-reload
systemctl enable minio
```
- 启动 minio
```bash
systemctl start monio
```
# 扩容多节点分布式存储
## 加装硬盘
- 在全部服务器上执行如下操作
- 在每台服务器上个增加四个新硬盘,每个硬盘创建一个分区,格式化
- 挂载新增的硬盘分区
```bash
mkdir -p /mnt/minio{5,6,7,8}
mount /dev/sdf1 /mnt/minio5
mount /dev/sdg1 /mnt/minio6
mount /dev/sdh1 /mnt/minio7
mount /dev/sdi1 /mnt/minio8
```
- 建议在 fstab 中配置开机自动挂载
## 扩容
- 在全部服务器上执行如下操作
- 停止 minio 服务
```bash
systemctl stop minio
```
- 修改 /etc/systemd/system/minio.service增加新的 server pool内容如下
```ini
[Unit]
Description=MinIO
After=network.service
Wants=network.service
[Service]
Environment=MINIO_ROOT_USER=XXX
Environment=MINIO_ROOT_PASSWORD=XXXXXXXX
ExecStart=/usr/local/bin/minio server \
--console-address ":9001" \
http://X{1...4}.X.X:9000/mnt/minio{1...4} \
http://X{1...4}.X.X:9000/mnt/minio{5...8}
#Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
```
- 启动 minio 服务
```bash
systemctl start minio
```
# 客户端常用操作
- 创建 alias**注意这里是 api 调用,要用 eth0 网卡 ip**
```bash
mc alias set XXX http://192.168.1.X:9000 XXX XXXXXXXX
```
- 创建 bucket
```bash
mc mb XXX/XXX
```
- 创建用户
```bash
mc admin user add XXX XXXXXXXX
```
- 给新增用户授权
```bash
mc admin policy set XXX readwrite user=XXX
```

217
content/post/mongodb.md Normal file
View File

@ -0,0 +1,217 @@
---
title: "Mongodb 笔记"
date: 2019-10-30T10:56:11+08:00
lastmod: 2019-10-30T10:56:11+08:00
keywords: []
tags: ["mongodb"]
categories: ["database"]
---
# 数据迁移
### 导出集合数据到 json 或 csv 文件
- 命令
```
mongoexport -d dbname -c collectionname -o file --type json/csv -f "field1,field2,...,fieldN"
```
- 参数
- -d 数据库名
- -c 集合名
- -o 输出文件名
- --type 输出格式,默认 json
- -f 输出字段,如果导出 csv需指定字段名
### 导入数据到集合
- 命令
```
mongoimport -d dbname -c collectionname --file filename --headerline --type json/csv -f "field1,field2,...,fieldN"
```
- 参数
- -d 数据库名
- -c 集合名
- --type 导入格式,默认 json
- -f 导入的字段名
- --headerline 导入csv时使用第一行的标题作为导入字段
- --file 导入的文件
### 备份数据库
- 命令
```
mongodump -h dbhost -d dbname -o backup_dir
```
- 参数
- -h ip[:port]
- -d 数据库名
- -o 备份数据存放目录,需提前建立
### 恢复数据库
- 命令
```
mongorestore -h dbhost -d dbname --dir backup_dir
```
- 参数
-h ip[:port]
-d 数据库名
--dir 备份数据存放目录
--drop 恢复前,先删除当前数据
# 操作数据库
- 默认数据库 test
- 创建 use dbname
- 查看当前选择的数据库 db
- 查看数据库列表 show dbs不显示空数据库
- 删除数据库 use dbname; db.dropDatabase()
# 操作集合
### 创建
```
db.createCollection("集合名", {capped:false, autoIndexId:false, size:最大字节, max:文档最多数量})
# 或者在插入文档时自动创建
db.集合名.inert({})
```
### 删除
```
db.集合名.drop()
```
# 操作文档
### insert
- 插入一个文档
```
db.集合名.insert({})
# 或者
db.集合名.insertOne({})
```
- 插入多个文档
```
db.集合名.insert([{},{},{},...,{}])
# 或者
db.集合名.insertMany([{},{},{},...,{}])
```
### find
- 查询匹配的文档
```
db.集合名.find({}).pretty()
```
- 查询,只返回一个文档
```
db.集合名.findOne({})
```
- 相等 {"key":"value"}
- 小于 {"key":{$lt:"value"}}
- 小于等于 {"key":{$lte:"value"}}
- 大于 {"key":{$gt:"value"}}
- 大于等于 {"key":{$gte:"value"}}
- 不等于 {"key":{$ne:"value"}}
- and {$and:[{},{}]}
- or {$or:[{},{}]}
- 投影
```
db.集合名.find({},{"key1":1,"key2":0 ...})
```
- 限制返回文档数量
```
db.集合名.find({}).limit(N)
```
- 跳过返回文档数量
```
db.集合名.find({}).limit(N).skip(N)
```
- 排序1升序-1降序
```
db.集合名.find({}).sort({"key":1})
```
### update
- 更新一个文档
```
db.集合名.update({},{$set:{}})
```
- 更新多个文档
```
db.集合名.update({},{$set:{},{multi:true}})
```
### save
```
db.集合名.save({,...})
```
### remove
- 删除多条记录
```
db.集合名.remove({})
```
- 删除一条记录
```
db.集合名.remove({},1)
```
- 删除集合中的所有文档,相当于 truncate
```
db.集合名.remove()
```
### 索引
- 创建索引1升序-1降序
```
db.集合名.createIndex({"key1":1,"key2":-1})
```
### 聚合
```
db.集合名.aggregate([{}])
```
# 用户
### 创建用户
- 管理员权限
```
use admin
db.createUser(
{
user: "username",
pwd: "password",
roles: [{role: "root", db: "admin"}]
}
)
```
- 测试库读写权限
```
use testdb
db.createUser(
{
user: "username",
pwd: "password",
roles: ["readWrite"]
}
)
```
### 验证身份
```
db.auth("username", "password")
```
### 列出所有用户
```
db.getUsers()
```
### 删除数据库用户
```
use testdb
db.dropUser("username")
```
### 更改用户密码
```
db.updateUser(
"username",
{
pwd: "new_password"
}
)
```

View File

@ -0,0 +1,86 @@
---
title: "Mysql 二进制日志"
date: 2019-10-30T11:05:08+08:00
lastmod: 2019-10-30T11:05:08+08:00
keywords: []
tags: ["mysql", "binlog"]
categories: ["database"]
---
# MySQL 5.7 开启 binlog
- 修改 my.cnf 文件
```
[mysqld]
log-bin=[/存放目录/]mysql-bin #注意 mysql 可读写“存放目录”,默认数据存放目录
expire-logs-days=7 #保留7天内修改过的 binglog 文件
max-binlog-size=512M #单个 binlog 文件大小上限默认1G
#指定或忽略要复制的数据库,存在跨库问题
binlog-do-db=db1
binlog-db-db=db2
#binlog-ignore-db=db1
#binlog-ignore-db=db2
```
# 常用操作
- 查看所有 binlog 文件列表
```sql
show master logs;
```
- 查看 master 状态,包含最新 binlog 文件名和 position
```sql
show master status;
```
- 清除过期 binlog 文件,并使用新编号的 binlog 文件开始记录日志
```sql
flush logs;
```
- 删除 binlog 文件
- 删除旧的 binlog 文件
```sql
purge master logs to 'mysql-bin.000573';
purge master logs before '2018-04-18 06:00:00';
purge master logs before DATE_SUB(NOW(), INTERVAL 2 DAY);
```
- 清空所有 binlog 文件
```sql
reset master
```
# 使用 mysqlbinlog 命令查看 binlog 文件的内容
- 使用
```bash
# 查看日志
mysqlbinlog [选项] binlog文件名
# 恢复数据
mysqlbinlog [选项] binlog文件名 | mysql -u用户名 -p密码 -D数据库 [-v]
```
- 常用选项
- --start-position=128 起始 pos
- --stop-position=256 结束 pos
- --start-datetime="2018-08-08 00:00:00" 起始时间
- --stop-datetime="2018-08-09 12:00:00" 结束时间
- --database=db_name 只恢复 db_name 数据库
# 使用 sql 查看 binlog 文件的内容
- 查询语句
```sql
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];
```
- 选项
- log_name binlog文件名默认第一个 binlog 文件
- pos 查询起始 pos默认 log_name 中的第一个 pos
- offset 偏移 pos 个数
- row_count 查询数量
# 调整 binlog_cache_size
- 查看当前 binlog_cache_size 大小(byte),默认 32k
```sql
show variables like 'binlog_cache_size';
```
- 查看当前 binlog_cache_use 和 binlog_cache_disk_use 次数
```sql
show status like 'binlog_cache%';
-- binlog_cache_disk_use 使用临时文件写 binlog 文件的次数
-- binlog_cache_use 使用缓存写 binlog 文件的次数
```

105
content/post/mysql-cache.md Normal file
View File

@ -0,0 +1,105 @@
---
title: "Mysql 缓存"
date: 2019-10-30T11:00:49+08:00
lastmod: 2019-10-30T11:00:49+08:00
keywords: []
tags: ["cache", "mysql", "缓存"]
categories: ["database"]
---
# MySQL 超时
- connect_timeout 与客户端连接建立超时默认10秒
- interactive_timeout 交互终端超时断开默认28800秒
- wait_timeout 非交互终端超时断开默认28800秒
- net_read_timeout 从客户端读取数据超时默认30秒
- net_write_timeout 向客户端写入数据超时默认60秒
- innodb_lock_wait_timeout 锁等待超时默认50秒
- innodb_rollback_on_timeout 超时后回滚整个事务操作默认OFF
- slave_net_timeout 从库读取binlog失败后等待指定秒后重新连接主库默认60秒
# 查询缓存配置
** MySQL 8.0 已关闭该功能 **
- have_query_cache 是否支持查询缓存默认yes
- query_cache_limit select结果集大于该值时不缓存默认1048576
- qeury_cache_min_res_unit 查询缓存申请的内存单位大小默认4096一般不改
- query_cache_size 查询缓存大小默认1048576
- query_cache_type
- 0(OFF) 关闭查询缓存,默认
- 1(ON) 如果select语句没有sql_no_cache选项则使用查询缓存
- 2(DEMOND) 如果select语句没有sql_cache选项则不使用查询缓存
- query_cache_wlock_invalidate
- 0(OFF) 锁表后,该表的查询缓存依旧有效,默认
- 1(ON) 锁表后,该表的查询缓存失效
# 查询缓存状态
** MySQL 8.0 已关闭该功能 **
- Qcache_free_blocks 查询缓存中的内存碎片数量
- 碎片过多表明查询结果集较小可适当减小query_cache_min_res_unit
- 整理查询缓存中的碎片,获得一个较大的内存空闲空间
```sql
flush query cache
```
- 缓存碎片率 = Qcache_free_blocks / Qcache_total_blocks * 100%
- Qcache_free_memory 查询缓存中的可用内存
- Qcache_hits 使用查询缓存的次数
- Qcache_inserts 查询缓存中缓存过的select结果集数量(包括当前正在缓存的)
- Qcache_lowmen_prunes 因查询缓存已满而删除的select结果集数量
- 该值较大表明查询缓存较小
- Qcache_not_cached 没有进入查询缓存的select语句个数
- Qcache_queries_in_cache 查询缓存中当前缓存着select结果集数量
- Qcache_total_blocks 查询缓存中的块总数
- Com_select 执行过的select语句数量
- 查询缓存的命中率 = Qcache_hits / Com_select * 100%
# 排序缓存配置
- sort_buffer_size 排序缓存大小默认262144
- max_length_for_sort_data 排序sql中的全部字段长度总和小于该值时使用优化排序方式否则使用常规排序方式默认1024
- [参考](https://www.cnblogs.com/moss_tan_jun/p/6021822.html)
- max_sort_length 使用列的前(默认1024)个字节排序
- innodb_sort_buffer_size InnoDB用于创建/重建索引的排序缓存默认1048576
# 排序缓存状态
- Sort_merge_passes 使用临时文件完成排序操作的次数
- 增加sort_buffer_size可减少使用临时文件排序的次数
- Sort_range 使用范围排序的次数
- Sort_rows 已经排序的记录行数
- Sort_scan 通过全表扫描完成排序的次数
# join 连接缓存
- join_buffer_size 两表join但不能使用索引时为每张表分配的连接缓存默认262144
- 尽量实现索引join
# 表/表结构 缓存配置
- table_open_cache 可以缓存表和视图的数量
- table_defination_cache 可以存储的表结构数量
- open_files_limit 可以打开的文件数量
# InnoDB 重做日志缓存配置
- innodb_log_buffer_size 事务提交前,把重做日志写入缓存中
- innodb_flush_log_at_trx_commit
- 0 每隔一秒,把日志缓存写到日志文件,并刷新到磁盘
- 1 每次提交时,把日志缓存写到日志文件,并刷新到磁盘
- 2 每次提交是,把日志缓存写到日志文件,每隔一秒刷新到磁盘
# InnoDB 预读配置
- innodb_read_ahead_threshold 预读的前后数据库个数
# FLUSH 语句
- HOSTS 清空主机表
- LOGS 关闭binlog文件创建新编号binlog文件
- PRIVILEGES 从数据库授权表中重新装载权限到缓存中
- TABLES 关闭打开的表,清空查询缓存
- QUERY CACHE 整理碎片,不影响查询缓存中现有数据
- 清空查询缓存
```sql
RESET QUERY CACHE
```
- TABLES WITH READ LOCK 关闭打开的表并加一个只读锁
- 解锁
```sql
UNLOCK TABLES
```
- STATUS 重置大多数状态变量到0
- MASTER(RESET MASTER) 删除全部binlog文件重建一个新的binlog文件
- SLAVE(RESET SLAVE) 忘记主库binlog文件位置删除relay log

View File

@ -0,0 +1,115 @@
---
title: "CentOS7 安装 Mysql Galera 集群"
date: 2019-10-30T11:13:44+08:00
lastmod: 2019-10-30T11:13:44+08:00
keywords: []
tags: ["mysql", "galera"]
categories: ["database"]
---
# 环境
cpu | mem | hostname | public ip | cluster ip | CentOS | MySQL
---- | ---- | ---- | ---- | ---- | ---- | ----
双核 | 2GB | mysql_1 | 10.0.0.231 | 10.10.10.1 | 7.5 | 5.7
双核 | 2GB | mysql_2 | 10.0.0.232 | 10.10.10.2 | 7.5 | 5.7
双核 | 2GB | mysql_3 | 10.0.0.233 | 10.10.10.3 | 7.5 | 5.7
# 创建 galera yum 源文件
```bash
cat > /etc/yum.repos.d/galera.repo <<-END
[galera]
name = Galera
baseurl = http://releases.galeracluster.com/galera-3/centos/7/x86_64/
gpgkey = http://releases.galeracluster.com/GPG-KEY-galeracluster.com
gpgcheck = 1
#
[mysql-wsrep]
name = MySQL-wsrep
baseurl = http://releases.galeracluster.com/mysql-wsrep-5.7/centos/7/x86_64/
gpgkey = http://releases.galeracluster.com/GPG-KEY-galeracluster.com
gpgcheck = 1
END
```
# 安装
```bash
yum install galera-3 mysql-wsrep-5.7 rsync
```
# 修改 /etc/my.cnf
```
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
binlog-format=ROW
bind-address=0.0.0.0
default-storage-engine=innodb
innodb-autoinc-lock-mode=2
innodb-flush-log-at-trx-commit=0
innodb-buffer-pool-size=1024M #物理内存一半
wsrep-provider=/usr/lib64/galera-3/libgalera_smm.so
wsrep-provider-options="gcache.dir=/var/lib/gcache;gcache.size=1G;gcache.recover=yes;pc.recovery=TRUE"
wsrep-cluster-name="mysql_galera_cluster" #集群名字
wsrep-cluster-address="gcomm://10.10.10.1,10.10.10.2,10.10.10.3"
wsrep-sst-method=rsync
wsrep-node-name=mysql_1 #当前节点名字
wsrep-node-address="10.10.10.1" #当前节点 cluster ip
#wsrep-auto-increment-control=OFF #只通过一个节点做增删改时使用
#
[mysql_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
#
!includedir /etc/my.cnf.d/
```
# 随机选择一个节点,使用专用脚本 mysqld_bootstrap 初始化集群
```bash
/usr/bin/mysqld_bootstrap
#该命令会启动本机的 mysqld 服务
systemctl status mysqld
```
# 查找密码,修改初始密码
```bash
grep -i password /var/log/messages
#记录输出的密码
mysqladmin -uroot -p password 'P@sswo2d'
#根据提示输入上一步输出的密码
```
# 在其他节点上启动 mysqld 服务
```bash
systemctl start mysqld
```
# 查看集群节点数量
```sql
show status like 'wsrep_cluster_size';
```
# ssl 加密同步数据(不推荐,存在性能损失)
- 生成证书
```bash
mkdir /etc/my.cnf.d/ssl && cd /etc/my.cnf.d/ssl
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 365000 \
-key ca-key.pem -out ca-cert.pem #按提示输入信息
openssl req -newkey rsa:2048 -days 365000 \
-nodes -keyout server-key.pem -out server-req.pem #按提示输入信息,与上一步信息不同
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 365000 \
-CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 \
-out server-cert.pem
```
- 修改配置文件 my.cnf
```
#在 wsrep_provider_options 中添加如下选项,选项间用分号";"间隔
socket.ssl_key=/etc/my.cnf.d/ssl/server-key.pem; socket.ssl_cert=/etc/my.cnf.d/ssl/server-cert.pem; socket.ssl_ca=/etc/my.cnf.d/ssl/ca-cert.pem; socket.checksum=2; socket.ssl_cipher=AES128-SHA
```
- 重新启动集群
# ssl 加密客户端(不推荐,存在性能损失)
- MySQL 5.7 server 自带 ssl 加密,客户端连接时,指定参数 --ssl-mode=required 即可

View File

@ -0,0 +1,148 @@
---
title: "MySQL 组复制"
date: 2020-04-28T00:52:00+08:00
lastmod: 2020-04-28T00:52:00+08:00
tags: ["mysql", "group", "replication", "组复制"]
categories: ["database"]
---
# 环境
hostname | ip | os | mysql
---- | ---- | ---- | ----
mysql_11 | 192.168.1.11 | centos7.7 | 8.0.19
mysql_22 | 192.168.1.22 | centos7.7 | 8.0.19
mysql_33 | 192.168.1.33 | centos7.7 | 8.0.19
# 安装 mysql
- 懒得写了 ...
# 修改 my.cnf
```
# mysql_11(选择一个)
server-id = 11
# mysql_22(选择一个)
server-id = 22
# mysql_33(选择一个)
server-id = 33
# 开启 binlog
log-bin = /var/log/mysql-bin/master
binlog-format = ROW
# 关闭 binlog 校验
binlog-checksum = NONE
# 保留 2 天的 binlog
binlog-expire-logs-seconds = 172800
# 开启 gtid
gtid-mode = ON
enforce-gtid-consistency = TRUE
# 指定 relay-log 存储位置
relay-log = /var/lib/mysql-bin/slave
# relay-log 更新计入 binlog
log-slave-updates = TRUE
# 多线程执行从库日志(可选)
slave-parallel-workers = 2
slave-parallel-type = LOGICAL_CLOCK
slave-preserve-commit-order = ON
# 存储引擎只能用 InnoDB
disabled-storage-engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
# 加载插件,克隆插件用于快速 state transfer
plugin-load-add = "group_replication.so;mysql_clone.so"
# 集群 uuid
group-replication-group-name = "aaaa1111-bbbb-2222-cccc-3333dddd4444"
# mysql_11(选择一个)
group-replication-local-address = "192.168.1.11:33061"
# mysql_22(选择一个)
group-replication-local-address = "192.168.1.22:33061"
# mysql_33(选择一个)
group-replication-local-address = "192.168.1.33:33061"
# 种子节点
group-replication-group-seeds = "192.168.1.11:33061,192.168.1.22:33061,192.168.1.33:33061"
# 新主库在执行完自己的从库日志后,再处理用户的写请求
group-replication-consistency = BEFORE_ON_PRIMARY_FAILOVER
# 启动时,不自动创建/初始化新集群
group-replication-bootstrap-group = OFF
# 新节点启动时,先不启动组复制,待手动配置完成并确认正常后,再把 OFF 改成 ON
group-replication-start-on-boot = OFF
# 怀疑某节点不可用2秒内如果该嫌疑节点依旧无响应则开除它(可选)
group-replication-member-expel-timeout = 2
# 2秒内依旧连接不上主网(majority),则退出组复制,进入 ERROR 状态(可选)
group-replication-unreachable-majority-timeout = 2
# 退出组复制后,不再尝试重新加入组复制,直接执行指定的退出动作(默认)
group-replication-autorejoin-tries = 0
# 指定退出动作: 数据库设置超级只读并关闭客户端连接(推荐)
group-replication-exit-state-action = OFFLINE_MODE
```
# 初始化集群
- 重新启动节点 mysql_11
```bash
systemctl restart mysqld
```
- 创建同步用户
```sql
SET SQL_LOG_BIN = 0;
CREATE USER rpl_user@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN = 1;
```
- 配置同步信息
```sql
CHANGE MASTER TO
MASTER_USER='rpl_user',
MASTER_PASSWORD='password'
FOR CHANNEL 'group_replication_recovery';
```
- 启动集群
```sql
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
```
- 查看集群成员(只有一个)
```sql
SELECT * FROM performance_schema.replication_group_members;
```
- 修改 my.cnf配置 group-replication-start-on-boot = ON
# 增加节点
- 重新启动节点 mysql_22
```bash
systemctl restart mysql_22
```
- 创建同步用户,与 mysql_11 相同
```sql
SET SQL_LOG_BIN = 0;
CREATE USER rpl_user@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN = 1;
```
- 配置同步信息
```sql
CHANGE MASTER TO
MASTER_USER='rpl_user',
MASTER_PASSWORD='password'
FOR CHANNEL 'group_replication_recovery';
```
- 启动组复制
```sql
START GROUP_REPLICATION;
```
- 在 mysql_33 上重复 mysql_22 的步骤
- 查看集群成员(有三个)
```sql
SELECT * FROM performance_schema.replication_group_members;
```
- 修改 mysql_22 和 mysql_33 的 my.cnf配置 group-replication-start-on-boot = ON
# 注意
- 每张表都必须显式指定主键

View File

@ -0,0 +1,296 @@
---
title: "MySQL 主从复制"
date: 2019-10-30T17:33:13+08:00
lastmod: 2020-04-18T23:40:00+08:00
tags: ["mysql", "master", "slave", "gtid", "replication", "同步"]
categories: ["database"]
---
# 环境
- mysql 主服务器centos7.4192.168.1.10,端口 10000
- mysql 从服务器centos7.4192.168.1.6
- 要复制的数据库有 data_db、conf_db
# 在主服务器上创建用于备份的用户 replicator
```sql
grant replication slave on *.* to 'replicator'@'192.168.1.6' identified by 'password';
flush privileges;
```
# 在主服务器上修改 my.cnf
```
# 建议与本机ip地址最后一位一致,与其他互备服务器均不一致
server-id = 10
read-only = 0
# 开启 binlog
log-bin = /var/log/mysql-bin/master
binlog-format = row
#关注要复制的数据库,存在跨库问题
binlog-do-db = data-db
binlog-do-db = conf-db
#忽略的数据库,存在跨库问题
#binlog-ignore-db =
#binlog 有效时间
expire-logs-days =
#GTID 复制模式
#gtid-mode = ON
#enforce-gtid-consistency=true
#双主或多主互备时,会用到以下配置
#自增主键初始值,与其他互备服务器一致
#auto-increment-offset =
#自增主键等差值,与其他互备服务器均不一致
#auto-increment-increment =
```
# 在主服务器上重启 mysql获取 master 状态
```sql
-- 如果 mysql 是全新安装,则无须导出数据库初态,直接查看 binlog pos 即可
-- 锁定要导出的数据库表
flush tables with read lock;
```
# 导出数据库初态
```bash
#在主服务器的另一个终端中运行
mysqldump -uroot -p data_db > /tmp/data_db.sql
mysqldump -uroot -p conf_db > /tmp/conf_db.sql
#复制到从服务器上
scp /tmp/data_db.sql /tmp/conf_db.sql 192.168.1.6:/tmp/
```
# 查看 binary 日志位置
```sql
show master status\G
-- 记住输出里的如下类似两行不记录也可以这两个信息已经写入了导出的sql文件中
-- File: mysql-bin.000001
-- Position: 137103822
-- 解锁数据库表
unlock tables;
```
# 在从服务器上编辑 my.cnf
```
# 建议与本机ip地址最后一位一致,与其他互备服务器均不一致
server-id = 6
read-only = 1
# 如果该 slave 中也运行了 master或者使用了 gtid 模式复制,则开启 binlog
#log-bin = mysql-bin
#binlog-format = row
# 把 slave 操作也计入 binlog用于链式同步
#log-slave-updates = ON
# 指定要复制的数据库,存在跨库问题
#replicate-do-db = data_db
#replicate-do-db = conf_db
# 指定要复制的数据表,无跨库问题
replicate-do-table = db1.t1
replicate-wild-do-table = db1.%
# 忽略的数据库,存在跨库问题
#replicate-ignore-db =
# 忽略的数据表,无跨库问题
#replicate-ignore-table = db1.t1
#replicate-wild-ignore-table = db1.%
# 中继日志
relay-log = /var/lib/mysql-bin/slave
# 多线程复制
slave-parallel-type = logical-clock
slave-parallel-workers = 4
# GTID 模式
#gtid-mode = ON
#enforce-gtid-consistency=true
# 双主或多主互备时,会用到以下配置
# 自增主键初始值,与其他互备服务器一致
#auto-increment-offset =
# 自增主键等差值,与其他互备服务器均不一致
#auto-increment-increment =
```
# 在从服务器上重启 mysql导入初态
```sql
-- 创建要导入的数据库
create database data_db default charset utf8mb4;
create database conf_db default charset utf8mb4;
```
# 导入数据库
```bash
msyql -uroot -p data_db < /tmp/data_db.sql
mysql -uroot -p conf_db < /tmp/conf_db.sql
```
# 开启同步
```sql
-- 基于 binlog 文件位置复制
change master to master_host = '192.168.1.10',
master_port = 3306,
master_user = 'replicator',
master_password = 'password',
master_log_file = 'mysql-bin.000001',
master_log_pos = 137103822;
flush privileges;
-- 基于 gtid 复制
change master to master_host = '192.168.1.10',
master_port = 3306,
master_user = 'replicator',
master_password = 'password',
master_auto_position = 1;
```
# 启动 slave查看 slave 状态
```sql
start slave;
-- 在从服务器上查看 slave 状态
show slave status\G
-- 如果看到
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- 则表示 slave 开启成功!
```
# MySQL8 gtid 互为主从配置
```
[mysqld]
# ---- 固定配置 ----
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
pid-file = /var/lib/mysql/mysql.pid
log-timestamps = SYSTEM
log-error = /var/log/mysql/error.log
slow-query-log = TRUE
slow-query-log-file = /var/log/mysql/slow.log
default-authentication-plugin = mysql_native_password
# ---- 动态配置 ----
mysqlx = OFF
character-set-server = utf8mb4
default-storage-engine = innodb
lower-case-table-names = 1
#skip-name-resolve = 1
#max-user-connections = 600
#innodb-buffer-pool-size = 8G
#innodb-buffer-pool-instances = 8
# master
# 确认不同节点该 id 唯一
server-id = 1
log-bin = /var/lib/mysql-bin/master
binlog-format = ROW
#binlog-do-db = db1
binlog-expire-logs-seconds = 172800
gtid-mode = ON
enforce-gtid-consistency = TRUE
# slave
replicate-wild-ignore-table = information_schema.%
replicate-wild-ignore-table = mysql.%
replicate-wild-ignore-table = performance_schema.%
replicate-wild-ignore-table = sys.%
slave-parallel-workers = 2
log-slave-updates = FALSE
relay-log = /var/lib/mysql-bin/slave
relay-log-recovery = TRUE
#read-only = ON
```
# MySQL8 gtid 多源复制从库配置
- 修改 my.cnf
```
[mysqld]
# ---- 固定配置 ----
datadir = /data/mysql
socket = /var/lib/mysql/mysql.sock
pid-file = /var/lib/mysql/mysql.pid
log-timestamps = SYSTEM
log-error = /var/log/mysql/error.log
slow-query-log-file = /var/log/mysql/slow.log
slow-query-log = TRUE
default-authentication-plugin = mysql_native_password
# ---- 动态配置 ----
mysqlx = OFF
character-set-server = utf8mb4
default-storage-engine = innodb
lower-case-table-names = 1
#skip-name-resolve = 1
#max-user-connections = 600
#innodb-buffer-pool-size = 8G
#innodb-buffer-pool-instances = 8
# master
server-id = 39
log-bin = /var/lib/mysql/master
binlog-format = ROW
#binlog-do-db = db1
gtid-mode = ON
enforce-gtid-consistency = TRUE
binlog-expire-logs-seconds = 172800
# slave
#replicate-wild-do-table = db1.%
replicate-wild-ignore-table = information_schema.%
replicate-wild-ignore-table = mysql.%
replicate-wild-ignore-table = performance_schema.%
replicate-wild-ignore-table = sys.%
slave-parallel-workers = 2
log-slave-updates = FALSE
relay-log = /var/lib/mysql/slave
relay-log-recovery = TRUE
super_read_only = ON
master_info_repository = table
relay_log_info_repository = table
```
- 导出主库数据
```bash
mysqldump -uroot -h<主库1> -p --single-transaction --set-gtid-purged=on --databases db1 > 1_db1.sql
mysqldump -uroot -h<主库2> -p --single-transaction --set-gtid-purged=on --databases db2 > 2_db2.sql
```
- 在导出的文件(1_db1.sql,2_db2.sql)中找到 "SET @@GLOBAL.gtid_purged ..." 语句,记录下来,并在该文件中删除
- 导入 1_db1.sql 和 2_db2.sql
```bash
mysql -uroot -p < 1_db1.sql
mysql -uroot -p < 2_db2.sql
```
- 合并这两个 "SET @@GLOBAL.gtid_purged ..." 语句(gtid set 做并集),导入 gtid set 并集
```sql
set @@global.gtid_purged = '<gtid set 并集>'
```
- 加入两个主库的同步配置
```sql
change master to master_host='<主库1>',
master_port=3306,
master_user='<主库上的 replication 账户>',
master_password='<主库上的 replication 账户的密码>',
master_auto_position=1 for channel '<master_1>';
change master to master_host='<主库2>',
master_port=3306,
master_user='<主库上的 replication 账户>',
master_password='<主库上的 replication 账户的密码>',
master_auto_position=1 for channel '<master_2>';
```
- 启动从库
```sql
start slave for channel '<master_1>';
start slave for channel '<master_2>';
```
- 查看从库
```sql
show slave status for channel '<master_1>'\G
show slave status for channel '<master_2>'\G
```
- 停止从库
```sql
-- 停止全部 slave
stop slave;
-- 停止指定 slave
stop slave for channel '...';
```
- 重置从库
```sql
-- 重置全部 slave
reset slave;
-- 重置指定 slave
reset slave for channel '...';
```
- 监控表: performance_schema.replication_connection_status

406
content/post/mysql.md Normal file
View File

@ -0,0 +1,406 @@
---
title: "Mysql 笔记"
date: 2019-10-30T11:51:23+08:00
lastmod: 2019-10-30T11:51:23+08:00
tags: ["mysql"]
categories: ["database"]
---
# MySQL 5.7 配置文件 my.cnf
```
[mysqld]
datadir = /db/mysql
socket = /var/lib/mysql/mysql.sock
symbolic-links = 0
log-timestamps = SYSTEM
slow-query-log = 1
slow-query-log-file = /var/log/mysqld/slow.log
long-query-time = 8
#log-queries-not-using-indexes = 1
log-error = /var/log/mysqld/error.log
pid-file = /var/run/mysqld/mysqld.pid
max-connections = 1000
max-connect-errors = 1000
max-user-connections = 600
interactive-timeout = 3600
wait-timeout = 3600
skip-name-resolve = 1
lower-case-table-names = 1
default-time-zone = '+08:00'
character-set-server = utf8mb4
sql-mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
bind-address = 0.0.0.0
table-open-cache = 2048
default-storage-engine = innodb
innodb-autoinc-lock-mode = 2
innodb-flush-log-at-trx-commit = 0
# 建议物理内存一半
innodb-buffer-pool-size = 8G
innodb-buffer-pool-instances = 8
max-allowed-packet = 512M
query-cache-size = 0
query-cache-type = 0
# 建议点分 ip 的最后一个数字
server-id = 123
# bin log
#binlog-format = ROW
#log-bin = /var/lib/mysql/mysql-bin
#expire-logs-days = 3
# relay log
#read-only = 1
#replicate-wild-do-table = db1.%
#relay-log = /var/lib/mysql/mysql-relay-bin
#slave-parallel-type = logical-clock
```
# 复制表结构
```sql
create table db1.t1 like db2.t2;
create table db1.t1 select db2.t2 where 1=2;
```
# 复制表结构及其数据
```sql
create table db1.t1 select db2.t2 [where ...]
```
# 复制表数据
```
insert into db2.t2(column1, column2 ...)
select column1, column2 ... from db1.t1 [where ...]
```
# 通过复制表文件来复制表数据
- 在db2中创建同结构表
```sql
create table db2.t1 like db1.t1;
```
- 丢弃表空间
```sql
alter table db2.t1 discard tablespace;
```
- 复制 t1 的表数据文件
```bash
#关闭数据库
systemctl stop mysqld
cd /var/lib/mysql
scp db1/t1.idb db2/t1.idb
chown mysql.mysql db2/t1.idb
#启动数据库
systemctl start mysqld
```
- 导入表空间
```sql
alter table db2.t1 import tablespace;
```
# 设置一个表的空列自增
```sql
-- 删除可能存在的主键
alter table 表名 drop primary key;
alter table 表名 modify 列名 auto_increment primary key;
```
# 查看数据库中每个表的全部列名
```sql
select table_name, column_name from
information_schema.columns
where table_schema = '数据库名';
```
# 查看数据库中每个表的行数
```sql
select table_name, table_rows
from information_schema.tables
where table_schema = '数据库名';
```
# 查看数据库中每个表的索引
```sql
select table_name, column_name, index_name
from INFORMATION_SCHEMA.STATISTICS
where table_schema = '数据库名';
```
# 表的部分列数据到另一个表
```sql
update db2.t2(column1, column2 ...) = (
select column1, column2 from db1.t1
where db1.t1.id = db2.t2.id);
```
# 把语句执行结果写到文件
```bash
mysql -uroot -p -hsever_ip -Ddb_name
-Ne "select ... from table_name;" > file_name
```
# 表分区
- 查看表的分区情况
```sql
select table_schema, table_name, partition_name, table_rows
from information_schema.partitions
where table_name = 'table_name';
```
- 建表时指定
```sql
create table table_name(...)
partition by range columns(column_name)
(partition part_name values less than(some_value));
```
- 修改成分区表
```sql
alter table table_name
partition by range(column_name)
(partition part_name values less than(som_value));
```
- 增加分区
```sql
alter table table_name add partition
(partition part_name values less than(som_value));
```
- 删除分区
```sql
alter table table_name drop partition part_name;
```
- 合并/拆分分区
```sql
alter table table_name
reorganize part_old_1, part_old_2, part_old_3 into
(partition part_new_1 values less than(value_1),
partition part_new_2 values less than(value_2));
```
- 重建分区,整理分区碎片
```sql
alter table table_name
rebuild partition part_name_1, part_name_2;
```
- 优化分区,回收空间,整理碎片
```sql
alter table table_name
optimize partition part_name_1, part_name_2;
```
- 分析分区,读取并保存分区的健分布
```sql
alter table table_name
analyze partition part_name_1, part_name_2;
```
- 修复分区
```sql
alter table table_name
repair partition part_name_1, part_name_2;
```
- 检查分区
```sql
alter table table_name
check partition part_name_1, part_name_2;
```
# MySQL 5.7 从库多线程同步
```sql
stop slave;
set global slave_parallel_type='logical_clock';
set global slave_parallel_workers=4;
start slave;
show processlist;
```
# MySQL 5.7 提示密码复杂度不够
```sql
set global validate_password_policy=0;
```
# MySQL 5.7 从库复制失败跳过指定数量的事务
```sql
stop slave;
-- 跳过一个事务
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
start slave;
-- 修改 my.cnf
slave-skip-errors=1062,1053,1146,1032 #跳过指定error no类型的错误
slave-skip-errors=all #跳过所有错误
```
# MySQL 5.7 查看全部任务
```sql
-- 分号换成 \G 显示完整 sql
show processlist;
show full processlist;
SELECT command FROM information_schema.processlist;
```
# MySQL 5.7 ssl 连接
```
--ssl-mode=REQUIRED
```
# MariaDB 10.1 修改密码
```sql
UPDATE user SET password=password('newpassword') WHERE user='root';
```
# MySQL 5.7 编码
- 查看
```sql
SHOW VARIABLES LIKE 'character_set%';
```
- 数据库连接参数中characterEncoding=utf8 会被自动识别为 utf8mb4但是 autoReconnect=true 必须指定
- 更改数据库编码
```sql
ALTER DATABASE db_name
CHARSET UTF8MB4 COLLATE UTF8MB4_GENERAL_CI;
```
- 更改表编码
```sql
ALTER TABLE table_name
CONVERT TO CHARSET UTF8MB4 COLLATE UTF8MB4_GENERAL_CI;
```
# MySQL 5.7 升级数据库管理表结构
```bash
mysql_upgrade -u root -p
```
# MySQL 5.7 误删 root 后恢复 root 账户
- 停止 mysql 服务
```bash
systemctl stop mysqld
```
- 修改 my.cnf
```
# 添加如下一行
skip-grant-tables
```
- 启动 mysql 服务
```bash
systemctl start mysqld
```
- 重建 root 账户,并授权
```sql
insert into user
set user='root',
ssl_cipher='',
x509_issuer='',
x509_subject='';
update user
set Host='localhost',
select_priv='y',
insert_priv='y',
update_priv='y',
Alter_priv='y',
delete_priv='y',
create_priv='y',
drop_priv='y',
reload_priv='y',
shutdown_priv='y',
Process_priv='y',
file_priv='y',
grant_priv='y',
References_priv='y',
index_priv='y',
create_user_priv='y',
show_db_priv='y',
super_priv='y',
create_tmp_table_priv='y',
Lock_tables_priv='y',
execute_priv='y',
repl_slave_priv='y',
repl_client_priv='y',
create_view_priv='y',
show_view_priv='y',
create_routine_priv='y',
alter_routine_priv='y',
create_user_priv='y',
event_priv='y',
trigger_priv='y',
create_tablespace_priv='y'
where user='root';
flush privileges;
```
- 停止 mysql 服务
```bash
systemctl stop mysqld
```
- 修改 my.cnf
```
# 删除刚添加的如下一行
#skip-grant-tables
```
- 启动 mysql 服务root 账户正常可用
```bash
systemctl start mysqld
```
# 通过EXPLAIN分析SQL的执行计划
- 使用
```sql
explain sql
```
- select_type 查询类型
- SIMPLE 简单表,没有表连接或子查询
- PRIMARY 最外层的查询
- UNION union语句的后置查询
- SUBQUERY 第一个子查询
- table 表/别名
- type 访问类型
- ALL 全表扫描
- index 全索引扫描
- range 索引范围扫描
- ref 非唯一索引扫描
- eq_ref 唯一索引扫描
- const,system 单表最多一个匹配行
- NULL 不需要扫描表或索引
- possible_keys 查询可能使用的索引
- key 实际使用的索引
- key_len 使用的索引字段的长度
- ref 其他匹配字段
- rows 扫描行的数量
- filtered 满足查询条件的记录占存储引擎返回记录的比例
- Extra 执行情况说明
- Using Index 全部使用索引,没有回表查询
- Using Where 有回表查询
- Using Index Condition ICP优化直接在存储引擎完成条件过滤
- Using Flesort 依靠索引顺序达不到排序效果,需额外排序
# 统计 insert、delete、update 和 select 次数
```sql
show global status where Variable_name in
('com_insert', 'com_delete', 'com_update', 'com_select');
```
# csv 文件
- 导出
```
# Shell 终端
# mysql -e "select * from t1
into outfile '/var/lib/mysql-files/t1.csv'
fields terminated by ','
enclosed by '\"'
escaped by '\\\'
lines terminated by '\n'"
# MySQL 终端
# MySQL> select * from t1
into outfile '/var/lib/mysql-files/t1.csv'
fields terminated by ','
enclosed by '\"'
escaped by '\\'
lines terminated by '\n';
```
- 导入
```
# Shell 终端
# mysql -e "load data infile '/var/lib/mysql-files/t1.csv'
into table t1
fields terminated by ','
enclosed by '\"'
escaped by '\\\'
lines terminated by '\n'"
# MySQL 终端
# MySQL> load data infile '/var/lib/mysql-files/t1.csv'
into table t1
fields terminated by ','
enclosed by '\"'
escaped by '\\'
lines terminated by '\n';
```

View File

@ -0,0 +1,57 @@
---
title: "CentOS7 yum 安装 Mysql5.7"
date: 2019-10-30T13:00:28+08:00
lastmod: 2019-10-30T13:00:28+08:00
tags: ["centos", "yum", "mysql"]
categories: ["database"]
---
# 环境
- CentOS 7.4 x86_64 最小安装
- MySQL 5.7.20
# 下载 mysql 源安装包
```bash
#repo 地址: https://repo.mysql.com/
cd /root/
curl -O https://repo.mysql.com/mysql57-community-release-el7.rpm
```
# 安装 mysql 源
```bash
rpm -ivh /root/mysql57-community-release-el7.rpm
```
# 更新 yum 缓存
```bash
yum clean all
yum makecache fast
```
# 安装 mysql
```bash
yum install mysql-community-server
```
# 启动 mysql
```bash
systemctl start mysqld
```
# 查找 mysql 默认密码
```bash
grep 'temporary password' /var/log/mysqld.log
mysql -uroot -p
# 输入查找到的密码
```
# 修改 mysql 本地密码
- 在 mysql 下修改
```sql
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'Pass-1234';
```
- 或者直接在终端修改
```bash
mysqladmin -uroot -p password 'Pass-1234'
```

View File

@ -0,0 +1,202 @@
---
title: "NetworKmanager"
date: 2019-10-29T18:26:17+08:00
lastmod: 2019-10-29T18:40:00+08:00
keywords: ["centos", "networkmanager", "network"]
tags: ["centos", "networkmanager", "network"]
categories: ["network"]
---
# 环境
- CentOS8 已废弃 network.service, 推荐使用 NetworkManager
# 概念
- 在NM里有2个维度: 连接(connection)和设备(device),这是多对一的关系
- 想给某个网卡配ip首先NM要能纳管这个网卡。设备里存在的网卡(即 nmcli d可以看到的)就是NM纳管的
- 可以为一个设备配置多个连接(即 nmcli c可以看到的)每个连接可以理解为一个ifcfg配置文件
- 同一时刻,一个设备只能有一个连接活跃,可以通过 nmcli c up切换连接
# 配置连接
- 状态
- 活跃(带颜色字体)表示当前该connection生效
- 非活跃(正常字体)表示当前该connection不生效
- 创建 connection配置静态 ip
```bash
nmcli c add \
type ethernet \
con-name ethX \
ifname ethX \
ipv4.addr 192.168.1.100/24 \
ipv4.gateway 192.168.1.1 \
ipv4.method manual \
autoconnect yes
# type ethernet:创建连接时候必须指定类型,类型有很多,可通过 "nmcli c add type -h" 看到
# con-name ethX: 表示连接(connection)的名字,可任意定义,无需和网卡名相同
# ifname ethX: 表示网卡名,这个 ethX 必须是在 nmcli d里能看到的
# ipv4.addr: 指定一个或多个 ip 地址
# ipv4.gateway: 网关
# ipv4.method: 对应ifcfg文件内容的BOOTPROTO
# ipv4.method 默认为auto对应为BOOTPROTO=dhcp这种时候如果指定ip就可能导致网卡同时有dhcp分配的ip和静态ip
# ipv4.method 设置为manual表示BOOTPROTO=none即只有静态ip
# 如果这是为ethX创建的第一个连接则自动生效
# 如果此时已有连接存在,则该连接不会自动生效,可以执行 nmcli c up ethX-test来切换生效
# autoconnect: 开机后自动连接
```
- 创建 connection配置多个静态 ip
```bash
nmcli c add \
type ethernet \
con-name ethX-X \
ifname ethX \
ipv4.addr '192.168.1.100/24,192.10.0.3.100/25' \
ipv4.routes '192.168.0.0/16 192.168.1.10,10.0.0.0/8 10.0.3.1' \
ipv4.gateway 192.168.1.254 \
ipv4.dns '8.8.8.8,4.4.4.4' \
ipv4.method manual
# ipv4.routes: 设置自定义路由
# ipv4.dns: 设置 dns
```
- 创建 connection配置动态 ip
```bash
nmcli c add \
type ethernet \
con-name ethX \
ifname ethX \
ipv4.method auto
```
- 修改 ip
```bash
# ethX 是 connection name也可以指定 connection UUID
# 直接替换
nmcli c modify ethX \
ipv4.addr '192.168.1.200/24'
nmcli c up ethX
# 通过nmcli c modify修改con-name只会对应修改ifcfg文件中的NAME而不会更改ifcfg文件名
# 增加 ip
nmcli c modify ethX \
+ipv4.addr '192.168.2.200/24'
+ipv4.routes '10.1.0.0/16 192.168.2.1'
nmcli c up ethX
# 删除 ip
nmcli c modify ethX \
-ipv4.addr '192.168.2.200/24'
-ipv4.routes '10.1.0.0/16 192.168.2.1'
nmcli c up ethX
```
- 操作 connection
```bash
# ethX 是 connection name也可以指定 connection UUID
# 启动
nmcli c up ethX
# 停止
nmcli c down ethX
# 删除
nmcli c delete ethX
# 删除当前连接后,会自动选择同一个设备的其他连接来顶替生效
```
- 查看 connection
```bash
# ethX 是 connection name也可以指定 connection UUID
# 查看列表
nmcli c show
# 查看活动连接列表
nmcli c show -a
# 查看指定 connection 详细信息
nmcli c show ethX
```
- 重载配置但不立即生效
```bash
# 重载全部 connection 的所有 ifcfg-xxxx 和 route-xxxx
nmcli c reload
# 重载指定 ifcfg-ethX 和 route-ethX
nmcli c load /etc/sysconfig/network-scripts/ifcfg-ethX
nmcli c load /etc/sysconfig/network-scripts/route-ethX
```
- 重载配置并立即生效
```bash
# ethXX 是 connection name也可以指定 connection UUID
nmcli c up ethXX
# ethX 是 device name
nmcli d reapply ethX
nmcli d connect ethX
```
# 配置网卡设备
- 状态
- connected: 已被NM纳管并且当前有活跃的connection
- disconnected: 已被NM纳管但是当前没有活跃的connection
- unmanaged: 未被NM纳管
- unavailable: 不可用NM无法纳管通常出现于网卡link为down的时候(比如ip link set ethX down)
- 查看网卡列表
```bash
nmcli d
# 查看全部网卡的详细信息
nmcli d show
```
- 操作网卡
```bash
# ethX 是 device name
# 设置 nm 管理网卡 ethX
# 并刷新该网卡对应的活跃 connection(如果之前有修改过connection配置)
# 如果有connection但是都处于非活跃状态则自动选择一个connection并将其活跃
# 如果没有connection则自动生成一个并将其活跃
nmcli d connect ethX
# 设置 nm 不管理网卡 ethX
# 此操作不会变更实际网卡的link状态只会使对应的connection变成非活跃
# 若重启系统则又会自动connect
# 另外如果手工将该网卡的connection全部删掉该网卡状态也会自动变为disconnected
nmcli d disconnect ethX
# 设置 nm 是否自动启动网卡
nmcli d set ethX autoconnect yes|no
# 设置 nm 是否自动管理网卡
nmcli d set ethX managed yes|no
```
- 关闭无线网络(默认启动)
```bash
nmcli r all off
```
# NM 状态
- 查看当前 nm 连接信息
```bash
nmcli
```
- 查看当前 nm 全部状态
```bash
nmcli general status
```
- 纳管状态
```bash
# 查看
nmcli n
# 开启
nmcli n on
# 关闭
nmcli n off
```
- 查看 nm 当前是否在线可用
```bash
nm-oncline
```
# 注意事项
- 如果希望NM不要纳管网卡只有一个办法最彻底最靠谱就是自己写ifcfg内容加上 NM_CONTROLLED=no这样该device的状态就会始终保持unmanaged。nmcli c up、nmcli c reload、nmcil c load都不会对其起任何作用
- NM只能对link状态为up的网卡进行操作如果手动 ip link set ethX down那么NM就无法对该网卡做任何操作(即使nmcli d connect也没有用)
- NetworkManager支持3种获取dhcp的方式dhclient、dhcpcd、internal当/etc/NetworkManager/NetworkManager.conf配置文件中的[main]部分没配置 dhcp=时候默认使用internalrhel7/centos7默认是dhclient。internal是NM内部实现的dhcp客户端
- NM默认会从dhcp里获取dns信息并修改/etc/resolv.conf如果不想让NM管理/etc/resolv.conf则只需在/etc/NetworkManager/NetworkManager.conf里的[main]里增加 dns=none即可
- 如果想让NM不要自动管理新网卡比如不要给新网卡获取ip地址则只需在/etc/NetworkManager/NetworkManager.conf里的[main]里增加 no-auto-default=\* 即可,改完后通过 systemctl restart NetworkManager 或者重启系统来生效

88
content/post/nfs.md Normal file
View File

@ -0,0 +1,88 @@
---
title: "Nfs 笔记"
date: 2019-10-30T00:51:22+08:00
lastmod: 2019-10-30T00:51:22+08:00
keywords: []
tags: ["nfs"]
categories: ["storage"]
---
# 环境
- 服务端 CentOS7 192.168.1.100
- 客户端 CentOS7 192.168.1.101
# 服务端
- 安装
```bash
yum install nfs-utils
systemctl enable nfs-server
systemctl start nfs-server
# rpcbind 服务自动 start 并 enable
```
- 创建配置文件
```bash
mkdir /nfs_share -p
chown -R nfsnobody.nfsnobody /nfs_share
cat > /etc/exports.d/mynfs.conf <<EOF
/nfs_share 192.168.1.0/24(rw,sync,all_squash)
EOF
```
- 重新载入配置
```bash
exportfs -r
# 查看配置
exportfs
```
# 客户端
- 安装
```bash
yum install nfs-utils
# 客户端就不需要启动 nfs 服务了
# rpcbind 服务自动 start 并 enable
```
- 查看服务端可用的共享目录
```bash
showmount -e 192.168.1.100
```
- 挂载服务端共享目录
```bash
# 先创建本地目录,用于挂载
mkdir /nfs_client
# 挂载远程 nfs 目录
mount -t nfs 192.168.1.100:/nfs_share /nfs_client
```
# 通信过程
- 首先服务器端启动 RPC 服务,并开启 111 端口
- 服务器端启动 NFS 服务,并向 RPC 注册端口信息
- **注:该端口是用来传输数据的,目前不知道 NFS 选择该端口的依据,如果是随机的,防火墙如何放行?**
- 客户端启动 RPC 服务,向服务端的 RPC 服务请求服务端的 NFS 端口
- 服务端的 RPC 服务反馈 NFS 端口信息给客户端
- 客户端通过获取的 NFS 端口来建立和服务端的 NFS 连接并进行数据的传输
# 服务端共享参数
参数 | 说明
---- | ----
ro | 只读访问
rw | 读写访问
sync | 所有数据在请求时写入共享
async | nfs 在写入数据前可以响应请求
secure | nfs 通过 1024 以下的安全 TCP/IP 端口发送
insecure | nfs 通过 1024 以上的端口发送
wdelay | 如果多个用户要写入 nfs 目录,则归组写入(默认)
no_wdelay | 如果多个用户要写入 nfs 目录,则立即写入,当使用 async 时,无需此设置
hide | 在 nfs 共享目录中不共享其子目录
no_hide | 共享 nfs 目录的子目录
subtree_check | 如果共享 /usr/bin 之类的子目录时,强制 nfs 检查父目录的权限(默认)
no_subtree_check | 不检查父目录权限
all_squash | 共享文件的 UID 和 GID 映射匿名用户 nfsnobody适合公用目录
no_all_squash | 保留共享文件的 UID 和 GID(默认)
root_squash | root 用户的所有请求映射成如 anonymous 用户一样的权限(默认)
no_root_squash | root 用户具有根目录的完全管理访问权限
anonuid=xxxx | 指定 nfs 服务器 /etc/passwd 文件中匿名用户的 UID
anongid=xxxx | 指定 nfs 服务器 /etc/passwd 文件中匿名用户的 GID
# 参考
- [https://www.linuxidc.com/Linux/2019-07/159479.htm](https://www.linuxidc.com/Linux/2019-07/159479.htm)

280
content/post/nginx.md Normal file
View File

@ -0,0 +1,280 @@
---
title: "Nginx 笔记"
date: 2019-10-30T11:47:55+08:00
lastmod: 2019-10-30T11:47:55+08:00
tags: ["nginx", "https", "ssl", "反向代理"]
categories: ["web"]
---
# set
- set ${变量名} {字符串};
# 全局变量
- $args $query_string 请求行中的参数
- $content_length 请求头里的 Content-length 字段
- $content_type 请求头里的 Content-type 字段
- $document_root 请求在 root 指令中指定的值
- $host 请求头里的 Host 字段,如果没有则是服务器名
- $http_user_agent 客户端agent信息
- $http_cookie 客户端cookie信息
- $limit_rate 这个变量可以限制连接速率
- $request_method 客户端请求的动作通常为GET或POST
- $remote_addr 客户端的IP地址
- $remote_port 客户端的端口
- $remote_user 已经经过 Auth Basic Module 验证的用户名
- $request_filename 请求的文件路径,由 root 或 alias 指令与 URI 请求生成
- $scheme http 或者 https
- $server_protocol 请求使用的协议 HTTP/1.0 或 HTTP/1.1
- $server_addr 服务器地址,在完成一次系统调用后可以确定这个值
- $server_name 服务器名称
- $server_port 请求到达服务器的端口号
- $request_uri 包含请求参数的原始URI不包含主机名如"/foo/bar.php?arg=baz"
- $document_uri $uri 不带请求参数的当前URI不包含主机名如"/foo/bar.html"
# rewrite
- rewrite {url正则} {replacement} {flag};
- flag
- last 完成 rewrite重新开始匹配
- break 重写后不再匹配后续 rewrite
- redirect 返回 302 临时重定向
- permanent 返回 301 永久重定向
# if
- if(condition){...}
- false 字符串为空或以 0 开头都是
- = != 变量比较
- ~ !~ 区分大小写正则是否匹配
- ~* !~* 不区分大小写是否匹配
- -f !-f 判断文件是否存在
- -d !-d 判断目录是否存在
- -e !-e 判断文件、目录、链接是否存在
- -x !-x 判断可执行文件是否存在
# location
- = 精确匹配
- ^~ 开头匹配指定字符串,不是正则,匹配符合后停止搜索
- ~ 区分大小写的正则匹配,匹配符合后继续向下搜索
- ~`*` 不区分大小写的正则匹配,匹配符合后继续向下搜索
- / 通用匹配,可匹配任何请求,匹配后继续向下搜索
# try_files
- try_files {file} ... {uri}
- try_files {file} ... ={code}
- try_files {file} ... {location_name}
# 客户端访问控制
- deny all 拒绝全部访问
- deny 192.168.1.0/24 拒绝指定网段
- deny 192.168.1.2 拒绝指定ip
- allow all 允许全部访问(默认)
- allow 192.168.1.0/24 允许指定网段
- allow 192.168.1.2 允许指定ip
# 配置 web 访问目录
```bash
location / {
root /var/www/html/;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
```
# 下载
```nginx
location ^~ /attachment/ {
root /data/;
# alias /data/attachment/;
add_header Content-Disposition: 'attachment;';
}
```
# 浏览目录文件
```nginx
location ^~ /share/ {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
```
# 反向代理负载均衡
- /etc/nginx/conf.d/upstream.conf
```nginx
http {
upstream tomcat {
#ip_hash;
server 192.168.1.201:8443 fail_timeout=32s;
server 192.168.1.202:8443 fail_timeout=32s;
server 192.168.1.203:8443 backup fail_timeout=32s;
keepalive 300;
}
```
- /etc/nginx/conf.d/80.conf
```nginx
server {
listen 80;
server_name _;
location ^~ /webapp/ {
proxy_pass http://tomcat;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header X-Forwarded-Host $host;
#proxy_set_header X-Forwarded-Server $host;
client_max_body_size 8m;
client_body_buffer_size 8m;
proxy_connect_timeout 2s;
#proxy_send_timeout 16;
#proxy_read_timeout 16;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
#proxy_max_temp_file_size 0;
#add_header 'Access-Control-Allow-Origin' *;
}
}
}
```
# 反向代理 websocket
```nginx
location /websocket/ {
proxy_pass http://127.0.0.1:8002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
```
# Basic HTTP 认证
- 生成密码文件(用户名是admin密码是123456)
```bash
echo "admin:$(openssl passwd -crypt 123456)" > /etc/nginx/nginx.auth
#或者
htpasswd -c -m /mnt/vdb1/svnrepos/accesspwd gxfp #根据提示输入密码
```
- 修改 nginx 配置http、server 和 location 都可以
```nginx
location / {
auth_basic "Kibana";
auth_basic_user_file /etc/nginx/nginx.auth;
}
```
# 创建 ssl 密钥
```bash
mkdir /etc/nginx/ssl && cd /etc/nginx/ssl
openssl genrsa -out ssl.key 2048
openssl req -new -key ssl.key -days 3650 -out ssl.csr
openssl x509 -req -in ssl.csr -signkey ssl.key -out ssl.crt
```
# https 访问
```nginx
server {
ssl on;
listen 443 ssl;
server_name www.domain.com;
ssl_certificate /etc/nginx/ssl/ssl.crt;
ssl_certificate_key /etc/nginx/ssl/ssl.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}
```
# http 自动跳转 https有三种配置
- rewrite 服务端重定向
```nginx
server {
listen 80;
server_name www.domain.com;
rewrite ^(.*) https://$server_name$1 permanent;
}
```
- return 客户端重定向
```nginx
server {
listen 80;
server_name www.domain.com;
return 301 https://$server_name$request_uri;
}
```
- error_page 客户端重定向
```nginx
server {
ssl on;
listen 80;
listen 443 ssl;
server_name www.domain.com;
ssl_certificate /etc/nginx/ssl/ssl.crt;
ssl_certificate_key /etc/nginx/ssl/ssl.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
error_page 497 https://$server_name$request_uri;
}
```
# http 和 https 共存
```nginx
server {
listen 80;
listen 443 ssl;
server_name www.domain.com;
ssl_certificate /etc/nginx/ssl/ssl.crt;
ssl_certificate_key /etc/nginx/ssl/ssl.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}
```
# nginx 日志配置
- http 常规日志
```
log_format main '$remote_addr - [$time_local] "$request_method $uri" "$args" '
'"-" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
```
- http 登陆日志,打印 post 请求体
```
log_format login '$remote_addr - [$time_local] "$request_method $uri" "$args" '
'"$request_body" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
```
- https 常规日志,从 http_x_forwoarded_for 中获取请求源地址
```
log_format smain '$http_x_forwarded_for - [$time_local] "$request_method $uri" "$args" '
'"-" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "-"';
```
- https 登陆日志,从 http_x_forwoarded_for 中获取请求源地址,并打印 post 请求体
```
log_format slogin '$http_x_forwarded_for - [$time_local] "$request_method $uri" "$args" '
'"$request_body" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "-"';
```
# 常用全局配置
```nginx
events {
use epoll;
multi_accept on;
worker_connections 10240;
}
http {
access_log /var/log/nginx/access.log main;
gzip on;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
server_tokens off;
keepalive_timeout 65;
types_hash_max_size 2048;
}
```

View File

@ -0,0 +1,175 @@
---
title: "CentOS7 安装 Openvpn"
date: 2019-10-30T01:12:40+08:00
lastmod: 2019-10-30T01:12:40+08:00
tags: ["openvpn"]
categories: ["network"]
---
# 环境
角色 | 主机名 | 操作系统 | IP
---- | ---- | ---- | ----
vpn 服务端 | vpn-server | CentOS7 | 192.168.1.90
vpn 客户端 | vpn-client | CentOS7 | 192.168.1.91
# 两台服务器初始准备
- 关闭 SELinux
- 关闭防火墙或放行 udp 端口 1194
- 安装 openvpn
```bash
yum install epel-release
yum clean all
yum makecache fast
yum install easy-rsa openvpn
```
# 在 vpn-server 上创建证书
- 复制 easy-rsa 脚本到 /opt/easy-rsa/ 下
```bash
cp -af /usr/share/easy-rsa/3.0.3/ /opt/easy-rsa
# vars 文件包含证书相关配置,可修改
cp /usr/share/doc/easy-rsa-3.0.3/vars.example /opt/easy-rsa/vars
```
- 初始化 pki 目录结构
```bash
cd /opt/easy-rsa
./easyrsa init-pki
```
- 生成免密 ca 证书
```bash
# 使用默认 common name 即可
./easyrsa build-ca nopass
```
- 生成服务端免密证书
```bash
# 参数 my-server0 指定生成的客户端证书文件名及其 common name
./easyrsa build-server-full my-server0 nopass
```
- 生成客户端免密证书
```bash
# 参数 my-client0 指定生成的客户端证书文件名及其 common name
# 不同的客户端需指定不同的 common name
# 方便在 client-conf-dir 目录下创建对应的同名客户端配置文件
./easyrsa build-client-full my-client0 nopass
```
- 生成 dh.pem
```bash
./easyrsa gen-dh
```
- 生成 ta.key
```bash
openvpn --genkey --secret pki/ta.key
```
- 查看证书目录
```
/opt/easy-rsa/
├── easyrsa
├── openssl-1.0.cnf
├── pki
│ ├── ca.crt
│ ├── certs_by_serial
│ │ ├── 1835C740AD1421868300998618C0641F.pem
│ │ └── 4F3AF1ED7D42ED56CCF26CC7622F4F50.pem
│ ├── dh.pem
│ ├── index.txt
│ ├── index.txt.attr
│ ├── index.txt.attr.old
│ ├── index.txt.old
│ ├── issued
│ │ ├── my-client0.crt
│ │ └── my-server0.crt
│ ├── private
│ │ ├── ca.key
│ │ ├── my-client0.key
│ │ └── my-server0.key
│ ├── reqs
│ │ ├── my-client0.req
│ │ └── my-server0.req
│ ├── serial
│ ├── serial.old
│ └── ta.key
├── vars
└── x509-types
├── ca
├── client
├── COMMON
├── san
└── server
```
- **该证书目录 /opt/easyrsa 需妥善保管,后期增加其他客户端证书时会用到**
# 配置 vpn-server
- 开启路由转发,修改 /etc/sysctl.conf
```bash
sysctl -w 'net.ipv4.ip_forward = 1'
sysctl -p
```
- 复制服务端证书到 openvpn 配置目录下
```bash
mkdir -p /etc/openvpn/server/my-server0/
cd /opt/easy-rsa/pki
cp ca.crt dh.pem issued/my-server0.crt private/my-server0.key ta.key \
/etc/openvpn/server/my-server0/
```
- 创建 /etc/openvpn/server/my-server0.conf
```bash
cd /usr/share/doc/openvpn-2.4.7/sample/sample-config-files
cp server.conf /etc/openvpn/server/my-server0.conf
```
- 修改 /etc/openvpn/server/my-server0.conf
```
ca my-server0/ca.crt
cert my-server0/my-server0.crt
key my-server0/my-server0.key
dh my-server0/dh.pem
tls-auth my-server0/ta.key 0
```
# 启动 vpn-server 服务
- 启动 openvpn-server@my-server0.service 服务
```bash
systemctl start openvpn-server@my-server0.service
```
- 如需提供 ca 密码
```bash
systemd-tty-ask-password-agent --query
```
# 配置 vpn-client
- 复制 vpn-server 上的客户端证书到 openvpn 配置目录下
```bash
mkdir -p /etc/openvpn/client/my-client0
scp vpn-server:/opt/easy-rsa/pki/{ca.crt,issued/my-client0.crt,private/my-client0.key,ta.key} /etc/openvpn/client/my-client0/
```
- 创建 /etc/openvpn/client/my-client0.conf
```bash
cd /usr/share/doc/openvpn-3.0.3/sample/sample-config-files
cp client.conf /etc/openvpn/client/my-client0.conf
```
- 修改 /etc/openvpn/client/my-client0.conf
```
remote 192.168.1.90 1194 # vpn server 地址
ca my-client0/ca.crt
cert my-client0/client.crt
key my-client0/client.key
tls-auth my-client0/ta.key 1
```
# 启动 vpn-client 服务
- 启动 openvpn-client@my-client0 服务
```bash
systemctl start openvpn-client@my-client0.service
```
- 如需提供 ca 密码
```bash
systemd-tty-ask-password-agent --query
```
# 验证
- vpn server 新增网卡 tun0地址是 10.8.0.1/24
- vpn client 新增网卡 tun0地址是 10.8.0.2/24
# 参考
- [创建证书](https://blog.csdn.net/zhuwei_clark/article/details/87949043)

325
content/post/openvpn.md Normal file
View File

@ -0,0 +1,325 @@
---
title: "Openvpn 笔记"
date: 2019-10-30T00:45:06+08:00
lastmod: 2019-10-30T00:45:06+08:00
keywords: []
tags: ["openvpn"]
categories: ["network"]
---
# 服务端配置文件 server.conf
```
#################################################
# 针对多客户端的OpenVPN 2.0 的服务器端配置文件示例
#
# 本文件用于多客户端<->单服务器端的OpenVPN服务器端配置
#
# OpenVPN也支持单机<->单机的配置(更多信息请查看网站上的示例页面)
#
# 该配置支持Windows或者Linux/BSD系统。此外在Windows上记得将路径加上双引号
# 并且使用两个反斜杠,例如:"C:\\Program Files\\OpenVPN\\config\\foo.key"
#
# '#' or ';'开头的均为注释内容
#################################################
#OpenVPN应该监听本机的哪些IP地址
#该命令是可选的如果不设置则默认监听本机的所有IP地址。
;local a.b.c.d
# OpenVPN应该监听哪个TCP/UDP端口
# 如果你想在同一台计算机上运行多个OpenVPN实例你可以使用不同的端口号来区分它们。
# 此外,你需要在防火墙上开放这些端口。
port 1194
#OpenVPN使用TCP还是UDP协议?
;proto tcp
proto udp
# 指定OpenVPN创建的通信隧道类型。
# "dev tun"将会创建一个路由IP隧道
# "dev tap"将会创建一个以太网隧道。
#
# 如果你是以太网桥接模式,并且提前创建了一个名为"tap0"的与以太网接口进行桥接的虚拟接口,则你可以使用"dev tap0"
#
# 如果你想控制VPN的访问策略你必须为TUN/TAP接口创建防火墙规则。
#
# 在非Windows系统中你可以给出明确的单位编号(unit number),例如"tun0"。
# 在Windows中你也可以使用"dev-node"。
# 在多数系统中除非你部分禁用或者完全禁用了TUN/TAP接口的防火墙否则VPN将不起作用。
;dev tap
dev tun
# 如果你想配置多个隧道你需要用到网络连接面板中TAP-Win32适配器的名称(例如"MyTap")。
# 在XP SP2或更高版本的系统中你可能需要有选择地禁用掉针对TAP适配器的防火墙
# 通常情况下非Windows系统则不需要该指令。
;dev-node MyTap
# 设置SSL/TLS根证书(ca)、证书(cert)和私钥(key)。
# 每个客户端和服务器端都需要它们各自的证书和私钥文件。
# 服务器端和所有的客户端都将使用相同的CA证书文件。
#
# 通过easy-rsa目录下的一系列脚本可以生成所需的证书和私钥。
# 记住服务器端和每个客户端的证书必须使用唯一的Common Name。
#
# 你也可以使用遵循X509标准的任何密钥管理系统来生成证书和私钥。
# OpenVPN 也支持使用一个PKCS #12格式的密钥文件(详情查看站点手册页面的"pkcs12"指令)
ca ca.crt
cert server.crt
key server.key # 该文件应该保密
# 指定迪菲·赫尔曼参数。
# 你可以使用如下名称命令生成你的参数:
# openssl dhparam -out dh1024.pem 1024
# 如果你使用的是2048位密钥使用2048替换其中的1024。
dh dh1024.pem
# 设置服务器端模式并提供一个VPN子网以便于从中为客户端分配IP地址。
# 在此处的示例中服务器端自身将占用10.8.0.1,其他的将提供客户端使用。
# 如果你使用的是以太网桥接模式,请注释掉该行。更多信息请查看官方手册页面。
server 10.8.0.0 255.255.255.0
# 指定用于记录客户端和虚拟IP地址的关联关系的文件。
# 当重启OpenVPN时再次连接的客户端将分配到与上一次分配相同的虚拟IP地址
ifconfig-pool-persist ipp.txt
# 该指令仅针对以太网桥接模式。
# 首先你必须使用操作系统的桥接能力将以太网网卡接口和TAP接口进行桥接。
# 然后你需要手动设置桥接接口的IP地址、子网掩码
# 在这里我们假设为10.8.0.4和255.255.255.0。
# 最后我们必须指定子网的一个IP范围(例如从10.8.0.50开始到10.8.0.100结束),以便于分配给连接的客户端。
# 如果你不是以太网桥接模式,直接注释掉这行指令即可。
;server-bridge 10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100
# 该指令仅针对使用DHCP代理的以太网桥接模式
# 此时客户端将请求服务器端的DHCP服务器从而获得分配给它的IP地址和DNS服务器地址。
#
# 在此之前你也需要先将以太网网卡接口和TAP接口进行桥接。
# 注意该指令仅用于OpenVPN客户端并且该客户端的TAP适配器需要绑定到一个DHCP客户端上。
;server-bridge
# 推送路由信息到客户端,以允许客户端能够连接到服务器背后的其他私有子网。
# (简而言之就是允许客户端访问VPN服务器自身所在的其他局域网)
# 记住这些私有子网也要将OpenVPN客户端的地址池(10.8.0.0/255.255.255.0)反馈回OpenVPN服务器。
;push "route 192.168.10.0 255.255.255.0"
;push "route 192.168.20.0 255.255.255.0"
# 为指定的客户端分配指定的IP地址或者客户端背后也有一个私有子网想要访问VPN
# 那么你可以针对该客户端的配置文件使用ccd子目录。
# (简而言之就是允许客户端所在的局域网成员也能够访问VPN)
# 举个例子假设有个Common Name为"Thelonious"的客户端背后也有一个小型子网想要连接到VPN该子网为192.168.40.128/255.255.255.248。
# 首先,你需要去掉下面两行指令的注释:
;client-config-dir ccd
;route 192.168.40.128 255.255.255.248
# 然后创建一个文件ccd/Thelonious该文件的内容为
# iroute 192.168.40.128 255.255.255.248
#这样客户端所在的局域网就可以访问VPN了
# 注意,这个指令只能在你是基于路由、而不是基于桥接的模式下才能生效。
# 比如,你使用了"dev tun"和"server"指令。
# 再举个例子假设你想给Thelonious分配一个固定的IP地址10.9.0.1。
# 首先,你需要去掉下面两行指令的注释:
;client-config-dir ccd
;route 10.9.0.0 255.255.255.252
# 然后在文件ccd/Thelonious中添加如下指令
# ifconfig-push 10.9.0.1 10.9.0.2
# 如果你想要为不同群组的客户端启用不同的防火墙访问策略,你可以使用如下两种方法:
# (1)运行多个OpenVPN守护进程每个进程对应一个群组并为每个进程(群组)启用适当的防火墙规则。
# (2) (进阶)创建一个脚本来动态地修改响应于来自不同客户的防火墙规则。
# 关于learn-address脚本的更多信息请参考官方手册页面。
;learn-address ./script
# 如果启用该指令所有客户端的默认网关都将重定向到VPN这将导致诸如web浏览器、DNS查询等所有客户端流量都经过VPN。
# (为确保能正常工作OpenVPN服务器所在计算机可能需要在TUN/TAP接口与以太网之间使用NAT或桥接技术进行连接)
;push "redirect-gateway def1 bypass-dhcp"
# 某些具体的Windows网络设置可以被推送到客户端例如DNS或WINS服务器地址。
# 下列地址来自opendns.com提供的Public DNS 服务器。
;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.220.220"
# 去掉该指令的注释将允许不同的客户端之间相互"可见"(允许客户端之间互相访问)。
# 默认情况下,客户端只能"看见"服务器。为了确保客户端只能看见服务器你还可以在服务器端的TUN/TAP接口上设置适当的防火墙规则。
;client-to-client
# 如果多个客户端可能使用相同的证书/私钥文件或Common Name进行连接那么你可以取消该指令的注释。
# 建议该指令仅用于测试目的。对于生产使用环境而言,每个客户端都应该拥有自己的证书和私钥。
# 如果你没有为每个客户端分别生成Common Name唯一的证书/私钥,你可以取消该行的注释(但不推荐这样做)。
;duplicate-cn
# keepalive指令将导致类似于ping命令的消息被来回发送以便于服务器端和客户端知道对方何时被关闭。
# 每10秒钟ping一次如果120秒内都没有收到对方的回复则表示远程连接已经关闭。
keepalive 10 120
# 出于SSL/TLS之外更多的安全考虑创建一个"HMAC 防火墙"可以帮助抵御DoS攻击和UDP端口淹没攻击。
# 你可以使用以下命令来生成:
# openvpn --genkey --secret ta.key
#
# 服务器和每个客户端都需要拥有该密钥的一个拷贝。
# 第二个参数在服务器端应该为'0',在客户端应该为'1'。
;tls-auth ta.key 0 # 该文件应该保密
# 选择一个密码加密算法。
# 该配置项也必须复制到每个客户端配置文件中。
;cipher BF-CBC # Blowfish (默认)
;cipher AES-128-CBC # AES
;cipher DES-EDE3-CBC # Triple-DES
# 在VPN连接上启用压缩。
# 如果你在此处启用了该指令,那么也应该在每个客户端配置文件中启用它。
comp-lzo
# 允许并发连接的客户端的最大数量
;max-clients 100
# 在完成初始化工作之后降低OpenVPN守护进程的权限是个不错的主意。
# 该指令仅限于非Windows系统中使用。
;user nobody
;group nobody
# 持久化选项可以尽量避免访问那些在重启之后由于用户权限降低而无法访问的某些资源。
persist-key
persist-tun
# 输出一个简短的状态文件,用于显示当前的连接状态,该文件每分钟都会清空并重写一次。
status openvpn-status.log
# 默认情况下日志消息将写入syslog(在Windows系统中如果以服务方式运行日志消息将写入OpenVPN安装目录的log文件夹中)。
# 你可以使用log或者log-append来改变这种默认情况。
# "log"方式在每次启动时都会清空之前的日志文件。
# "log-append"这是在之前的日志内容后进行追加。
# 你可以使用两种方式之一(但不要同时使用)。
;log openvpn.log
;log-append openvpn.log
# 为日志文件设置适当的冗余级别(0~9)。冗余级别越高,输出的信息越详细。
#
# 0 表示静默运行,只记录致命错误。
# 4 表示合理的常规用法。
# 5 和 6 可以帮助调试连接错误。
# 9 表示极度冗余,输出非常详细的日志信息。
verb 3
# 重复信息的沉默度。
# 相同类别的信息只有前20条会输出到日志文件中。
;mute 20
```
# 客户端配置文件
```
##############################################
# 针对多个客户端的OpenVPN 2.0 的客户端配置文件示例
#
# 该配置文件可以被多个客户端使用,当然每个客户端都应该有自己的证书和密钥文件
#
# 在Windows上此配置文件的后缀应该是".ovpn"在Linux/BSD系统中则是".conf"
##############################################
# 指定这是一个客户端,我们将从服务器获取某些配置文件指令
client
# 在大多数系统中除非你部分禁用或者完全禁用了TUN/TAP接口的防火墙否则VPN将不起作用。
;dev tap
dev tun
# 在Windows系统中如果你想配置多个隧道则需要该指令。
# 你需要用到网络连接面板中TAP-Win32适配器的名称(例如"MyTap")。
# 在XP SP2或更高版本的系统中你可能需要禁用掉针对TAP适配器的防火墙。
;dev-node MyTap
# 指定连接的服务器是采用TCP还是UDP协议。
# 这里需要使用与服务器端相同的设置。
;proto tcp
proto udp
# 指定服务器的主机名(或IP)以及端口号。
# 如果有多个VPN服务器为了实现负载均衡你可以设置多个remote指令。
remote my-server-1 1194
;remote my-server-2 1194
# 如果指定了多个remote指令启用该指令将随机连接其中的一台服务器
# 否则,客户端将按照指定的先后顺序依次尝试连接服务器。
;remote-random
# 启用该指令,与服务器连接中断后将自动重新连接,这在网络不稳定的情况下(例如:笔记本电脑无线网络)非常有用。
resolv-retry infinite
# 大多数客户端不需要绑定本机特定的端口号
nobind
# 在初始化完毕后降低OpenVPN的权限(该指令仅限于非Windows系统中使用)
;user nobody
;group nobody
# 持久化选项可以尽量避免访问在重启时由于用户权限降低而无法访问的某些资源。
persist-key
persist-tun
# 如果你是通过HTTP代理方式来连接到实际的VPN服务器请在此处指定代理服务器的主机名(或IP)和端口号。
# 如果你的代理服务器需要身份认证,请参考官方手册页面。
;http-proxy-retry # 连接失败时自动重试
;http-proxy [proxy server] [proxy port #]
# 无线网络通常会产生大量的重复数据包。设置此标识将忽略掉重复数据包的警告信息。
;mute-replay-warnings
# SSL/TLS 参数配置。
# 更多描述信息请参考服务器端配置文件。
# 最好为每个客户端单独分配.crt/.key文件对。
# 单个CA证书可以供所有客户端使用。
ca ca.crt
cert client.crt
key client.key
# 指定通过检查证书的nsCertType字段是否为"server"来验证服务器端证书。
# 这是预防潜在攻击的一种重要措施。
#
# 为了使用该功能你需要在生成服务器端证书时将其中的nsCertType字段设为"server"
# easy-rsa文件夹中的build-key-server脚本文件可以达到该目的。
ns-cert-type server
# 如果服务器端使用了tls-auth密钥那么每个客户端也都应该有该密钥。
;tls-auth ta.key 1
# 指定密码的加密算法。
# 如果服务器端启用了cipher指令选项那么你必须也在这里指定它。
;cipher x
# 在VPN连接中启用压缩。
# 该指令的启用/禁用应该与服务器端保持一致。
comp-lzo
# 设置日志文件冗余级别(0~9)。
# 0 表示静默运行,只记录致命错误。
# 4 表示合理的常规用法。
# 5 和 6 可以帮助调试连接错误。
# 9 表示极度冗余,输出非常详细的日志信息。
verb 3
# 忽略过多的重复信息。
# 相同类别的信息只有前20条会输出到日志文件中。
;mute 20
```
# 撤销客户端证书
- 生成/更新 crl.pem
```bash
./easyrsa revoke my-client0 # my-client0 是被注销证书的 common name
./easyrsa gen-crl
cp pki/crl.pem /etc/openvpn-server/server/my-server0/
```
- 修改 openvpn-server 的配置文件,追加/修改下面一行
```
# 注意: 该 crl.pem 文件本身及其上级目录,均需对 openvpn 运行用户可读
crl-verify my-server0/crl.pem
```
- 重启 openvpn-server 服务
# 参考链接
- [https://www.iyunv.com/forum.php?mod=viewthread&tid=250551](https://www.iyunv.com/forum.php?mod=viewthread&tid=250551)
- [https://blog.csdn.net/a8039974/article/details/89279147](https://blog.csdn.net/a8039974/article/details/89279147)
- [https://blog.csdn.net/a8039974/article/details/89279086](https://blog.csdn.net/a8039974/article/details/89279086)
- [https://blog.csdn.net/a8039974/article/details/89279036](https://blog.csdn.net/a8039974/article/details/89279036)
- [https://my.oschina.net/liucao/blog/863112](https://my.oschina.net/liucao/blog/863112)

View File

@ -0,0 +1,86 @@
---
title: "安装 Oracle 需要调整的内核参数"
date: 2019-10-30T17:58:46+08:00
lastmod: 2019-10-30T17:58:46+08:00
tags: ["oracle"]
categories: ["database"]
---
在**安装**Oracle的时候需要调整**linux**的**内核参数**,但是各参数代表什么含义呢,下面做详细解析。
Linux安装文档中给出的最小值
```
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.shmall = 2097152
kernel.shmmax = 4294967295
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048586
```
各参数详解:
**kernel.shmmax**
是核心参数中最重要的参数之一用于定义单个共享内存段的最大值。设置应该足够大能在一个共享内存段下容纳下整个的SGA ,设置的过低可能会导致需要创建多个共享内存段,这样可能导致系统性能的下降。至于导致系统下降的主要原因为在实例启动以及**Server**Process创建的时候多个小的共享内存段可能会导致当时轻微的系统性能的降低(在启动的时候需要去创建多个虚拟地址段,在进程创建的时候要让进程对多个段进行“识别”,会有一些影响),但是其他时候都不会有影响。
官方建议值:
32位linux系统可取最大值为4GB4294967296bytes-1byte即4294967295。建议值为多于内存的一半所以如果是32为系统一般可取值为4294967295。32位系统对SGA大小有限制所以SGA肯定可以包含在单个共享内存段中。
64位linux系统可取的最大值为物理内存值-1byte建议值为多于物理内存的一半一般取值大于SGA\_MAX\_SIZE即可可以取物理内存-1byte。例如如果为12GB物理内存可取12\*1024\*1024\*1024-1=12884901887SGA肯定会包含在单个共享内存段中。
**kernel.shmall**
该参数控制可以使用的共享内存的总页数。Linux共享内存页大小为4KB,共享内存段的大小都是共享内存页大小的整数倍。一个共享内存段的最大大小是16G那么需要共享内存页数是16GB/4KB=16777216KB /4KB=4194304也就是64Bit系统下16GB物理内存设置kernel.shmall = 4194304才符合要求(几乎是原来设置2097152的两倍)。这时可以将shmmax参数调整到16G了同时可以修改SGA\_MAX\_SIZE和SGA_TARGET为12G您想设置的SGA最大大小当然也可以是2G~14G等还要协调PGA参数及OS等其他内存使用不能设置太满比如16G
**kernel.shmmni**
该参数是共享内存段的最大数量。shmmni缺省值4096一般肯定是够用了。
**fs.file-max**
该参数决定了系统中所允许的文件句柄最大数目文件句柄设置代表linux系统中可以打开的文件的数量。
**fs.aio-max-nr**
此参数限制并发未完成的请求应该设置避免I/O子系统故障。
**kernel.sem**
以kernel.sem = 250 32000 100 128为例
250是参数semmsl的值表示一个信号量集合中能够包含的信号量最大数目。
32000是参数semmns的值表示系统内可允许的信号量最大数目。
100是参数semopm的值表示单个semopm()调用在一个信号量集合上可以执行的操作数量。
128是参数semmni的值表示系统信号量集合总数。
**net.ipv4.ip_local_port_range: **
表示应用程序可使用的IPv4端口范围。
**net.core.rmem_default: **
表示套接字接收缓冲区大小的缺省值。
**net.core.rmem_max: **
表示套接字接收缓冲区大小的最大值。
**net.core.wmem_default: **
表示套接字发送缓冲区大小的缺省值。
**net.core.wmem_max: **
表示套接字发送缓冲区大小的最大值

496
content/post/oracle.md Normal file
View File

@ -0,0 +1,496 @@
---
title: "Oracle 基础"
date: 2019-10-30T11:55:46+08:00
lastmod: 2019-10-30T11:55:46+08:00
tags: ["oracle"]
categories: ["database"]
---
# 字符型
类型 | 大小 | 描述
---- | ---- | ----
varchar2 | 0~4000 | 可变长度字符串
nvarchar2 | 0~1000 | Unicode字符串的可变长字符型数据
char | 0~2000 | 定长字符型数据
nchar | 0~1000 | Unicode字符集定长字符型数据
long | 0~2GB | 变长字符串
# 数字型
类型 | 进制 | 描述
---- | ---- | ----
number(p,s) | 十进制 | p最大精度38位s小数位数
float | 二进制 | 126位整数
# 日期
类型 | 大小 | 描述
---- | ---- | ----
date | 公元前4712-1-1~9999-12-31 | 存储日期和时间
timestamp | 公元前4712-1-1~9999-12-31 | 精确到小数秒,显示上下午
# 其他数据类型
类型 | 大小 | 描述
---- | ---- | ----
blob | 4GB | 二进制
clob | 4GB | 字符串
bfile | 视操作系统 | 存储非结构化数据到数据库外的文件中
# 创建表
```sql
CREATE TABLE table_name
(
column_name datatype [NULL|NOT NULL],
...,
PRIMARY KEY(),
CONSTRAINT table_name constraint_name FOREIGN KEY (column_name) REFERENCE table_name(column_name) ON DELETE CASCADE,
CONSTRAINT constraint_name CHECK(condition),
CONSTRAINT constraint_name UNIQUE(column_name)
)
|AS SELECT column_name1,column_name2,...FROM source_table;
DROP TABLE table_name;
```
# 删除表
```bash
DROP TABLE table_name;
# 执行最快删除数据、结构、索引、约束、触发器和索引存储过程和索引invalid状态直接生效不可回滚不释放空间
TRUNCATE TABLE table_name;
# 执行较快,只删除数据,直接生效,不可回滚,释放空间
DELETE FROM table_name [WHERE condition];
# 执行最慢只删除数据commit 后生效,可回滚,不释放空间
```
# 操作表列
```sql
ALTER TABLE table_name
ADD column_name datatype [NULL|NOT NULL]
|MODIFY column_name new_datatype|NULL|NOT NULL
|DROP COLUMN column_name;
-- 删除列时通常追加 CASCADE CONSTRAINTS ,以删除于该列有关的约束
```
# 操作主键
```sql
ALTER TABLE table_name
ADD CONSTRAINTS constraint_name PRIMARY KEY(column_name)
|DROP CONSTRAINTS constraint_name;
```
# 操作外键
```sql
ALTER TABLE table_name
ADD CONSTRAINT constraint_name FOREIGN KEY(column_name) REFERENCE table_name(column_name) ON DELETE CASCADE
|DROP CONSTRAINT constraint_name;
```
# 操作CHECK约束
```sql
ALTER TABLE table_name
ADD CONSTRAINT constraint_name CHECK(condition)
|DROP CONSTRAINT constraint_name;
```
# 操作UNIQUE约束
```sql
ALTER TABLE table_name
ADD CONSTRAINT constraint_name UNIQUE(column_name)
|DROP CONSTRAINT constraint_name;
```
# 添加数据
```sql
INSERT INTO table_name(column_name1,column_name2,...)
VALUES(data1,data2,...)
|SELECT column_name1,column_name2...FROM table_name2;
```
# 修改数据
```sql
UPDATE table_name SET column_name1=data1,column_name2=data2,...[WHERE condition];
```
# 删除数据
```sql
DELETE FROM table_name [WHERE condition];
TRUNCATE TABLE table_name;
```
# 查询数据
```sql
SELECT column_name1,column_name2,...FROM table_name [WHERE condition];
```
# MERGE语句
```sql
MERGE INTO table_name1 USING table_name2 ON(condition) WHEN MATCHED THEN ... WHEN NOT MATCHED THEN ...;
```
# SELECT 语句
```sql
SELECT [DISTINCT|ALL] select_list FROM table_list [WHERE ...] [GROUP BY ...] [HAVING ...] [ORDER BY ...];
```
# select_list
```sql
*|[schema.] {table|view} .*|expr[ [AS ]c_alias]
```
# expr
```sql
"||" 连接的字符串 | 函数
```
# ORDER BY ...
```sql
{expr|positon|c_alias} {ASC|DESC} {NULLS FIRST|NULLS LAST}[ {expr|positon|c_alias} {ASC|DESC} {NULLS FIRST|NULLS LAST},...]
```
# 模糊查询关键字like
```sql
'_'替代一个字符,'%'替代多个字符
```
# 从给定值中选取查询
```sql
IN(data1,data2,...)
```
# 连接
```sql
-- 连接,只能查询匹配记录
SELECT select_list FROM table_name1 INNER JOIN table_name2 ON condition;
-- 左外连接
SELECT select_list FROM table_name1 LEFT JOIN table_name2 ON condition;
-- 右外连接
SELECT select_list FROM table_name1 RIGHT JOIN table_name2 ON condition;
-- 全外连接
SELECT select_list FROM table_name1 FULL JOIN table_name2 ON condition;
```
# 内置函数
```sql
ABS(n) -- n绝对值
MOD(n2,n1) -- n2对n1取余
SIGN(n) -- n的符号
CEIL(n) -- 大于等于n的最小整数
FLOOR(n) -- 小于等于n的最大整数
SQRT(n) -- n的平方根
POWER(n2,n1) -- n2的n1次幂
EXP(n) -- e的n次幂
LOG(n1,n2) -- n1为底n2的对数
LN(n) -- n的自然对数
ROUND(n2,n1) -- n2小数部分四舍五入至n1位
TRUNC(n2,n1) -- n2截取至n1位
CHR(n) -- 把n根据ASCII转换成字符
ASCII(char) -- 参数首字母的ASCII值
LENGTH(char) -- 字符串长度
SUBSTR(char,position[,substring_length]) -- 截取字符串
CONCAT(char1,char2) -- 连接字符串
INSTR(string,substring[,position[,occurrence]]) -- 查找字符串
UPPER(char) -- 转换成大写
LOWER(char) -- 转换成小些
INITCAP(char) -- 单词首字母大写
NLSSORT(char[,nslparam]) -- 按指定方式排序'NLS_SORT=SCHINESE_PINYIN_M'
REPLACE(char,search_string[,replacement_string]) -- 字符串替换,默认删除
RPAD(expr1,n[,expr2]) -- 用expr2右填充expr1至长度为n默认空格
LPAD(expr1,n[,expr2]) -- 用expr2左填充expr1至长度为n默认空格
TRIM([LEADING|TRAILING|BOTH] [trim_character FROM] trim_source) -- 删除字符串首尾指定字符
SYSDATE -- 获取系统当前日期
SYSTIMESTAMP -- 获取系统当前时间
DBTIMEZONE -- 获取数据库当前时区
ADD_MONTHS(date,integer) -- 指定日期增加指定月份数
SESSIONTIMEZONE -- 获取当前会话的时区
LAST_DAY(date) -- 获取指定日期对应月份的最后一天
NEXT_DAY(date,char) -- 获取下周char的日期
CURRENT_DATE -- 获取会话时区的当前日期
EXTRACT(datetime) -- 从指定时间中获取指定部分
MONTHS_BETWEEN(date1,date2) -- 获取两个时间之间的月份数
NET_TIME(date,timezone1,timezone2) -- 获取时区1中的时间转换到时区2后的时间
TO_CHAR(n[,fmt]) -- 转换为字符类型
TO_DATE(n[,fmt]) -- 转换为时间类型
TO_NUMBER(n[,fmt]) -- 转换为数字类型
LNNVL(condition) -- 排除指定条件函数
NVL(expr1,expr2) -- expr1为空时返回expr2
NVL2(expr1,expr2,expr3) -- expr1为空时返回expr3不为空返回expr2
AVG([DISTINCT|ALL ]expr) -- 获取平均值
COUNT(*|[DISTINCT|ALL ]expr) -- 获取数量
SUM([DISTINCT|ALL ]expr) -- 获取和
SELECT USER FROM DUAL; -- 返回当前会话的登录名
USERENV(param) -- 返回当前会话的信息
SYS_CONTEXT(namespace,param) -- 返回oracle已创建的context
DECODE(expr,search,result[,search1,result1...]) -- expr结果是search返回result
```
# 查看所有默认表空间
```sql
SELECT TABLESPACE_NAME FROM DBA_TABLESPACES;
```
# 查看指定用户默认表空间
```sql
SELECT DEFAULT_STAPCE,USERNAME FROM DBA_USERS WHERE USERNAME='username';
```
# 创建表空间
```sql
CREATE TABLESPACE tablespace_name
DATAFILE filename
SIZE size
[AUTOEXTEND [ON NEXT size|OFF]]
[MAXSIZE size]
[PERMANENT|TEMPORARY] 永久/临时表空间,默认永久
[EXTENT MANAGEMENT [DICTIONARY|LOCAL 字典/本地管理方式,默认本地
[AUTOALLOCATE|UNIFORM. [SIZE integer[K|M]]]];
```
# 重命名表空间
```sql
ALTER TABLESPACE oldname RENAME TO newname;
```
# 修改表空间大小
```sql
ALTER DATABASE DATAFILE filename RESIZE size;
```
# 增加表空间大小
```sql
ALTER TABLESPACE tablespace_name ADD DATAFILE filename SIZE size;
```
# 设置表空间读写状态
```sql
ALTER TABLESPACE tablespace_name READ {ONLY|WRITE};
```
# 设置表空间可用状态
```sql
ALTER TABLESPACE tablespace_name {ONLINE|OFFLINE [NORMAL|TEMPORARY|IMMEDIATE]};
```
# 创建大文件表空间
```sql
CREATE BIGFILE TABLESPACE tablespace_name DATAFILE filename SIZE size;
```
# 删除表空间
```sql
DROP TABLESPACE tablespace_name
[INCLUDING CONTENTS AND DATAFILES] 数据文件删除
[CASCADE CONSTRAINTS]; 完整性删除
```
# 查看表空间大小
```sql
SELECT TABLESPACE_NAME,FILE_NAME,BYTES FROM DBA_DATA_FILES WHERE TABLESPACE_NAME=tablespace_name;
```
# 查看表空间剩余 空间
```sql
SELECT TABLESPACE_NAME,BYTES FROM DBA_FREE_SPACES;
```
# 创建/修改用户
```sql
CREATE|ALTER
USER user_name
IDENTIFIED BY password
[DEFAULT TABLESPACE tablespace_name ]
[QUOTA size|UNLIMITED ON tablespace_name ] 用户使用表空间的最大值
[PROFILE profile ] 概要文件
[PASSWORD EXPIRE ] 用户密码过期
[ACCOUNT LOCK|UNLOCK]; 默认锁定状态
```
# 删除用户
```sql
DROP USER user_name CASCADE;
```
# 授予系统权限
```sql
GRANT
system_privileges|ALL PRIVILEGES 权限
TO {user IDENTIFIED BY password|role } 用户/角色
[WITH ADMIN OPTION]; 授予其他用户或角色系统权限
```
# 授予对象权限
```sql
GRANT
object_privilege|ALL 权限
ON schema.object 对象
TO user_name|role_name 用户/角色
[WITH ADMIN OPTION ] 授予其他用户或角色系统权限
[WITH THE GRANT ANY OBJECT]; 授予其他用户或角色对象权限
```
# 撤销系统权限
```sql
REVOKE system_privilege FROM
user|role;
```
# 撤销对象权限
```sql
REVOKE
object_privilege |ALL
ON schema.object FROM
user_name|role_name
[CASCADE CONSTRAINTS];
```
# 数据字典
数据 | 字典
---- | ----
系统权限 | DBA_SYS_PRIVS
对象权限 | DBA_TAB_PRIVS
用户角色 | DBA_ROLE_PRIVS
# 创建角色
```sql
CREATE|ALTER //创建/修改
ROLE role_name
[NOT IDENTIFIED|IDENDIFIED BY [password]];
GRANT //填充权限
system_privilege|ALL PRIVILEGES
TO role_name
[WITH ADMIN OPTION];
-- 角色创建完成后不能直接使用,需将角色赋予用户才能使用
GRANT role_name TO user_name;
SET ROLE role_name -- 设置角色生效
SET ROLE ALL -- 设置所有角色生效
SET ROLE ALL EXCEPT role_name -- 设置只有role_name失效
SET ROLE NONE -- 设置所有角色失效
```
# 删除角色
```sql
DROP ROLE role_name;
```
# 脱机备份(冷备份)/恢复
```sql
关闭数据库服务后直接复制需要的文件,包括数据文件和控制文件
```
# 联机备份(热备份)
```sql
ARCHIVE LOG LIST 查看本机数据库的日志状态
ALTER SYSTEM SET LOG_ARCHIVE_START=TRUE SCOPE=SPFILE; 设置日志模式为归档
SHUTDOWN IMMEDIATE; 关闭数据库
STARTUP MOUNT; 启动mount实例
ALTER DATABASE ARCHIVELOG; 更改数据库为归档日志模式
ALTER DATABASE OPEN; 更改数据库状态为打开模式
ALTER TABLESPACE tablespace_name BEGIN BACKUP; 开始备份数据库
复制文件到其他目录
ALTER TABLESPACE tablespace_name END BACKUP; 结束备份操作
```
# 恢复
```sql
ALTER SYSTEM ARCHIVE LOG CURRENT; 归档当前日志
ALTER SYSTEM SWITCH LOGFILE; 切换日志文件
SELECT * FROM v$RECOVER_FILE 获取文件编号
ALTER DATABASE DATAFILE file_id OFFLINE DROP; 把要恢复的数据文件脱机
ALTER DATABASE OPEN; 更改数据库状态为打开模式
RECOVER DATAFILE file_id; 恢复数据文件
ALTER DATABASE DATAFILE file_id ONLINE; 设置数据文件联机
```
# EXP工具导出数据
```bash
exp db_user/password 登陆数据库的用户名和密码非SYS
```
# EXP工具直接导出表
```bash
exp db_user/password file="filename.dmp" tables="table_name,..."
```
# EXP工具导出表空间
```bash
exp db_user/password file="filename.dmp" tablespaces="tablespaces_name"
```
# EXPDP导出数据
```sql
CREATE DIRECTORY directory_name AS 'file_name'; 目录名称 文件名称
GRANT READ,WRITE ON DIRECTORY directory_name TO db_user; 授权用户使用该目录
#expdp db_user/password directory=directory_name dumpfile=file_name tables=table_name;
```
# IMP导入数据
```sql
imp db_user/password
```
# IMP直接导入表
```sql
imp db_user/password file="filename.dmp" tables="table_name,..."
```
# IMPDP导入数据
```sql
impdp db_user_password
```
# IMPDP直接导入表
```bash
impdp db_user/password directory=dir dumpfile=filename.dmp tables=table_name;
```
# RMAN工具配置
```sql
CONN /AS SYSDBA; 连接恢复目录数据库
CREATE USER rman_user IDENTIFIED BY password DEFAULT TABLESPACE tablespace_name; 创建恢复用户
GRANT RECOVERY_CATALOG_OWNER TO rman_user; 为新创建的用户授权
#rman
CONN CATALOG rman_user/password; 连接新创建的用户
CREATE CATALOG; 创建恢复目录
```
# RMAN工具使用
```sql
#rman target db_user/password@servicename catalog rman_user/password 连接恢复目录数据库
CONNECT TARGET db_user/password@servicename; 连接目标数据库
CONNECT CATALOG rman_user/password@servicename; 连接恢复目录数据库
REGISTER database; 在恢复目录数据库中注册数据库
```
# 手动分配通道
```sql
关闭目标数据库启动到mount状态运行
run
{
ALLOCATE CHANNEL channel_name1 DEVICE TYPE {sbt|disk};
...
BACKUP [level] [backup type] [option]
}
```
# 自动分配通道
```sql
CONFIGURE DEVICE TYPE {sbt|disk} PARALLELISM n; 指定通道类型和名称
CONFIGURE DEFAULT DEVICE TYPE {sbt|disk}; 指定默认设备类型
BACKUP [level] [backup type] [option];
```
# BACKUP 参数
```sql
level 备份增量1、2、3、4或者FULL全备份
backup type 对象类型database、datafile、tablespace、controlfilecopy、archivelog all
option channel备份使用的通道 maxsetsize定义备份集的最大值
```
# RESTORE还原
```sql
RESTORE database_object;
database_object: DATABASE(mount),TABLESPACE(open),DATAFILE,CONTROLFILE(mount),ARCHIVELOG,SPFILE(mount)
```
# RECOVER同步恢复
```sql
RECOVER database_object;
database_object: DATABASE(mount),TABLESPACE(open),DATAFILE
```

View File

@ -0,0 +1,199 @@
---
title: "CentOS7.4 静默安装 Oracle11g"
date: 2019-10-30T11:54:49+08:00
lastmod: 2019-10-30T11:54:49+08:00
tags: ["oracle"]
categories: ["database"]
---
# 环境
- CentOS7.4 最小安装
- 数据库软件
- linux.x64_11gR2_database_1of2.zip
- linux.x64_11gR2_database_2of2.zip
# 操作系统配置
- 关闭 SELinux
```bash
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
```
- 关闭防火墙,或者放行 tcp 1521 端口
```bash
systemctl disable firewalld
systemctl stop firewalld
```
- 重启操作系统
```bash
reboot
```
# 安装依赖
- 安装可能用到的工具
```bash
yum install epel-release
yum clean all
yum makecache fast
yum install vim unzip rlwrap
```
- 安装 oracle 需要的包
```bash
yum install binutils compat-libcap1 compat-libstdc++-33 \
compat-libstdc++-33*i686 gcc gcc-c++ glibc glibc*.i686 \
glibc-devel glibc-devel*.i686 ksh libaio libaio*.i686 libaio-devel \
libgcc libgcc*.i686 libstdc++ libstdc++*.i686 libstdc++-devel \
libXi libXi*.i686 libXtst libXtst*.i686 make sysstat unixODBC \
unixODBC*.i686 unixODBC-devel unixODBC-devel*.i686
```
# 配置安装环境
- 创建 oracle 用户
```bash
groupadd oinstall
groupadd dba
useradd -g oinstall -G dba oracle
```
- 创建 oracle 安装目录
```bash
mkdir -p /opt/oracle/app/product/11.2.0
mkdir -p /opt/oracle/app/oradata
mkdir -p /opt/oracle/app/fast_recovery_area
mkdir -p /opt/oracle/inventory
chown -R oracle:oinstall /opt/oracle
chmod -R 775 /opt/oracle
```
- 修改 sysctl.conf
```bash
cat << EOF >> /etc/sysctl.conf
fs.aio-max-nr = 1048576
fs.file-max = 6815744
#物理内存一半和4G中的较大者
kernel.shmmax = 4294967296
#shmmax / 4k (getconf PAGESIZE)
kernel.shmall = 1048576
kernel.shmmni = 4096
kernel.sem = 250 32000 200 200
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.wmem_max = 1048586
net.core.rmem_max = 4194304
EOF
sysctl -p
```
- 修改 limits.conf
```bash
cat << EOF >> /etc/security/limits.conf
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
EOF
```
- 修改 login
```bash
cat << EOF >> /etc/pam.d/login
session required /lib64/security/pam_limits.so
session required pam_limits.so
EOF
```
- 修改 profile
```bash
cat << EOF >> /etc/profile
if [ \$USER = "oracle" ] ; then
if [ \$SHELL = "/bin/ksh" ]; then
ulimit -p 16384
ulimit -n 65536
else
ulimit -u 16384 -n 65536
fi
umask 022
fi
EOF
```
- 修改 oracle 用户的 .bash_profile
```bash
cat << EOF >> /home/oracle/.bash_profile
export ORACLE_BASE=/opt/oracle/app
export ORACLE_HOME=\$ORACLE_BASE/product/11.2.0
export ORACLE_SID=orcl
export PATH=\$PATH:\$ORACLE_HOME/bin
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8"
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
EOF
```
# 安装数据库
- 上传数据库软件到 /root 下,解压
```bash
unzip linux.x64_11gR2_database_1of2.zip -d /home/oracle/
unzip linux.x64_11gR2_database_2of2.zip -d /home/oracle/
chown -R oracle.oinstall /home/oracle/database
```
- 切换到 oracle 用户,后续操作都在该 oracle 用户下执行
```bash
su - oracle
```
- 创建 response 文件
```bash
cd /home/oracle
cp database/response/*.rsp ./
```
- 修改 db_install.rsp
```bash
sed -i \
-e '/^oracle.install.option=/s#=.*$#=INSTALL_DB_SWONLY#' \
-e '/^UNIX_GROUP_NAME=/s#=.*$#=oinstall#' \
-e '/^INVENTORY_LOCATION=/s#=.*$#=/opt/oracle/inventory#' \
-e '/^SELECTED_LANGUAGES=/s#=.*$#=en,zh_CN#' \
-e '/^ORACLE_HOME=/s#=.*$#=/opt/oracle/app/product/11.2.0#' \
-e '/^ORACLE_BASE=/s#=.*$#=/opt/oracle/app#' \
-e '/^oracle.install.db.InstallEdition=/s#=.*$#=EE#' \
-e '/^oracle.install.db.DBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle.install.db.OPER_GROUP=/s#=.*$#=dba#' \
-e '/^oracle.install.db.config.starterdb.type=/s#=.*$#=GENERAL_PURPOSE#' \
-e '/^DECLINE_SECURITY_UPDATES=/s#=.*$#=true#' \
/home/oracle/db_install.rsp
```
- 无需修改 netca.rsp
- 修改 dbca.rsp
```bash
sed -i \
-e '/^GDBNAME=/s#=.*$#=orcl#' \
-e '/^SID=/s#=.*$#=orcl#' \
-e '/^SYSPASSWORD=/s#=.*$#=111111#' \
-e '/^SYSTEMPASSWORD=/s#=.*$#=111111#' \
-e '/^CHARACTERSET=/s#=.*$#=ZHS16GBK#' \
/home/oracle/dbca.rsp
```
- 安装 oracle 软件
```bash
cd /home/oracle/database
./runInstaller -silent -responseFile /home/oracle/db_install.rsp -ignorePrereq
#安装成功后,系统提示需要在 root 下执行两个脚本
/opt/oracle/invertory/orainstRoot.sh
/opt/oracle/app/product/11.2.0/root.sh
```
- 配置监听
```bash
netca /silent /responseFile /home/oracle/netca.rsp
#配置成功后,监听启动,查看监听状态
lsnrctl status
```
- 创建数据库
```bash
dbca -silent -responseFile /home/oracle/dbca.rsp
#查看屏幕输出的创建进度
```
# 简单使用
- 登陆数据库
```
[oracle@localhost ~]$ rlwrap sqlplus / as sysdba
SQL*Plus: Release 11.2.0.1.0 Production on 星期一 6月 25 14:46:58 2018
Copyright (c) 1982, 2009, Oracle. All rights reserved.
连接到:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>
```

View File

@ -0,0 +1,228 @@
---
title: "CentOS7 静默安装 Oracle12c"
date: 2019-10-30T11:11:13+08:00
lastmod: 2019-10-30T11:11:13+08:00
keywords: []
tags: ["oracle"]
categories: ["database"]
---
# 环境
- CentOS7.5 最小安装
- 数据库软件
- linuxx64_12201_database.zip
# 操作系统配置
- 关闭 SELinux
```bash
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
```
- 关闭防火墙
```bash
systemctl disable firewalld
systemctl stop firewalld
```
- 禁用 NetworkManager
```bash
systemctl disable NetworkManager
systemctl stop NetworkManager
```
- 重启操作系统
```bash
reboot
```
# 安装依赖
- 安装可能用到的工具
```bash
yum install epel-release
yum clean all
yum makecache fast
yum install vim unzip rlwrap
```
- 安装 oracle 需要的包
```bash
yum install binutils compat-libcap1 compat-libstdc++-33 \
compat-libstdc++-33*i686 gcc gcc-c++ glibc glibc*.i686 \
glibc-devel glibc-devel*.i686 ksh libaio libaio*.i686 libaio-devel \
libgcc libgcc*.i686 libstdc++ libstdc++*.i686 libstdc++-devel \
libXi libXi*.i686 libXtst libXtst*.i686 make sysstat unixODBC \
unixODBC*.i686 unixODBC-devel unixODBC-devel*.i686
```
# 配置安装环境
- 创建 oracle 用户
```bash
groupadd oinstall
groupadd dba
groupadd oper
useradd -g oinstall -G dba,oper oracle
```
- 创建 oracle 安装目录
```bash
mkdir -p /opt/oracle/app/product/12.2.0
mkdir -p /opt/oracle/app/oradata
mkdir -p /opt/oracle/app/fast_recovery_area
chown -R oracle:oinstall /opt/oracle
chmod -R 775 /opt/oracle
```
- 修改 sysctl.conf
```bash
cat << EOF >> /etc/sysctl.conf
fs.aio-max-nr = 1048576
fs.file-max = 6815744
#物理内存一半和4G中的较大者当前服务器16G
kernel.shmmax = 8589934592
#shmmax / 4k (getconf PAGESIZE)
kernel.shmall = 2097152
kernel.shmmni = 4096
kernel.sem = 250 32000 200 200
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.wmem_max = 1048586
net.core.rmem_max = 4194304
EOF
sysctl -p
```
- 修改 limits.conf
```bash
cat << EOF >> /etc/security/limits.conf
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
oracle soft stack 10240
EOF
```
- 修改 login
```bash
cat << EOF >> /etc/pam.d/login
session required /lib64/security/pam_limits.so
session required pam_limits.so
EOF
```
- 修改 profile
```bash
cat << EOF >> /etc/profile
if [ \$USER = "oracle" ] ; then
if [ \$SHELL = "/bin/ksh" ]; then
ulimit -p 16384
ulimit -n 65536
else
ulimit -u 16384 -n 65536
fi
umask 022
fi
EOF
```
- 修改 oracle 用户的 .bash_profile
```bash
cat << EOF >> /home/oracle/.bash_profile
export ORACLE_BASE=/opt/oracle/app
export ORACLE_HOME=\$ORACLE_BASE/product/12.2.0
export ORACLE_SID=orcl
export PATH=\$PATH:\$ORACLE_HOME/bin
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8"
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
EOF
```
# 安装数据库
- 上传数据库软件到 /root 下,解压
```bash
unzip linuxx64_12201_database.zip -d /home/oracle/
chown -R oracle.oinstall /home/oracle/database
```
- 切换到 oracle 用户,后续操作都在该 oracle 用户下执行
```bash
su - oracle
```
- 创建 response 文件
```bash
cd /home/oracle
cp database/response/*.rsp ./
```
- 修改 db_install.rsp
```bash
sed -i \
-e '/^oracle\.install\.option=/s#=.*$#=INSTALL_DB_SWONLY#' \
-e '/^UNIX_GROUP_NAME=/s#=.*$#=oinstall#' \
-e '/^INVENTORY_LOCATION=/s#=.*$#=/opt/oracle/oraInventory#' \
-e '/^ORACLE_HOME=/s#=.*$#=/opt/oracle/app/product/12.2.0#' \
-e '/^ORACLE_BASE=/s#=.*$#=/opt/oracle/app#' \
-e '/^oracle\.install\.db\.InstallEdition=/s#=.*$#=EE#' \
-e '/^oracle\.install\.db\.OSDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSOPER_GROUP=/s#=.*$#=oper#' \
-e '/^oracle\.install\.db\.OSBACKUPDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSDGDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSKMDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSRACDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle.install.db.config.starterdb.type=/s#=.*$#=GENERAL_PURPOSE#' \
-e '/^oracle\.install\.db\.config\.starterdb\.characterSet=/s#=.*$#=ZHS16GBK#' \
-e '/^DECLINE_SECURITY_UPDATES=/s#=.*$#=true#' \
/home/oracle/db_install.rsp
```
- 无需修改 netca.rsp
- 修改 dbca.rsp
```bash
sed -i \
-e '/^gdbName=/s#=.*$#=orcl#' \
-e '/^sid=/s#=.*$#=orcl#' \
-e '/^createAsContainerDatabase=/s#=.*$#=true#' \
-e '/^numberOfPDBs=/s#=.*$#=1#' \
-e '/^pdbName=/s#=.*$#=pdborcl#' \
-e '/^templateName=/s#=.*$#=General_Purpose.dbc#' \
-e '/^pdbAdminPassword=/s#=.*$#=P@sswo2d#' \
-e '/^sysPassword=/s#=.*$#=P@sswo2d#' \
-e '/^systemPassword=/s#=.*$#=P@sswo2d#' \
/home/oracle/dbca.rsp
```
- 安装 oracle 软件
```bash
cd /home/oracle/database
./runInstaller -silent -responseFile /home/oracle/db_install.rsp -ignorePrereq
#安装成功后,系统提示需要在 root 下执行两个脚本
/opt/oracle/oraInventory/orainstRoot.sh
/opt/oracle/app/product/12.2.0/root.sh
```
- 配置监听
```bash
netca /silent /responseFile /home/oracle/netca.rsp
#配置成功后,监听启动,查看监听状态
lsnrctl status
```
- 创建数据库
```bash
dbca -silent -createDatabase -responseFile /home/oracle/dbca.rsp
#查看屏幕输出的创建进度
```
# 简单使用
- 登陆数据库,切换到 pdb 数据库
```
[oracle@fpManager2 ~]$ rlwrap sqlplus / as sysdba
SQL*Plus: Release 12.2.0.1.0 Production on 星期一 6月 25 14:41:16 2018
Copyright (c) 1982, 2016, Oracle. All rights reserved.
连接到:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
SQL> alter session set container=pdborcl;
会话已更改。
SQL> show con_name
CON_NAME
------------------------------
PDBORCL
SQL> select file_name from dba_data_files;
FILE_NAME
--------------------------------------------------------------------------------
/opt/oracle/app/oradata/orcl/pdborcl/system01.dbf
/opt/oracle/app/oradata/orcl/pdborcl/sysaux01.dbf
/opt/oracle/app/oradata/orcl/pdborcl/undotbs01.dbf
/opt/oracle/app/oradata/orcl/pdborcl/users01.dbf
SQL>
```

242
content/post/oracle_1.md Normal file
View File

@ -0,0 +1,242 @@
---
title: "Oracle 笔记"
date: 2019-10-30T11:53:08+08:00
lastmod: 2019-10-30T11:53:08+08:00
tags: ["oracle"]
categories: ["database"]
---
# 导出一个表的表结构 sql
```sql
set heading off;
set echo off;
set pages 999;
set long 90000;
spool table_name.sql
select dbms_metadata.get_ddl('TABLE','table_name','user_name') from dual;
spool off;
```
# 到处一个用户的全部表结构 sql
```sql
set pagesize 0
set long 90000
set feedback off
set echo off
spool user_tables.sql
SELECT DBMS_METADATA.GET_DDL('TABLE',t1.table_name) FROM USER_TABLES t1;
spool off;
```
# 设置 oracle 客户端的字符集
```sql
select * from v$nls_parameters;
-- 在输出中找到 NLS_LANGUAGE、NLS_TERRITORY、NLS_CHARACTERSET 这三个变量的值
-- 环境变量 NLS_LANG 就是由这三个变量组成NLS_LANG = language_territory.charset
```
# 终端连接(ssh) sqlplus 中文乱码
- 设置该终端与数据库服务器当前字符集编码一致即可
# 修改数据库字符集
```sql
shutdown immediate; (把database停了)
startup mount; (把database重开去可更改情況)
alter system enable restricted session;
alter system set job_queue_processes=0;
alter system set aq_tm_processes=0;
alter database open;
alter database character set internal_use utf8;
shutdown immediate;
startup; (重开正常oracle)
```
# Oracle 12c PDB 管理
- 查看当前模式
```sql
show con_name; -- 默认 CDB$ROOT
```
- 查看 CDB$ROOT 下所有 pdbs
```sql
select name, open_mode from v$pdbs;
-- 或者
show pdbs;
```
- 创建 PDB 数据库
```sql
create pluggable database pdborcl1
admin user pdborcl1_adm identified by pdborcl1_pass
roles=(dba,connect,resource)
file_name_convert=('/opt/oracle/app/oradata/orcl/pdbseed','/opt/oracle/app/oradata/orcl/pdborcl1')
path_prefix='/opt/oracle/app/oradata/orcl/pdborcl1';
```
- PDB 数据库创建完成后进入 mount 状态,需手动启动
```sql
alter pluggable database {pdborcl1[,pdborcl2]|all [except pdborcl2]} open [read only] [force];
```
- 进入打开的 PDB 数据库
```sql
alter session set container=pdborcl1;
```
- 切换回 CDB$ROOT
```sql
alter session set container=cdb$root;
```
- 关闭 PDB 数据库
```sql
alter pluggable database {pdborcl1[,pdborcl2]|all [except pdborcl2]} close [immediate];
```
- 删除关闭的 PDB 数据库
```sql
drop pluggable database pdborcl1 [including datafiles];
```
# sqlplus 到处 csv 文件
```sql
sqool /home/oracle/sql_result.csv
select '"' || field1 || '","' || field2 || '","' ... '","' || fieldn || '"' from table1;
spool off
```
# 系统变量
## 常用设置
- 域输出分隔符
```sql
set colsep ' ';
```
- 设置查询出来的数据分多少页显示如果需要连续的数据中间不要出现空行就把newp设置为none这样输出的数据行都是连续的中间没有空行之类的
```sql
set newp none;
```
- 显示start启动的脚本中的每个sql命令缺省为on
```sql
set echo off;
```
- 设置运行命令是是否显示语句
```sql
set echo on;
```
- 设置显示"已选择XX行"
```sql
set feedback on;
```
- 回显本次sql命令处理的记录条数缺省为on即去掉最后的 "已经选择10000行"
```sql
set feedback off;
```
- 输出域标题缺省为on 设置为off就去掉了select结果的字段名只显示数据
```sql
set heading off;
```
- 输出每页行数缺省为24,为了避免分页可设定为0。
```sql
set pagesize 0;
```
- 输出一行字符个数缺省为80
```sql
set linesize 80;
```
- 输出number类型域长度缺省为10
```sql
set numwidth 12;
```
- 显示脚本中的命令的执行结果缺省为on
```sql
set termout off;
```
- 去除标准输出每行的拖尾空格缺省为off
```sql
set trimout on;
```
- 去除重定向spool输出每行的拖尾空格缺省为off
```sql
set trimspool on;
```
- 设置允许显示输出类似dbms_output
```sql
set serveroutput on;
```
- 设置显示已用时间
```sql
set timing on;
```
- 设置允许对执行的sql进行分析
```sql
set autotrace on;
```
## 系统变量记录
- ARRAY[SIZE] {20(默认值)|n} sqlplus 一次从数据库获取的行数,有效值为1至5000. 大的值可提高查询和子查询的有效性,可获取许多行,但也需要更多的内存.当超过1000时,其效果不大.
- AUTO[COMMIT] {OFF(默认值)|ON|IMM[EDIATE]} 控制ORACLE对数据库的修改的提交. 置ON时,在ORACLE执行每个SQL命令或PL/SQL块后对数据库提交修改;置OFF时则制止自动提交,需要手工地提交修改,例如用SQL的COMMIT命令. IMMEDIATE功能同ON.
- BLO[CKTERMINATOR] {.(默认值)|C} 置非字母数字字符,用于结束PL/SQL块.要执行块时,必须发出RUN命令或/命令.
- CMDS[EP] {;|C|OFF(默认值)|ON} 置非字母数字字符,用于分隔在一行中输入的多个SQL/PLUS命令.ON或OFF控制在一行中是否能输入多个命令. ON时将自动地将命令分隔符设为分号(.其中C表示所置字符.
- COM[PATIBILITY] {V5|V6|V7|NATIVE(默认值)} 指定当前所链接的ORACLE版本.如果当前ORACLE的版本为5,则置COMPATIBILITY为V5; 为版本6时置成V6; 为版本7时置成V7. 如果希望由数据库决定该设置,在置成NATIVE.
- CON[CAT] {.(默认值)|C|OFF|ON(默认值)} 设置结束一替换变量引用的字符.在中止替换变量引用字符之后可跟所有字符,作为体会组成部分,否则sqlplus将解释为替换变量名的一部分.当CONCAT开关为ON时,sqlplus可重置CONCAT的值为点(.).
- COPYC[OMMIT] {0(默认值)|n} 控制COPY命令提交对数据库修改的批数.每次拷贝n批后,将提交到目标数据库.有效值为0到5000. 可用变量ARRAYSIZE设置一批的大小.如果置COPYCOMMIT为0,则仅在COPY操作结束时执行一次提交.
- CRT crt 改变 sqlplus RUNFORM 命令使用的缺省CRT文件.如果置CRT不包含什么,则crt仅包含''''.如果在一个Form的系统调用期间,要使用NEW.CRT(缺省CRT是OLD.CRT),可按下列形式调用Form:
```
SQL>;RUNFORM -C NEW form名
或者
SQL>;SET CRT NEW
SQL>;RUNFORM form名
# 第二中方法存储CRT选择,以致在下次运行RUNFORM命令(是在同一次sqlplus交互中)时,不需要指定.
```
- DEF[INE] {&|C|OFF|ON(默认值)} 设置在替换变量时所使用的字符.ON或OFF控制sqlplus是否扫描替换变量的命令及用他们的值代替. DEFINE的ON或OFF的设置控制SCAN变量的设置.
- ECHO {OFF|ON} 控制START命令是否列出命令文件中的每一命令.为ON时,列出命令;为OFF时,制止列清单.
- EMBEDDED {OFF(默认值)|ON} 控制每一报表在一页中开始的地方. 为OFF时,迫使每一报表是在新页的顶部开始;为ON时,运行一报表在一页的任何位置开始.
- ESC[APE] {\(默认值)|C|OFF(默认值)|ON} 定义作为Escape字符的字符.为OFF时,使Escape字符不起作用.为ON时,使Escape字符起作用.
- FEED[BACK] {6(默认值)|n|OFF|ON} 显示由查询返回的记录数.ON和OFF置显示为开或关.置FEEDBACK为ON时,等价于置n为1. 如果置FEEDBACK为0,等价于将它置成OFF.
- FLU[SH] {OFF|ON(默认值)} 控制输出送至用户的显示设备.为OFF时,运行操作系统做缓冲区输出;为ON时,不允许缓冲. 仅当非交互方式运行命令文件时使用OFF,这样可减少程序I/O总是,从而改进性能.
- HEA[DING] {OFF|ON(默认值)} 控制报表中列标题的打印.为ON时,在报表中打印列标题;为OFF时禁止打印列标题.
- HEADS[EP] {|(默认值)|C|OFF|ON(默认值)} 定义标题分隔字符.可在COLUMN命令中使用标题分隔符,将列标题分成多行.ON和OFF将标题分隔置成开或关.当标题分隔为关(OFF)时,sqlplus打印标题分隔符像任何字符一样.
- LIN[ESIZE] {80(默认值)|n} 置sqlplus在一行中显示的字符总数,它还控制在TTITLE和BTITLE中对准中心的文本和右对齐文本. 可定义LINESIZE为1至最大值,其最大值依赖于操作系统.
- LONG {80(默认值)|n} 为显示和拷贝LONG类型值的最大宽度的设置. 对于ORACLE7, n的最大值为2G字节;对于版本6,最大值为32767.
- LONGC[HUNKSIZE] {80(默认值)|n} 为sqlplus检索LONG类型值的增量大小.由于内存的限制,可按增量检索,该变量仅应用于ORACLE7.
- MAXD[ATA] n 置sqlplus可处理的最大行宽字符数,其缺省值和最大值在不同操作系统中是可变的.
- NEWP[AGE] {1(默认值)|n} 置每一页的头和顶部标题之间要打印的空行数.如果为0, 在页之间送一换号符,并在许多终端上清屏.
- NULL text 设置表示空值(null)的文本,如果NULL没有文本,则显示空格(缺省时). 使用COLUMN命令中的NULL子句可控制NULL变量对该列的设置.
- NUMF[ORMAT] 格式 设置显示数值的缺省格式,该格式是数值格式.
- NUM[WIDTH] {10(默认值)|n} 对显示数值设置缺省宽度.
- PAGES[IZE] {14(默认值)|n} 置从顶部标题至页结束之间的行数.在11英寸长的纸上打印报表,其值为54,上下各留一英寸(NEWPAGE值为6).
- PAU[SE] {OFF(默认值)|ON|text} 在显示报表时,控制终端滚动.在每一暂停时,必须按RETURN键.ON将引起sqlplus在每一报表输出页开始时暂停.所指定的文本是每一次sqlplus暂停时显示的文本.如果要键入多个词,必须用单引号将文本括起来.
- RECSEP {WR[APPED](默认值)|EA[CH]|OFF} 指定显示或打印记录分行符的条件.一个记录分行符,是由RECSEPCHAR指定的字符组成的单行.空格为RECSEPCHAR的默认字符.
- RECSEPCHAR { |C} 告诉sqlplus在哪儿做记录分隔.例如将RECSEP置成WRAPPED,在每一缠绕行之后,打印记录分行符.如果将RECSEP置成EACH,sqlplus在每一行后打印一记录分行符.如果将RECSEP置成OFF, sqlplus不打印分行符.
- SCAN {OFF|ON(默认值)} 控制对存在的替换变量和值的扫描.OFF禁止替换变量和值的处理; ON则允许正常处理.
- SERVEROUT[PUT] {OFF|ON} [SIZE n] 控制在sqlplus中的存储过程是否显示输出.OFF时为禁止; ON时则显示输出. SIZE设置缓冲输出的字节数,缺省值为2000, n不能小于2000或大于一百万.
- SHOW[MODE] {OFF(默认值)|ON} 控制sqlplus在执行SET命令时是否列出其新老值old或new的设置.
- SPA[CE] {1(默认值)|n} 设置输出列之间空格的数目,其最大值为10.
- SQLC[ASE] {MIX[ED](默认值)|LO[WER]|UP[PER]} 先于执行之前,将SQL命令和PL/SQL块的大小写进行转换. sqlplus将转换命令中的全部文本,包括带引号的直接量和标示符.SQLCASE不改变SQL缓冲区本身.
- SQLCO[NTINUE] {>;(默认值)|文本} 在一附加行上继续一sqlplus命令时,sqlplus以该设置的字符序列进行提示.
- SQLN[UMBER] {OFF|ON(默认值)} 为SQL命令和PL/SQL块的第二行和后继行设置提示.为ON时,提示行号;为OFF时,提示设置为SQLPROMPT的值.
- SQLPER[FIX] {#(默认值)|C} 设置sqlplus前缀字符.在键入一SQL命令或PL/SQL块时,可在单独行上键入一sqlplus命令,由sqlplus的前缀字符做前缀. sqlplus直接执行该命令,不影响SQL命令或PL/SQL块.前缀字符必须是非字母数字字符.
- SQLP[ROMPT] {SQL>;(默认值)|文本} 设置sqlplus的命令提示符.
```
11:37:45 SQL> show sqlprompt
sqlprompt "SQL> "
11:38:21 SQL> set sqlprompt Jamm>
11:39:54 Jamm>show sqlprompt
sqlprompt "Jamm>"
11:40:03 Jamm>
```
- SQLT[ERMINATOR] {;(默认值)|C|OFF|ON(默认值)} 设置用于结束和执行SQL命令的字符. OFF意味着sqlplus不识别命令终止符,用键入空行来结束SQL命令. ON重设置终止符为默认的分号.
- SUF[FIX] {SQL(默认值)|文本} 设置缺省文件的后缀,sqlplus在命令中使用,来引用命令文件. SUFFIX不控制输出(spool)文件的扩展名.
- TAB {OFF|ON(默认值)} 决定sqlplus在终端输出中如何格式化空白空间. 为OFF时,在输出中使用空格格式化空白空间;为ON时,用TAB字符. TAB的缺省值依赖于系统,用SHOW TAB命令可查看该缺省值.
- TERM[OUT] {OFF|ON(默认值)} 控制由文件执行命令所产生的输出的显示. OFF禁止显示,以致从一个命令文件假脱机输出,在屏幕上看不到输出. ON时显示输出. TERMOUT OFF 不影响交互地进行命令的输出.
- TI[ME] {OFF(默认值)|ON} 控制当前日期的显示. ON时,在每条命令提示前显示当前时间; OFF时禁止时间的显示.
```
11:37:54 SQL> set time off
SQL> set time on
11:38:21 SQL>
```
- TIMI[NG] {OFF(默认值)|ON} 控制时间统计的显示. ON时,显示每一个运行的SQL命令或PL/SQL块的时间统计; OFF时,禁止每一个命令的时间统计.
- TRIM[OUT] {OFF|ON(默认值)} 决定sqlplus在每一显示行的末端是否允许带空格. ON时将每行尾部的空格去了,特别当从慢速的通信设备存取sqlplus时可改进性能; OFF时允许sqlplus显示尾部的空格.TRIMOUT ON 不影响假脱机输出. 设置TAB ON时,sqlplus忽略TRIMOUT ON.
- UND[ERLINE] {-(默认值)|C|OFF|ON(默认值)} {-(默认值)|C|OFF|ON(默认值)} 设置用在sqlplus报表中下划线列标题的字符. ON或OFF将下划线置成开或关.
- VER[IFY] {OFF|ON(默认值)} 控制sqlplus用值替换前、后是否列出命令的文本. ON时显示文本;OFF时禁止列清单.
- WRA[P] {OFF|ON(默认值)} 控制sqlplus是否截断数据项的显示. OFF时截断数据项;ON时允许数据项缠绕到下一行. 在COLUMN命令中使用WRAPPED和TRUNCATED子句可控制对指定列的WRAP的设置.
# 参考
- [https://blog.csdn.net/lfc453048573/article/details/12956191](https://blog.csdn.net/lfc453048573/article/details/12956191)

View File

@ -0,0 +1,145 @@
---
title: "Ovirt 安装"
date: 2019-10-30T11:16:47+08:00
lastmod: 2019-10-30T11:16:47+08:00
tags: ["ovirt", "kvm", "虚拟化"]
categories: ["kvm"]
---
# 版本
Ovirt 4.1.7
# 操作系统初始配置
角色 | 主机名 | 配置 | IP | 版本 | /etc/hosts 追加行
-------- | ------- | -------------------- | ----------- | ------------------ | -------------------
管理节点 | engine | CPU: 多核<BR>RAM: 2G | 10.0.16.160 | CentOS 7.4 Minimal | 10.0.16.160 engine engine.ovirt<BR>10.0.16.161 host161
计算节点 | host161 | CPU: 多核<BR>RAM: 4G | 10.0.16.161 | CentOS 7.4 Minimal | 10.0.16.161 host161
- 建议保留操作系统自带的 NetworkManager 和 SELinux 服务
- 建议禁用操作系统自带的 firewalld 服务
- 时间同步,编辑 /etc/chrony.conf修改 server 地址如下
```
server s1c.time.edu.cn iburst
server s2m.time.edu.cn iburst
server s1b.time.edu.cn iburst
server s1e.time.edu.cn iburst
server s2a.time.edu.cn iburst
server s2b.time.edu.cn iburst
```
- 重启时间同步服务
```
systemctl restart chronyd
```
- 存储服务暂时采用计算节点的本机 NFS
# 导入 Ovirt yum 源
- 创建 ovirt.repo内容如下
```
[ovirt-4.1]
name=Latest oVirt 4.1 Release
baseurl=http://mirror.isoc.org.il/pub/ovirt/ovirt-4.1/rpm/el7/
enabled=1
skip_if_unavailable=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-ovirt-4.1
[ovirt-4.1-epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/7/x86_64/
failovermethod=priority
enabled=1
includepkgs=epel-release,python-uinput,puppet,python-lockfile,python-cpopen,python-ordereddict,python-pthreading,python-inotify,python-argparse,novnc,python-ply,python-kitchen,python-daemon,python-websockify,livecd-tools,spice-html5,mom,python-IPy,python-ioprocess,ioprocess,safelease,python-paramiko,python2-paramiko,python2-crypto,libtomcrypt,libtommath,python-cheetah,python-ecdsa,python2-ecdsa,python-markdown,rubygem-rgen,ovirt-guest-agent*,userspace-rcu,protobuf-java,objenesis,python34*,hystrix-core,archaius-core,rxjava,jctools,hystrix-metrics-event-stream,jackson-core,python-simplejson
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/epel/RPM-GPG-KEY-EPEL-7
[ovirt-centos7]
name=ovirt 4.1 CentOS 7
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/7/virt/x86_64/ovirt-4.1/
enabled=1
gpgcheck=0
[centos-opstools-release]
name=CentOS-7 - OpsTools - release
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/7/opstools/x86_64/
enabled=1
gpgcheck=0
[patternfly-patternfly1]
name=Copr repo for patternfly1 owned by patternfly
baseurl=https://copr-be.cloud.fedoraproject.org/results/patternfly/patternfly1/epel-7-$basearch/
type=rpm-md
skip_if_unavailable=True
gpgcheck=1
gpgkey=https://copr-be.cloud.fedoraproject.org/results/patternfly/patternfly1/pubkey.gpg
repo_gpgcheck=0
enabled=1
enabled_metadata=1
```
- 分发 ovirt.repo 到全部服务器的 /etc/yum.repos.d/ 下
- 下载[RPM-GPG-ovirt-4.1](http://mirror.isoc.org.il/pub/ovirt/keys/RPM-GPG-ovirt-v2),分发到全部服务器的 /etc/pki/rpm-gpg/ 下
- 在全部服务器上,执行以下命令:
```bash
yum clean all
yum makecache fast
yum repolist #此时能看到新增加的 ovirt.repo 文件中的 yum 源
```
# 配置管理节点(engine)
- 在 engine 上分发免密登陆各计算节点(host)的密钥
```bash
ssh-keygen #全部默认回车即可
ssh-copy-id host161
```
- 安装 ovirt-engine 软件包
```bash
yum install ovirt-engine
```
- 配置 engine
```bash
engine-setup
#进入交互中,根据提示选择适合自己的选项
```
- 配置完成后engine 服务启动
- 在个人 PC 上配置好 "10.0.16.160 engine engine.ovirt",浏览器打开 https://engine.ovirt
# 配置计算节点(host161)
- 打开 ovirt 管理 web 界面: http://engine.ovirt以 admin 身份登陆
- 打开 "主机" 标签页,单击左上角的 "新建"
- 在打开 "新建主机" 窗口中,选择 "主机集群",填写 "名称"、"地址"、"ssh端口"、"用户名" 等信息
- 选择 "ssh公共密钥",复制右侧文本框中的公钥到目标计算节点(host161)的 /root/.ssh/authorized_keys 中
- 单击 "确定"host161 开始自动安装,通过 web 界面底部的详情窗格中可以看到安装过程
- host 安装完成后会自动启动,状态变成 "up"
# 配置存储
- 服务器数量有限,这里直接在计算节点上启动 NFS
- 在 host161 上编辑 /etc/exports增加如下配置
```
/NFS/iso1 10.0.16.160(rw,no_all_squash,async)
/NFS/iso1 10.0.16.161(rw,no_all_squash,async)
/NFS/data1 10.0.16.161(rw,no_all_squash,async)
```
- 在 host161 上创建可读写的 nfs 目录,启动 NFS
```bash
mkdir /NFS/{data1,iso1}
chmod -R 0777 /NFS
systemctl start nfs
systemctl enable nfs
```
- 打开 ovirt 管理 web 界面: http://engine.ovirt以 admin 身份登陆
- 打开 "存储" 标签页,单击左上角的 "新建域"
- 在打开的 "新建域" 窗口中,选择 "域功能"-"Data", "存储类型"-"NFS", "使用主机"-"host161", "名称"-"data1"
- 在 "导出路径" 文本框中输入: 10.0.16.161:/NFS/data1
- 单击 "确定"DATA 存储域 "data1" 开始自动配置
- 自动配置成功后,该 DATA 存储域状态自动切换为 "Active"
- 再次单击 "新建域",在 "新建域" 窗口中选择 "域功能"-"ISO", "名称"-"iso1", 其他项与 DATA 存储域配置一致
- 在 "导出路径" 文本框中输入: 10.0.16.161:/NFS/iso1
- 单击 "确定"ISO 存储域 "iso1" 开始自动配置,完成后,该存储域状态自动切换为 "Active"
# 导入操作系统 iso
- 前面的存储创建好后ovirt 就可以用了,接下来是导入 iso 镜像
- 从 engine 导入 iso 文件
```bash
engine-iso-uploader --iso-domain=iso1 upload {filename.iso}
#密码是 web 管理界面 admin 用户的密码
```
- iso 文件导入成功后,就可以用来创建虚拟机了

101
content/post/ovirt.md Normal file
View File

@ -0,0 +1,101 @@
---
title: "Ovirt 笔记"
date: 2019-10-30T13:04:51+08:00
lastmod: 2019-10-30T13:04:51+08:00
tags: ["ovirt"]
categories: ["kvm"]
---
# 封装 CentOS6/7 虚拟机
- 标识 “重新配置”
```bash
touch /.unconfigured
```
- 删除 ssh 主机密钥
```bash
rm -rf /etc/ssh/ssh_host_*
```
- 恢复原始主机名 ”localhost“
```bash
#CentOS6
sed -i '/^HOSTNAME/cHOSTNAME=localhost.localdomain' /etc/sysconfig/network
#CentOS7
sed -i '/^HOSTNAME/cHOSTNAME=localhost.localdomain' /etc/hostname
```
- 清理 udev
```bash
rm -rf /etc/udev/rules.d/70-*
```
- 删除网卡硬件标识
```bash
sed -i -e '/HWADDR/d' -e '/UUID/d' /etc/sysconfig/network-scripts/ifcfg-{eth,enp}*
```
- 清空日志
```bash
rm -rf /var/log/*
```
- 关闭虚拟机
```bash
poweroff
```
# 解锁 admin 用户
- 查看状态
```bash
ovirt-aaa-jdbc-tool user show admin
```
- 解锁
```bash
ovirt-aaa-jdbc-tool user unlock admin
```
# 创建本地 yum 源
- 安装工具
```bash
yum install yum-utils createrepo
```
- 解压 rpm 包(无用,仅作记录)
```bash
rpm2cpio {filename}.rpm | cpio -ivd
```
- 下载 ovirt.repo保存到本地服务器的 /etc/yum.repos.d/ 下
- 下载 RPM-GPG-ovirt-4.1,保存到本地服务器的 /etc/pki/rpm-gpg/ 下
- 在该服务器上,执行以下命令:
```bash
yum clean all
yum makecache fast
yum repolist #此时能看到新增加的 ovirt.repo 文件中的 yum 源
```
- 同步 yum repo 到本地
```bash
mkdir /DATA/yum && cd /DATA/yum
reposync -nld \
--repoid=ovirt-4.1 \
--repoid=ovirt-4.1-epel \
--repoid=ovirt-centos7 \
--repoid=centos-opstools-release \
--repoid=patternfly-patternfly1
```
- 创建本地 yum repo
```bash
createrepo --update ovirt-4.1
createrepo --update ovirt-4.1-epel
createrepo --update ovirt-centos7
createrepo --update centos-opstools-release
createrepo --update patternfly-patternfly1
```
- nginx.conf 配置
```nginx
server {
listen 1080 default_server;
listen [::]:1080 default_server;
server_name _;
root /DATA/yum;
location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
}
```

22
content/post/pip.md Normal file
View File

@ -0,0 +1,22 @@
---
title: "python pip"
date: 2019-10-29T21:17:22+08:00
lastmod: 2019-10-29T21:17:22+08:00
keywords: []
tags: ["pip", "python"]
categories: ["python"]
---
# 配置 pip 源
- 创建 $HOME/.pip/pip.conf 文件,内容如下
```ini
[global]
index-url=https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host=pypi.tuna.tsinghua.edu.cn
[list]
format=columns
```

View File

@ -0,0 +1,101 @@
---
title: "CentOS7 安装 Postgresql"
date: 2019-10-30T00:48:54+08:00
lastmod: 2019-11-04T02:03:00+08:00
keywords: []
tags: ["postgresql"]
categories: ["database"]
---
# 环境
- CentOS 7
- PostgreSQL 10.10
# 安装
- 安装 yum 源
```bash
yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# 或者从清华镜像站下载
yum install https://mirrors.tuna.tsinghua.edu.cn/postgresql/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# 可以更换成清华镜像站地址
sed -i 's,download.postgresql.org/pub,mirrors.tuna.tsinghua.edu.cn/postgresql,' /etc/yum.repos.d/pgdg-redhat-all.repo
# 更新 yum 缓存
yum clean all
yum makecache fast
```
- 安装 postgresql-server
```bash
yum install postgresql10-server
```
- 初始化数据库
```bash
/usr/pgsql-10/bin/postgresql-10-setup initdb
```
- 启动数据库
```bash
systemctl start postgresql-10
```
# 配置 postgresql.conf
- 监听本机全部地址
```
clisten_addresses = '*'
```
# 配置 pg_hba.conf
- 配置同网段客户端可通过 pguser1 使用密码登陆 pgdb1
```bash
echo 'host pgdb1 pguser1 samenet md5' >> pg_hba.conf
```
- 配置任何客户端可通过任何用户使用密码登陆任何数据库
```bash
echo 'host all all all md5' >> pg_hba.conf
```
# 简单使用
- 登陆数据库
```bash
su - postgres
psql -U postgres
```
- 简单操作
```sql
-- 修改 postgres 用户的默认密码
alter user postgres with password '123456';
-- 创建新用户 pguser1
create user pguser1 with password '123456';
-- 创建数据库 pgdb1
create database pgdb1 owner pguser1 encoding utf8;
-- 授权
grant all on database pgdb1 to pguser1;
-- 查看系统操作帮助
\?
-- 查看 sql 语句操作帮助
\h
-- 查看建库语句操作
\h create database
-- 退出数据库
\q
```
# 迁移数据库目录
- 停止数据库 postgresql
```bash
systemctl stop postgresql-10
```
- 移动数据库目录
```bash
mkdir -p /data/pgsql/10
mv /var/lib/pgsql/10/data /data/pgsql/10/
chown -R postgres.postgres /data/pgsql
```
- 修改 service 文件
```bash
sed -i 's,/var/lib/pgsql/10,/data/pgsql/10,' /usr/lib/systemd/system/postgresql-10.service
systemctl daemon-reload
```
- 启动数据库
```bash
systemctl start postgresql-10
```

View File

@ -0,0 +1,69 @@
---
title: "Postgresql 主从"
date: 2019-11-04T02:09:29+08:00
lastmod: 2019-11-04T02:09:29+08:00
tags: ["postgresql", "replcation", "同步"]
categories: ["database"]
---
# 主库配置
- 修改 postgresql.conf
```
listen_address = '*'
wal_level = replica
wax_wal_senders = 10
wal_keep_segments = 64
hot_standby = on
```
- 启动主库 postgresql-10 服务
```bash
systemctl start postgresql-10
```
- 创建同步账户
```sql
create user replica superuser password '123456';
-- 这里可以只赋予 replication 权限,后面从库复制初始数据库时使用其他有权限帐号
```
- 修改 pg_hba.conf
```
host replication replica samenet md5
```
# 从库配置
- 停止从库 postgresql-10 服务,清空数据库目录
```bash
systemctl stop postgresql-10
rm -rf /var/lib/pgsql/10/data/*
```
- 从主库复制初始数据库
```bash
pg_basebackup \
-h <主库ip> \
-U replica \
-F p \
-X stream \
-P -R \
-D /var/lib/pgsql/10/data/ \
-l backup_20191104
```
- -h 指定连接的数据库的主机名或IP地址
- -U 指定连接的用户名
- -F 指定了输出的格式支持p原样输出或者ttar格式输出
- -X 表示备份开始后启动另一个流复制连接从主库接收WAL日志
- -P 表示允许在备份过程中实时的打印备份的进度
- -R 表示会在备份结束后自动生成recovery.conf文件
- -D 指定备份写入的数据目录,需要与数据库配置的数据库目录一致,初次备份之前从库的数据目录需要手动清空
- -l 表示指定一个备份的标识
# 检查状态
- 检查从库进程
```bash
ps -ef|grep postgres
# 可以看到 wal sender 和 receiver process 两个进程
```
- 从库为只读模式,无法进行 增/删/改 操作
- 主库查看 replication 客户端
```sql
select client_addr,sync_state from pg_stat_replication;
```

View File

@ -0,0 +1,98 @@
---
title: "Dnsmasq 实现网络 PXE 装机"
date: 2019-11-08T15:52:55+08:00
lastmod: 2019-11-08T15:52:55+08:00
tags: ["dnsmasq", "pxe"]
categories: ["OS"]
---
# 把 dnsmasq 配置成 pxe 服务器
- 安装 dnsmasq
```bash
# rhel
yum install dnsmasq
# archlinux
pacman -S dnsmasq
```
- 修改配置 /etc/dnsmasq.conf
```ini
port=0 # 用不着 dns 功能,可以关闭
#interface=ens8u2u4u1 # 指定网卡
dhcp-range=10.0.86.1,10.0.86.9,255.255.255.0,1h
#dhcp-boot=pxelinux.0 # bios 引导
dhcp-boot=grubx64.efi # efi 引导
enable-tftp
tftp-root=/var/ftpd
```
- 启动 dnsmasq
```bash
systemctl start dnsmasq
```
# 安装 CentOS7/8
- **本次测试使用 CentOS7.7 和 CentOS8.0 镜像**
## 挂载系统镜像,提供软件源服务
- 下载 centos7/8 镜像到 dnsmasq 服务器
- 挂载镜像到 /mnt 目录
```bash
mount -o loop xxxx.iso /mnt
```
- 直接在系统镜像的挂载目录(/mnt)启动 http 服务
```bash
cd /mnt
python2 -m SimpleHTTPServer 10086
# 或者使用 python3
python3 -m http.server 10086
```
## 网络 BIOS 引导
- 复制 centos7/8 镜像里的启动文件到 dnsmasq 服务器的 /var/ftpd/ 下
```bash
cd /var/ftpd
cp /mnt/isolinux/* .
mkidr pxelinux.cfg
mv isolinux.cfg pxelinux.cfg/default
```
- 打开 /var/ftpd/pxelinux.cfg/default修改第一个启动项
```
label linux
menu label ^Install CentOS 7/8
kernel vmlinuz
append initrd=initrd.img inst.repo=http://10.0.86.1:10086/ quiet
# ks 参数: inst.ks=<ks.cfg url>
```
- 在 centos7/8 上安装 syslinux
```bash
yum install syslinux # centos7
dnf install syslinux # centos 8
```
- 把 /user/share/syslinux/pxelinux.0 复制到 dnsmasq 服务器的 /var/ftpd/ 下
- 修改文件权限,确保 dnsmasq 用户可读
```bash
chown -R dnsmasq.dnsmasq /var/ftpd/
```
## 网络 EFI 引导
- **不支持 secure boot**
- 复制 centos7/8 镜像里的启动文件到 dnsmasq 服务器的 /var/ftpd/ 下
```bash
cp -a /mnt/EFI/BOOT/* /var/ftpd/
```
- 打开 /var/ftpd/grub.cfg修改第一个启动项
```
menuentry 'Install CentOS 7/8' --class fedora --class gnu-linux --class gnu --class os {
linuxefi vmlinuz inst.repo=http://10.0.86.1:10086/ quiet
initrdefi initrd.img
}
# ks 参数: inst.ks=<ks.cfg url>
```
- 修改文件权限,确保 dnsmasq 用户可读
```bash
chown -R dnsmasq.dnsmasq /var/ftpd/
```
# 装机
- 把待安装机器和 dnsmasq 服务器接入同一个交换机(无其他 dhcp 广播)
- 启动待安装机器,选择 pxe 引导,从第一个启动项启动

169
content/post/python-cf.md Normal file
View File

@ -0,0 +1,169 @@
---
title: "Python 的 ConfigParser 模块"
date: 2019-10-30T18:04:09+08:00
lastmod: 2019-10-30T18:04:09+08:00
tags: ["python", "configparser"]
categories: ["python"]
---
# 样例文件
- 该类配置文件可以包含一个或多个节section每个节可以有多个参数键=值)。
- 样例配置文件(/proj/conf/example_conf
```
[book]
title:ConfigParser模块教程
author:大头爸爸
email:366500050@qq.com
time:2012-09-20 22:04:55
[size]
size:1024
[other]
blog:csdn.net
```
- 上面配置文件中用的是冒号,也可以用等号。
# 读取配置文件
- 示例文件: example.py
```python
# -*- coding: utf-8 -*-
import ConfigParser
import string
config=ConfigParser.ConfigParser()
config.read(u'/proj/conf/example_conf')
print string.upper(config.get("book","title")),
print "by",config.get("book","author"),
print "("+config.get("book","email")+")"
print
print config.get("size","size")
print
print config.sections()
for section in config.sections():
print section
for option in config.options(section):
print " ",option,"=",config.get(section,option)
```
- example.py文件执行结果
```
CONFIGPARSER模块教程 by 大头爸爸 (366500050@qq.com)
1024
['book', 'size', 'other']
book
title = ConfigParser模块教程
author = 大头爸爸
email = 366500050@qq.com
time = 2012-09-20 22:04:55 size
size = 1024 other
blog = csdn.n
```
# 写入配置文件
- 示例
```python
import ConfigParser
import sys
config=ConfigParser.ConfigParser()
config.add_section("book")
config.set("book","title","这是标题")
config.set("book","author","大头爸爸")
config.add_section("size")
config.set("size","size",1024)
config.write(sys.stdout)
```
- 执行结果
```
[book]
title = 这是标题
author = 大头爸爸
[size]
size = 1024
```
# ConfigParser方法
- 创建ConfigParser实例
```python
config=ConfigParser.ConfigParser()
```
- 返回配置文件中节序列
```python
config.sections()
```
- 返回某个项目中的所有键的序列
```python
config=ConfigParser.ConfigParser()
config.options(section)
```
- 返回section节中option的键值
```python
config=ConfigParser.ConfigParser()
config.get(section,option)
```
- 添加一个配置文件节点(str)
```python
config=ConfigParser.ConfigParser()
config.add_section(str)
```
- 设置section节点中键名为option的值(val)
```python
config=ConfigParser.ConfigParser()
config.set(section,option,val)
```
- 读取配置文件
```python
config=ConfigParser.ConfigParser()
config.read(filename)
```
- 写入配置文件
```python
config=ConfigParser.ConfigParser()
config.write(obj_file)
```
# 综合实例
```python
#coding=utf-8
import ConfigParser
def writeConfig(filename):
config = ConfigParser.ConfigParser()
# set db
section_name = 'db'
config.add_section( section_name )
config.set( section_name, 'dbname', 'MySQL')
config.set( section_name, 'host', '127.0.0.1')
config.set( section_name, 'port', '80')
config.set( section_name, 'password', '123456')
config.set( section_name, 'databasename', 'test')
# set app
section_name = 'app'
config.add_section( section_name )
config.set( section_name, 'loggerapp', '192.168.20.2')
config.set( section_name, 'reportapp', '192.168.20.3')
# write to file
config.write( open(filename, 'a') )
def updateConfig(filename, section, **keyv):
config = ConfigParser.ConfigParser()
config.read(filename)
print config.sections()
for section in config.sections():
print "[",section,"]"
items = config.items(section)
for item in items:
print "\t",item[0]," = ",item[1]
print config.has_option("dbname", "MySQL")
print config.set("db", "dbname", "11")
print "..............."
for key in keyv:
print "\t",key," = ", keyv[key]
config.write( open(filename, 'r+') )
if __name__ == '__main__':
file_name = 'test.ini'
writeConfig(file_name)
updateConfig(file_name, 'app', reportapp = '192.168.100.100')
print "end__"
```

View File

@ -0,0 +1,65 @@
---
title: "Python 的 cx_Oracle 模块"
date: 2019-10-30T17:55:41+08:00
lastmod: 2019-10-30T17:55:41+08:00
tags: ["python", "cx_oracle"]
categories: ["python"]
---
# 导入 cx_Oracle 模块
```
import cx_Oracle # 导入模块
```
# 连接数据库
```
db = cx_Oracle.connect('user', 'password', 'host:port/SID') #建立连接,3个参数分开写
print db.version
#输出 10.2.0.1.0 测试成功
```
# 自动提交
```
db.autocommit=True #开启自动提交
db.autocommit=False #关闭自动提交
```
# 建立 cursor 光标
```
cursor = db.cursor() #建立一个cursor
```
# 执行sql
```
cursor.execute(select * from tabs) # 执行一条sql
sql = "insert into person(name, age, telephone) values(%s, %s, %s)"
tmp = (('ninini', 89, '888999'), ('koko', 900, '999999'))
conn.executemany(sql, tmp) #执行多条sql
```
# 获取执行结果
```
row=cursor.fetchone() #取一行结果,元组(a,b,c,d)
row=cursor.fetchall() #获取所有结果,列表[(a,b,c,d),(e,f,g,h),...]
for x in row:
For y in x:
Print y
print cursor.rowcount() #获取输出记录数量
```
# 提交
```
db.commit()
```
# 回滚
```
db.rollback()
```
# 关闭连接
```
cursor.close()
db.close()
```

View File

@ -0,0 +1,77 @@
---
title: "Python 的 logging 模块"
date: 2019-10-30T18:03:55+08:00
lastmod: 2019-10-30T18:03:55+08:00
tags: ["python", "logging"]
categories: ["python"]
---
# 单输出日志到屏幕
- 示例
```python
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
```
- 输出
```python
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
```
- 默认情况下python的logging模块将日志打印到了标准输出中且只显示了大于等于WARNING级别的日志。
- 默认的日志级别设置为WARNING日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
- 默认的日志格式为日志级别:Logger名称:用户输出消息。
# 配置日志
- 示例
```python
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='/tmp/test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
```
- 输出
```python
cat /tmp/test.log
Mon, 05 May 2014 16:29:53 test_logging.py[line:9] DEBUG debug message
Mon, 05 May 2014 16:29:53 test_logging.py[line:10] INFO info message
Mon, 05 May 2014 16:29:53 test_logging.py[line:11] WARNING warning message
Mon, 05 May 2014 16:29:53 test_logging.py[line:12] ERROR error message
Mon, 05 May 2014 16:29:53 test_logging.py[line:13] CRITICAL critical message
```
- logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为参数解释
- filename用指定的文件名创建FiledHandler后边会具体讲解handler的概念这样日志会被存储在指定的文件中。
- filemode文件打开方式在指定了filename时使用这个参数默认值为“a”还可指定为“w”。
- format指定handler使用的日志显示格式。
- datefmt指定日期时间格式。
- level设置rootlogger后边会讲解具体概念的日志级别
- stream用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件默认为sys.stderr。若同时列出了filename和stream两个参数则stream参数会被忽略。
- format参数中可能用到的格式化串
- %(name)s Logger的名字
- %(levelno)s 数字形式的日志级别
- %(levelname)s 文本形式的日志级别
- %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
- %(filename)s 调用日志输出函数的模块的文件名
- %(module)s 调用日志输出函数的模块名
- %(funcName)s 调用日志输出函数的函数名
- %(lineno)d 调用日志输出函数的语句所在的代码行
- %(created)f 当前时间用UNIX标准的表示时间的浮 点数表示
- %(relativeCreated)d 输出日志信息时的自Logger创建以 来的毫秒数
- %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
- %(thread)d 线程ID。可能没有
- %(threadName)s 线程名。可能没有
- %(process)d 进程ID。可能没有
- %(message)s用户输出的消息

104
content/post/python-op.md Normal file
View File

@ -0,0 +1,104 @@
---
title: "Python 的 optionparser 模块"
date: 2019-10-30T17:46:52+08:00
lastmod: 2019-10-30T17:46:52+08:00
tags: ["python", "optionparser"]
categories: ["python"]
---
# 生成标准的、符合Unix/Posix 规范的命令行说明
```python
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-p', '--pdbk', action = 'store_true', dest = 'pdcl', default = False,
help = 'write pdbk data to oracle db')
parser.add_option('-z', '--zdbk', action = 'store_true', dest = 'zdcl', default = False,
help = 'write zdbk data to oracle db')
(options, args) = parser.parse_args()
if options.pdcl == True:
print 'pdcl is true.'
if options.zdcl == True:
print 'zdcl is True.'
```
# 简单流程
```python
#引入OptionParser类创建OptionParser对象
from optparse import OptionParser
parser = OptionParser()
# 定义命令行参数
parser.add_option(opt_str, ..., attr = value, ...)
# 解析命令行参数
(options, args) = parser.parse_args()
```
# parse_args 和 add_options 函数
- parse_args() 接收一个命令行列表,默认使用 sys.argv\[:-1\]
- 返回两个值options 保存命令行参数值args 是由 positional arguments 组成的列表
- add_option() 用来加入选项parse_args() 解析选项
```python
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-f', '--file', dest = 'filename', metavar = 'FILE',
help = 'write report to FILE')
parser.add_option('-q', '--quit', action = 'store_false', dest = 'verbose', default = True,
help = 'Don\'t print status message to stdout.')
(options, args) = parser.parse_args()
```
- action 默认 store 表示将参数值保存到 options 对象里
```python
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-f', '--file', action = 'store', type = 'string', dest = 'filename')
args = ['-f', 'foo.txt']
(options, args) = parser.parse_args(args)
print options.filename
```
- type 默认 'string',也可以是 'int' 或 'float' 等长参数名可选dest 未指定时将用命令行的参数名来存取 options 对象的值
- store 其他两种形式store_true 和 store_false还有 store_const、append、count、callback
```python
parser.add_option('-v', action = 'store_true', dest = 'verbose')
parser.add_option('-q', action = 'store_false', dest = 'verbose')
#当解析到 '-v', options.verbose 为 True解析到 '-q'options.verbose 为 False
```
- default 设置参数默认值
```
parser.add_option('-f', action = 'store', dest = 'filename', default = 'foo.txt')
parser.add_option('-v', action = 'store_true', dest = 'verbose', default = True)
#也可以使用 set_default()
parser.set_defaults(filename = 'foo.txt', verbose = True)
parser.add_option(...)
(options, args) = parser.parse_args()
```
- help 生成帮助信息
```python
usage = 'usage: %prog [options] arg1 arg2'
parser = OptionParser(usage = usage)
parser.add_option('-v', '--verbose', action = 'store_true', dest = 'verbose', default = True,
help = 'make lots of noise [default]')
parser.add_option('-q', '--quiet', action = 'store_false', dest = 'verbose',
help = 'be very quiet')
parser.add_option('-f', '--filename', metavar = 'FILE',
help = 'write output to FILE')
parser.add_option('-m', '--mode', metavar='MODE', default = 'intermediate',
help = 'interaction mode: novice, intermediate, or expert [default: %default]')
```
# 备注
- optparse 解析到 help 后不再解析其他命令行参数usage 信息会优先打印,默认 "usage: %prog \[options\]"
- metavar 提醒用户该参数期待的参数,如 metavar = 'mode' 会在帮助中显示成 -m MODE, --mode=MODE
# OptionGroup 参数分组
```python
group = OptionGroup(parser, 'Dangerous Options',
'Caution: use these options at your own risk. It is believed that some of them bite.')
group.add_option('-g', action = 'store_true', help = 'Group option.')
parser.add_option_group(group)
```
- version 创建OptionParser对象时指定该参数会解释成 --version 命令行参数
- optparser 可以自动探测并处理一些用户异常,也可以使用 parser.error() 方法来自定义部分异常的处理
```
if options.a and options.b:
parser.error('options -a and -b are mutually exclusive')
```

26
content/post/python-os.md Normal file
View File

@ -0,0 +1,26 @@
---
title: "Python 的 os 和 os.path"
date: 2019-10-30T17:45:33+08:00
lastmod: 2019-10-30T17:45:33+08:00
tags: ["python", "os", "os.path"]
categories: ["python"]
---
- os.getcwd() #返回运行脚本的目录
- os.listdir() #获取目录中的内容
- os.path.basename() #去掉目录路径,返回文件名
- os.path.dirname() #去掉文件名,返回目录路径
- os.path.join() #组合成合法路径
- os.path.split() #返回路径和文件名元组
- os.path.splitdrive() #返回驱动器符号和路径元组
- os.path.splitext() #返回文件名和扩展名元组
- os.path.getatime() #返回文件最近的访问时间戳
- os.path.getctime() #返回文件的创建时间戳
- os.path.getmtime() #返回文件修改时间
- os.path.getsize() #返回文件大小Bytes
- os.path.exists() #指定目录或文件是否存在
- os.path.isabs() #指定路径是否为绝对路径
- os.path.isdir() #指定路径是否为目录
- os.path.isfile() #指定路径是否为文件
- os.path.samefile() #指定路径名是否指向同一个文件

Some files were not shown because too many files have changed in this diff Show More