Jim

Talk is cheap. Show me the code.


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

  • 搜索

谷歌云对象存储 gcs 开启日志记录功能

发表于 2019-01-06 | 分类于 Google Cloud Platform

问题描述

有时候我们需要对 gcs 开启日志记录功能,一方面可以分析统计每个针对 gcs 的 http 请求的详细信息,另一方面还可以用于问题调试用途,比如我们对一个存储分区的对象配置了生命周期,可以看其访问日志判断配置是否生效。

gcs 日志记录功能记录两种类型日志

访问日志:访问日志是每小时创建一次,记录对指定存储分区发出的所有请求的信息;
存储日志:存储分区过去 24 小时内存储空间平均使用量,以字节为单位;

https://cloud.google.com/storage/docs/access-logs?hl=zh-cn&refresh=1

gcs 开启日志记录功能步骤

以开启 gs://gcs-bucket 存储分区日志记录功能为例:

  1. 创建一个存储分区用于存储日志记录,名字随便起:

    1
    gsutil mb -l asia gs://gcs-bucket-logs-record
  2. 设置权限以使 Cloud Storage 对该存储分区具有 WRITE 权限

    1
    gsutil acl ch -g cloud-storage-analytics@google.com:W gs://gcs-bucket-logs-record
  3. 为存储分区开启日志记录功能
    命令格式:gsutil logging set on -b <日志存储分区> <要开启日志记录功能的存储分区>

    1
    gsutil logging set on -b gs://gcs-bucket-logs-record gs://gcs-bucket
  4. 检查日志记录功能是否开启成功

    1
    gsutil logging get gs://gcs-bucket

    如果开启成功会显示:{"logBucket": "gcs-bucket-logs-record", "logObjectPrefix": "gcs-bucket"}

    另外,开启成功后过 2 小时左右就可以在 gs://gcs-bucket-logs-record 看到日志文件产生了,日志文件格式为 csv。

  5. 关闭日志记录功能

    1
    gsutil logging set off gs://gcs-bucket

日志文件命名格式及日志内容格式见文档详细说明

https://cloud.google.com/storage/docs/access-logs?hl=zh-cn&refresh=1

非容器化 gitlab 进行容器化改造

发表于 2018-12-02 | 分类于 Git

本文主要介绍非容器化(通过 yum 在 Linux 服务器安装)gitlab 进行容器化改造的两种方法,都是基于 Kubernetes 平台,均采用 helm 部署。第一种是基于自建 k8s 平台部署 gitlab,第二种是基于 Google GKE 平台部署 gitlab。

Docker 镜像采用基于 Omnibus 安装包的镜像,gitlab 的各个组件都运行在同一个容器中。关于 GitLab Ominibus 镜像和云原生镜像的区别见这里。

gitlab 容器化改造(基于自建 k8s 平台部署 gitlab)

一、搭建和原先版本一致的 gitlab

github helm gitlab-ee chart:https://github.com/helm/charts/tree/master/stable/gitlab-ee

在此 helm chart 基础上将备份目录也(/var/opt/gitlab/backups)通过PVC持久化,方便数据的备份恢复: https://github.com/qhh0205/helm-charts/tree/master/gitlab-ee

  1. 手动创建需要的 pv(基于 nfs)
    https://github.com/qhh0205/kubernetes-resources/tree/master/gitlab-pv
  2. 部署
    其他自定义参数修改 values-custom.yaml 文件,比如镜像版本、硬件配置等参数。
    1
    2
    3
    git clone git@github.com:qhh0205/helm-charts.git
    cd helm-charts/gitlab-ee
    helm install --name gitlab --set externalUrl=http://domain/,gitlabRootPassword=xxxx -f values-custom.yaml ./ --namespace=gitlab

二、数据恢复

  1. 拷贝 gitlab 备份文件到容器外挂nfs目录(/data/nfs/gitlab/gitlab-data-backups(nfs路径)—>/var/opt/gitlab/backups(容器路径));
  2. 进入容器:
    kubectl exec -it pod_name /bin/sh -n gitlab
  3. gitlab-ctl reconfigure
  4. chown git:git 1543237967_2018_11_26_10.1.3-ee_gitlab_backup.tar
  5. chown -R git:root /gitlab-data # 由于 gitlab-rake 执行过程中 默认用户名是 git,所以需要把该目录的属主改成 git,否则恢复时报错权限问题;
  6. gitlab-rake gitlab:backup:restore
    根据提示输入相关信息
    YES
    YES
    gitlab-ctl restart

gitlab 容器化改造(基于 Google 云 GKE 平台)

一、搭建和原先版本一致的 gitlab

github helm gitlab-ee chart:https://github.com/helm/charts/tree/master/stable/gitlab-ee

在此 helm chart 基础上将备份目录也(/var/opt/gitlab/backups)通过PVC持久化,方便数据的备份恢复:
https://github.com/qhh0205/helm-charts/tree/master/gitlab-ee

其他自定义参数修改 values-custom.yaml 文件,比如镜像版本、硬件配置等参数。

1
2
3
git clone git@github.com:qhh0205/helm-charts.git
cd helm-charts/gitlab-ee
helm install --name gitlab --set externalUrl=http://domain/,gitlabRootPassword=xxxx -f values-custom.yaml ./ --namespace=gitlab

二、数据迁移恢复

  1. 将 gitlab 备份文件拷贝到 k8s gitlab pod 容器目录:

    1
    2
    kubectl cp 1543237967_2018_11_26_10.1.3-ee_gitlab_backup.tar \
    namespace/pod_name:/var/opt/gitlab/backups -n gitlab
  2. gitlab-ctl reconfigure

  3. chown git:git 1543237967_2018_11_26_10.1.3-ee_gitlab_backup.tar
  4. chown -R git:root /gitlab-data # 由于 git-rake 执行过程中 默认用户名是 git,所以需要把该目录的属主改成git,否则恢复时报错权限问题;
  5. gitlab-rake gitlab:backup:restore
    根据提示输入相关信息
    YES
    YES
    gitlab-ctl restart

外部访问

  1. Kong Ingress
  2. NodePort
  3. LoadBalancer(云提供商平台,比如 Google GKE)

相关链接

  • 容器化安装 gitlab:https://docs.gitlab.com/ee/install/docker.html
  • gitlab 数据存放目录修改:https://blog.whsir.com/post-1490.html
  • gitlab 安装软件和硬件需求:https://docs.gitlab.com/ce/install/requirements.html
  • Omnibus GitLab documentation: https://docs.gitlab.com/omnibus/README.html

Linux 文件与目录管理相关命令总结

发表于 2018-12-02 | 分类于 Linux

Python 解析 Spring pom 文件获取 jar 包名称

发表于 2018-11-18 | 分类于 Python

前段时间在做持续集成有个小需求是根据 pom 文件获取 jar 包名称,在网上搜寻一番,整理了一份脚本,可以直接使用,通过解析 pom 文件获取(xml2pydict.py):
使用示例:python xml2pydict.py pom.xml
输出结果:jar 包名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/10/22 下午5:53
# @Author : haohao.qiang
# @Mail : qhh0205@gmail.com
# @File : xml2pydict.py

import sys
import warnings
from xml.parsers import expat
import xml.etree.ElementTree as ElementTree
warnings.filterwarnings("ignore")

class XmlListConfig(list):
def __init__(self, aList):
for element in aList:
if element:
# treat like dict
if len(element) == 1 or element[0].tag != element[1].tag:
self.append(XmlDictConfig(element))
# treat like list
elif element[0].tag == element[1].tag:
self.append(XmlListConfig(element))
elif element.text:
text = element.text.strip()
if text:
self.append(text)


class XmlDictConfig(dict):
'''
Example usage:

tree = ElementTree.parse('your_file.xml')
root = tree.getroot()
xmldict = XmlDictConfig(root)

Or, if you want to use an XML string:

root = ElementTree.XML(xml_string)
xmldict = XmlDictConfig(root)

And then use xmldict for what it is... a dict.
'''
def __init__(self, parent_element):
if parent_element.items():
self.update(dict(parent_element.items()))
for element in parent_element:
if element:
# treat like dict - we assume that if the first two tags
# in a series are different, then they are all different.
if len(element) == 1 or element[0].tag != element[1].tag:
aDict = XmlDictConfig(element)
# treat like list - we assume that if the first two tags
# in a series are the same, then the rest are the same.
else:
# here, we put the list in dictionary; the key is the
# tag name the list elements all share in common, and
# the value is the list itself
aDict = {element[0].tag: XmlListConfig(element)}
# if the tag has attributes, add those to the dict
if element.items():
aDict.update(dict(element.items()))
self.update({element.tag: aDict})
# this assumes that if you've got an attribute in a tag,
# you won't be having any text. This may or may not be a
# good idea -- time will tell. It works for the way we are
# currently doing XML configuration files...
elif element.items():
self.update({element.tag: dict(element.items())})
# finally, if there are no child tags and no attributes, extract
# the text
else:
self.update({element.tag: element.text})


if __name__ == "__main__":
xml = sys.argv[1]
oldcreate = expat.ParserCreate
expat.ParserCreate = lambda encoding, sep: oldcreate(encoding, None)
tree = ElementTree.parse(xml)
root = tree.getroot()
xmldict = XmlDictConfig(root)
print "{}-{}.{}".format(xmldict.get('artifactId'), xmldict.get('version'), xmldict.get('packaging'))

Linux 文件权限属性相关总结

发表于 2018-11-18 | 分类于 Linux

Linux 文件权限属性相关总结

基础知识

文件权限与属性修改

  • chgrp: 更改文件属组
  • chown: 更改文件属主
  • chmod: 更改文件权限,SUID、SGID、SBIT 等属性

1. 更改文件属组

更改时组名必须存在,即在必须在 /etc/group 文件内存在,否则报错。

1
2
3
4
5
6
7
8
9
10
命令格式: chgrp [-R] group_name dirname/filename ...
选顷参数:
-R : 递归(recursive)更改,即连同子目彔下的所有文件、目录
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 vagrant vagrant 5 Nov 17 19:04 aa
[root@centos7 vagrant]# chgrp root aa
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 vagrant root 5 Nov 17 19:04 aa

2. 更改文件属主

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
命令格式: 
chown [-R] 账号名称 文件或目彔(只更改属主)
chown [-R] 账号名称:组名 文件或目彔(属主和属组同时更改)
选顷参数:
-R : 递归(recursive)更改,即连同子目彔下的所有文件、目录
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 vagrant root 5 Nov 17 19:04 aa
[root@centos7 vagrant]# chown root aa
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 root root 5 Nov 17 19:04 aa
[root@centos7 vagrant]# chown vagrant:vagrant aa
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 vagrant vagrant 5 Nov 17 19:04 aa

Tips:
chown 也能修改属组:chown .group_name filename

1
2
3
4
5
6
7
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 vagrant vagrant 5 Nov 17 19:04 aa
[root@centos7 vagrant]# chown .root aa
[root@centos7 vagrant]# ls -l
total 4
-rw-rw-r--. 1 vagrant root 5 Nov 17 19:04 aa

3. 更改文件权限

更改文件权限使用 chmod 命令,该命令有两种使用方式:以数字或者符号来进行权限的变更。

  • 数字方式更改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    命令格式: chmod [-R] xyz 文件或目录
    选项参数:
    -R: 递归(recursive)更改,即连同子目彔下的所有文件、目录
    xyz: 权限数字
    [root@centos7 vagrant]# ls -l
    total 4
    -rw-rw-r--. 1 vagrant root 5 Nov 17 19:04 aa
    [root@centos7 vagrant]# chmod 755 aa
    [root@centos7 vagrant]# ls -l
    total 4
    -rwxr-xr-x. 1 vagrant root 5 Nov 17 19:04 aa
  • 符号方式更改

    1
    2
    3
    4
    5
    6
    将文件权限设置为: -rwxr-xr-x
    [root@centos7 vagrant]# chmod u=rwx,g=rx,o=rx aa
    给所有人赋予文件可写权限
    [root@centos7 vagrant]# chmod a+w aa
    所在组和其他组人去除可写权限
    [root@centos7 vagrant]# chmod g-x,o-x aa

文件与目录的权限区别

Linux 下文件与目录的权限(r、w、x)有很大的不同,具体如下:

Linux FHS 标准

Linux FHS(Filesystem Hierarchy Standard)文一种规范,规范 Linux 各发行版的目录结构,什么目录下该存放什么类型的文件。大概规范如下(其中灰色部分目录不能在系统的不同磁盘设备,因为都是和系统启动有关的,必须在系统盘所在的磁盘):

基于 Hexo 的 GitHub Pages 配置 CloudFlare CDN

发表于 2018-11-04 | 分类于 Hexo

概述

由于 GitHub Pages 在国外,静态博客页面在国内访问速度可能会非常慢,我们可以用 CDN 来加速,对比了下 CloudFlare CDN 和 腾讯云 CDN,发现 CloudFlare 免费版没有流量限制(腾讯云 CDN 每月由流量限制),而且配置起来非常简单,所以在此选用 CloudFlare CDN 来加速页面访问。

准备工作

  • 个人域名
  • CloudFlare 账号
  • 基于 hexo 的 github_username.github.io 静态博客

配置流程

  1. 在 Hexo 博客 source 文件夹新建名为 CNAME 的文件,内容为个人域名;
  2. hexo g && hexo d 部署生产的静态页面到 GitHub;
  3. 进入 CloudFlare 控制台,点击添加站点,输入个人域名,根据向导进行操作;
  4. 在 CloudFlare DNS 配置页面配置两个 CNAME 均指向 github_username.github.io 地址:
    根域名(@) CNAME 到 github_username.github.io
    子域名(www) CNAME 到 github_username.github.io

    ⚠️注意:其实一般的域名提供商是不支持根域名 CNAME ,只有子域名才可以,但是 CloudFlare 通过 CNAME Flattening 技术支持这种配置。这么做的好处是我们不需要再一个个添加以 GitHub Pages 的 IP 为值的 A 记录了,同时还能提高后续的可维护性,后续即使 GitHub Pages 的 IP 发生了变化,也不影响,CloudFlare 会通过 CNAME Flattening 技术 自动解析出来。

  5. 将个人域名的 NS 记录修改为 CloudFlare 的 NS;
  6. 等 CloudFlare DNS 解析生效后,并且 CloudFlare 站点状态为 Active 即表示配置生效。

CloudFlare CDN HTTP 强制跳转 HTTPS

默认情况下配置完成后 HTTPS 是开启的,会在 24 小时内给你配的站点颁发 https 证书,并且证书是自动更新的。我们可以在 CloudFlare 控制台配置 HTTP 强制跳转 HTTPS:

基于 Kubernetes 的 Jenkins 主从通信异常解决

发表于 2018-10-14 | 分类于 DevOps

问题描述

基于 Kubernetes 部署 Jenkins 动态 slave 后,运行 Jenkins Job 会抛java.nio.channels.ClosedChannelException 异常完整的异常栈如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
FATAL: java.nio.channels.ClosedChannelException
java.nio.channels.ClosedChannelException
Also: hudson.remoting.Channel$CallSiteStackTrace: Remote call to JNLP4-connect connection from 10.244.8.1/10.244.8.1:55340
at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1741)
at hudson.remoting.Request.call(Request.java:202)
at hudson.remoting.Channel.call(Channel.java:954)
at hudson.FilePath.act(FilePath.java:1071)
at hudson.FilePath.act(FilePath.java:1060)
at hudson.FilePath.mkdirs(FilePath.java:1245)
at hudson.model.AbstractProject.checkout(AbstractProject.java:1202)
at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:574)
at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:86)
at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:499)
at hudson.model.Run.execute(Run.java:1819)
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:429)
Caused: hudson.remoting.RequestAbortedException
at hudson.remoting.Request.abort(Request.java:340)
at hudson.remoting.Channel.terminate(Channel.java:1038)
at org.jenkinsci.remoting.protocol.impl.ChannelApplicationLayer.onReadClosed(ChannelApplicationLayer.java:209)
at org.jenkinsci.remoting.protocol.ApplicationLayer.onRecvClosed(ApplicationLayer.java:222)
at org.jenkinsci.remoting.protocol.ProtocolStack$Ptr.onRecvClosed(ProtocolStack.java:832)
at org.jenkinsci.remoting.protocol.FilterLayer.onRecvClosed(FilterLayer.java:287)
at org.jenkinsci.remoting.protocol.impl.SSLEngineFilterLayer.onRecvClosed(SSLEngineFilterLayer.java:172)
at org.jenkinsci.remoting.protocol.ProtocolStack$Ptr.onRecvClosed(ProtocolStack.java:832)
at org.jenkinsci.remoting.protocol.NetworkLayer.onRecvClosed(NetworkLayer.java:154)
at org.jenkinsci.remoting.protocol.impl.NIONetworkLayer.ready(NIONetworkLayer.java:142)
at org.jenkinsci.remoting.protocol.IOHub$OnReady.run(IOHub.java:795)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE

原因及解决方法

原因

抛 java.nio.channels.ClosedChannelException 异常的原因是 Jenkins Slave Pod 在 Jenkins Job 运行时突然挂掉,然后 Master Pod 无法和 Slave Pod 进行通信。那么解决方法就是找到 Slave Pod 经常挂掉的原因,经排查是 Slave Pod 的资源限制不合理,配置的 CPU 和内存太小,导致 Pod 在运行是很容易超出资源限制,然后被 k8s Kill 掉。

解决方法

打开 Jenkins 设置 Slave Pod 模版的资源限制:
Jenkins->系统管理->系统设置->云->镜像->Kubernetes Pod Template->Container Template->高级,然后根据实际情况调整 CPU 和内存需求。

相关文档

https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes/issues/118
https://medium.com/@garunski/closedchannelexception-in-jenkins-with-kubernetes-plugin-a7788f1c62a9

基于 Kubernetes 的动态 Jenkins slave 部署

发表于 2018-10-14 | 分类于 DevOps

采用官方 Helm Chart 部署,服务对外暴露方式为 KongIngress.

官方 Jenkins Chart 仓库:https://github.com/helm/charts/tree/master/stable/jenkins

1. 创建 jenkins pv

pv 底层类型为 nfs
jenkins_pv.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kubectl create -f jenkins_pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
labels:
app: jenkins
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
nfs:
path: /data1/nfs/jenkins
server: 10.4.37.91

2. 创建 namespace

1
kubectl create ns jenkins

3. 采用 KongIngress 方式对外暴露服务

修改 values.yml 文件:
3.1. Master.ServiceType 改为 ClusterIP
3.2. HostName 取消注释,值设置为 Jenkins 访问域名:example.com
3.3. rbac 设置为 true;
3.4. Master.Ingress.Annotations 添加如下内容:

1
2
ingress.plugin.konghq.com: jenkins-kong-ingress
kubernetes.io/ingress.class: nginx

3.5. values.yaml Master 节点下添加 Kong Ingress 相关变量

1
2
3
4
5
6
7
8
9
10
KongIngress:
Name: jenkins-kong-ingress
Route:
StripPath: true
PreserveHost: true
Proxy:
ConnectTimeout: 10000
Retries: 5
ReadTimeout: 60000
WriteTimeout: 60000

4. 编辑 jenkins-master-ingress.yaml 添加 KongIngress 资源对象

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: {{ .Values.Master.KongIngress.Name }}
route:
strip_path: {{ .Values.Master.KongIngress.Route.StripPath }}
preserve_host: {{ .Values.Master.KongIngress.Route.PreserveHost }}
proxy:
connect_timeout: {{ .Values.Master.KongIngress.Proxy.ConnectTimeout }}
retries: {{ .Values.Master.KongIngress.Proxy.Retries }}
read_timeout: {{ .Values.Master.KongIngress.Proxy.ReadTimeout }}
write_timeout: {{ .Values.Master.KongIngress.Proxy.WriteTimeout }}

5. helm 打包

1
helm package jenkins

6. 重新生成 chart 索引

1
helm repo index .

7. helm 部署

1
helm install --name jenkins helm_local_repo/jenkins --namespace jenkins

8. 获取 Jenkins 初始密码

执行 kubectl get secret jenkins -n jenkins -o yaml 得到 jenkins-admin-password 的 base64 编码值,然后通过 base64 解码,得到密码:

1
echo 'base64d_str' | base64 -d

参考链接

https://mp.weixin.qq.com/s/OoTEtPNEORn_sFYG8rzaqA

容器化部署 Wordpress 的一个坑

发表于 2018-10-13 | 分类于 Wordpress

问题描述

非容器化 nginx + docker-compose 容器化 wordpress 后,媒体库上传图片报错:HTTP 错误

问题解决

其实这个问题的原因非常多,网上文章一大堆(https://www.duoluodeyu.com/2402.html ),但是本文中所遇到同样问题的原因却比较诡异:nginx client_max_body_size 参数必须要和 PHP 的 post_max_size 参数值一致。

1.修改 Wordpress 容器 PHP 参数

新建 uploads.ini 文件,将该文件挂载到容器:/usr/local/etc/php/conf.d/uploads.ini 文件
uploads.ini:

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

docker-compose 文件添加卷,将文件挂载到容器

1
2
3
volumes:
- ./wp_site:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini

2. 修改 nginx client_max_body_size 参数配置

这个是坑的地方,这个参数的值必须要和上一步 PHP post_max_size 参数的值一致,否则还是报同样的 HTTP 错误。之前没注意这个问题,按照网上各种配置调整,均不起作用,后来经过各种猜测测试,其实问题的根因就在这里:nginx client_max_body_size 参数必须要和 php post_max_size 参数的值一致。

附件(完整的 Wordpress docker-compose.yaml)

容器外挂文件 uploads.ini 是定义 PHP 的一些参数配置,比如最大文件上传大小、POST 请求体大小限制、内存大小限制等等,这个文件挂载是可选的,但是如果要自定义 PHP 参数可以这么做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- ./db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- ./wp_site:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
ports:
- "9001:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress

相关参考文档

https://www.duoluodeyu.com/2402.html
https://github.com/docker-library/wordpress/issues/10

kubeadm 安装的 k8s 集群 delete node 后重新添加回集群问题解决

发表于 2018-09-11 | 分类于 Kubernetes

问题描述

前不久公司同事误操作,直接 kubectl delete node node_ip 从集群中删除了一个 node,后来未知原因服务器给宕机了,重启服务器后 docker、kubelet 等服务器都自动重启了(用 systemd 管理),但是 node 一直是 Not Ready 状态,按理来说执行如下命令把节点添加回集群即可:

1
kubeadm join --token xxxxxxx master_ip:6443 --discovery-token-ca-cert-hash sha256:xxxxxxx

但是执行如上命令后报错如下(提示 10250 端口被占用):

1
2
3
4
5
6
7
8
[root@com10-81 ~]# kubeadm join --token xxxx 10.4.37.167:6443 --discovery-token-ca-cert-hash sha256:xxxxxx
[preflight] Running pre-flight checks.
[WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 17.12.1-ce. Max validated version: 17.03
[WARNING FileExisting-crictl]: crictl not found in system path
[preflight] Some fatal errors occurred:
[ERROR Port-10250]: Port 10250 is in use
[ERROR FileAvailable--etc-kubernetes-pki-ca.crt]: /etc/kubernetes/pki/ca.crt already exists
[ERROR FileAvailable--etc-kubernetes-kubelet.conf]: /etc/kubernetes/kubelet.conf already exists

解决方法

出现如上问题的主要原因是之前 kubeadm init 初始化过,所以一些配置文件及服务均已存在,重新执行 kubeadm join 时必然
会导致冲突,解决方法如下:
1.先执行 kubeadm reset,重新初始化节点配置:
kubeadm reset

1
2
3
4
5
6
7
[root@com10-81 ~]# kubeadm reset
[preflight] Running pre-flight checks.
[reset] Stopping the kubelet service.
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Removing kubernetes-managed containers.
[reset] No etcd manifest found in "/etc/kubernetes/manifests/etcd.yaml". Assuming external etcd.
[reset] Deleting contents of stateful directories: [/var/lib/kubelet /etc/cni/net.d /var/lib/dockershim /var/run/kubernetes]

2.然后执行 kubeadm join 添加节点到集群(如果 token 失效,到主节点执行:kubeadm token create 重新生成):
kubeadm join --token xxxxx master_ip:6443 --discovery-token-ca-cert-hash sha256:xxxx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@com10-81 ~]# kubeadm join --token xxxxx 10.4.37.167:6443 --discovery-token-ca-cert-hash sha256:xxxxxxx
[preflight] Running pre-flight checks.
[WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 17.12.1-ce. Max validated version: 17.03
[WARNING FileExisting-crictl]: crictl not found in system path
[preflight] Starting the kubelet service
[discovery] Trying to connect to API Server "10.4.37.167:6443"
[discovery] Created cluster-info discovery client, requesting info from "https://10.4.37.167:6443"
[discovery] Requesting info from "https://10.4.37.167:6443" again to validate TLS against the pinned public key
[discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "10.4.37.167:6443"
[discovery] Successfully established connection with API Server "10.4.37.167:6443"

This node has joined the cluster:
* Certificate signing request was sent to master and a response
was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the master to see this node join the cluster.

PS: k8s 集群 /etc/kubernetes/pki/ca.crt 证书(任何一节点都有该文件) sha256 编码获取(kubeadm join 添加集群节点时需要该证书的 sha256 编码串认证):
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

到此节点添加回集群了,但是直接执行 kubectl 相关的命令可能还会报如下错误:

1
2
3
[root@com10-81 ~]# kubectl get pod
The connection to the server localhost:8080 was refused - did you specify the right host or port?
You have mail in /var/spool/mail/root

问题原因及解决方法:
很明显 kubelet 加载的配置文件(/etc/kubernetes/kubelet.conf)有问题,可能服务器重启的缘故,启动后该文件丢失了,导致里面的连接 master 节点的配置及其他配置给丢了,因此会默认连接 localhost:8080 端口。解决方法很简单:拷贝其他任一节点的该文件,然后重启 kubelet (systemctl restart kublete)即可。

参考链接

https://stackoverflow.com/questions/41732265/how-to-use-kubeadm-to-create-kubernetest-cluster
https://blog.csdn.net/mailjoin/article/details/79686934

1…789…14

haohao

Talk is cheap. Show me the code.

134 日志
35 分类
43 标签
GitHub CSDN 开源中国 E-Mail
© 2017 — 2021 haohao
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.3
访问人数 总访问量 次