1. 部署单控制平面集群
· 阅读需 6 分钟
本文详细介绍如何部署Kubernetes单控制平面集群,包含环境准备、系统配置、组件安装等完整步骤。
本文详细介绍如何部署Kubernetes单控制平面集群,包含环境准备、系统配置、组件安装等完整步骤。
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
kind: PersistentVolume
apiVersion: v1
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual //该名称将用于将PersistentVolumeClaim请求绑定到此
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/storage/pv1"
# 编 写Yaml文件
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
# 编写Yaml文件
kind: Pod
apiVersion: v1
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
# NFS Server节点安装部署
apt-get -y install nfs-kernel-server
mkdir /storage && echo "/storage *(rw,sync,no_root_squash)" >> /etc/exports
systemctl restart nfs-kernel-server
# NFS Client节点安装部署
apt-get -y install nfs-common
下载系统插件
git clone https://github.com/kubernetes-incubator/external-storage.git
部署NFS-Client插件
# 修改yaml信息
cd /root/external-storage/nfs-client/deploy
vim deployment.yaml
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 172.31.53.155
- name: NFS_PATH
value: /storage
volumes:
- name: nfs-client-root
nfs:
server: 172.31.53.155
path: /storage
# 部署插件
kubectl apply -f rbac.yaml
kubectl apply -f deployment.yaml
kubectl apply -f class.yaml
测试一:创建pvc后自动创建pv并bound
# 编写Yaml文件
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-test
spec:
accessModes:
- ReadWriteMany
storageClassName: managed-nfs-storage
resources:
requests:
storage: 1Gi
测试二:创建Pod,自动创建pvc与pv
# 编写Yaml文件
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteMany" ]
storageClassName: "managed-nfs-storage"
resources:
requests:
storage: 1Gi
测试三:将nfs的storageclass设置为默认,创建Pod不指定storageclass,申请pvc的资源是否成功
# 设置managed-nfs-storage为默认
kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# 测试,编写yaml文件不指定storageclass
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 2 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: html
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
创建ConfigMap
# 编写Yaml文件
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
data:
username: damon
password: redhat
pod使用envFrom导入环境变量
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: test-configmap-env-pod
spec:
containers:
- name: test-container
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "sleep 1000000" ]
envFrom:
- configMapRef:
name: test-config
pod使用valueFrom导入 环境变量
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: test-configmap-command-env-pod
spec:
containers:
- name: test-container
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "echo \$(MYSQLUSER) \$(MYSQLPASSWD); sleep 1000000" ]
env:
- name: MYSQLUSER
valueFrom:
configMapKeyRef:
name: test-config
key: username
- name: MYSQLPASSWD
valueFrom:
configMapKeyRef:
name: test-config
key: password
命令行创建ConfigMap
echo 123 > index.html
kubectl create configmap web-config --from-file=index.html
pod使用volume挂载
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: test-configmap-volume-pod
spec:
volumes:
- name: config-volume
configMap:
name: web-config
containers:
- name: test-container
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html
Pod使用subPath挂在
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: test-configmap-volume-pod
spec:
volumes:
- name: config-volume
configMap:
name: web-config
containers:
- name: test-container
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
创建Secret
# 手动加密
echo -n 'admin' | base64
# 解密
echo 'YWRtaW4=' | base64 --decode
# 编写Yaml文件
apiVersion: v1
kind: Secret
metadata:
name: mysecret-env
type: Opaque
data:
username: YWRtaW4=
password: cmVkaGF0
pod使用envFrom导入环境变量
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: envfrom-secret
spec:
containers:
- name: envars-test-container
image: nginx
envFrom:
- secretRef:
name: test-secret
pod使用valueFrom导入环境变量
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-env-secret
spec:
containers:
- name: mycontainer
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "echo \$(SECRET_USERNAME) \$(SECRET_PASSWORD); sleep 1000000" ]
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret-env
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret-env
key: password
命令行创建Secret
echo 123 > index.html
kubectl create secret generic web-secret --from-file=index.html
pod使用volume挂载
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-secret
spec:
containers:
- name: pod-volume-secret
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: test-web
mountPath: "/usr/share/nginx/html"
volumes:
- name: test-web
secret:
secretName: web-secret
Pod使用subPath挂在
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-secret
spec:
containers:
- name: pod-volume-secret
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: test-web
mountPath: "/usr/share/nginx/html/index.html"
subPath: index.html
volumes:
- name: test-web
secret:
secretName: web-secret
部署Harbor
# 下载离线安装包
wget https://github.com/goharbor/harbor/releases/download/v1.10.0/harbor-offline-installer-v1.10.0.tgz
# 下载docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x v1.26.2-docker-compose-Linux-x86_64 && mv v1.26.2-docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
# 修改docker daemon.json ,添加安全私有镜像仓库
"insecure-registries": ["172.31.53.128"],
systemctl restart docker
# 安装harbor之前需要在harbor安装目录下修改harbor.yml文件,编辑hostname,注释https
./install.sh
# 登陆web创建用户,设定密码,创建项目
# docker login 私有仓库
docker login http://172.31.53.128/
# 上传image到damon用户的私有仓库中
docker tag
docker push
创建secret
kubectl create secret docker-registry harbor-secret --docker-server=172.27.141.61 --docker-username=damon --docker-password=Damon@123 --docker-email=damon@qq.com
创建Pod,调用imagePullSecrets
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: u-demo
image: 172.31.53.96:18080/test/nginx:latest
imagePullSecrets:
- name: harbor-secret
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
labels:
app: myapp
spec:
volumes:
- name: storage
emptyDir: {}
containers:
- name: myapp1
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
volumeMounts:
- name: storage
mountPath: /storage
command: ['sh', '-c', 'sleep 3600000']
- name: myapp2
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
volumeMounts:
- name: storage
mountPath: /storage
command: ['sh', '-c', 'sleep 10000000']
# 编写Yaml文件
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
volumes:
- name: storage
emptyDir: {}
containers:
- name: myapp-containers
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
volumeMounts:
- name: storage
mountPath: /storage
command: ['sh', '-c', 'if [ -f /storage/testfile ] ; then sleep 3600000 ; fi']
initContainers:
- name: init-containers
image: radial/busyboxplus
imagePullPolicy: IfNotPresent
volumeMounts:
- name: storage
mountPath: /storage
command: ['sh', '-c', 'touch /storage/testfile && sleep 10']
需求:打开 12306 登陆页面,自动输入用户名密码,点击验证码后,登录
网址 url:https://kyfw.12306.cn/otn/login/init
分析:主要是对验证码的处理
实现代码如下:
from time import sleep
from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
bro.maximize_window()
sleep(1)
bro.find_element_by_xpath('//div[@class="login-box"]//li[@class="login-hd-account"]').click()
sleep(2)
bro.save_screenshot('main.png')
bro.find_element_by_id('J-userName').send_keys('12345678')
bro.find_element_by_id('J-password').send_keys('abcdefgh')
# 将当次登录对应的验证码图片进行裁剪需分两步:1.保存完整页面截屏。2.截取验证码部分
# 截取当前登录页面对应的完整图片
img_tag = bro.find_element_by_id('J-loginImg')
# 获取img_tag表示的图片在当前页面中左上角坐标
location = img_tag.location
# 验证码标签的尺寸
size = img_tag.size
# 基于location和size制定出裁剪的范围,我的浏览器可能因为屏幕分辨率原因会有偏差,所以这里乘以1.5的系数,一般情况是不需要的
rectangle = (int(location['x'] * 1.5), int(location['y'] * 1.5), int(location['x'] * 1.5) + int(size['width'] * 1.5), int(location['y'] * 1.5 + int(size['height']* 1.5)))
# 根据rangle表示的裁剪范围进行图片的裁剪
# 基于图片进行裁剪:pip install PIL/Pillow
img_data = Image.open('main.png')
frame = img_data.crop(rectangle)
frame.save('code.png')
# img_tag.screenshot('code.png') # 上面获取验证码截图的一系列代码其实可以简化为这一句
# 识别验证码图片
# result是返回需要点击的所有坐标
result = get_img_code('code.png', 9004)
# 将字符串左边转换为列表,且数字转成整型。'61,71|118,137'==>[[61,71],[118,137]]
all_list = [[int(s.split(',')[0]) // 1.5, int(s.split(',')[1]) // 1.5] for s in result.split('|')] # [[61,71],[118,137]]
print(all_list)
# 点击所有需要选择的坐标
for xy in all_list:
ActionChains(bro).move_to_element_with_offset(img_tag, *xy).click().perform()
sleep(1)
# 点击确认按钮
bro.find_element_by_id('J-login').click()
sleep(3)
bro.quit()
验证码的功能封装成了函数:
#!/usr/bin/env python
# coding:utf-8
import requests
from hashlib import md5
class Chaojiying_Client(object):
def __init__(self, username, password, soft_id):
self.username = username
password = password.encode('utf8')
self.password = md5(password).hexdigest()
self.soft_id = soft_id
self.base_params = {
'user': self.username,
'pass2': self.password,
'softid': self.soft_id,
}
self.headers = {
'Connection': 'Keep-Alive',
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
}
def PostPic(self, im, codetype):
"""
im: 图片字节
codetype: 题目类型 参考 http://www.chaojiying.com/price.html
"""
params = {
'codetype': codetype,
}
params.update(self.base_params)
files = {'userfile': ('ccc.jpg', im)}
r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
return r.json()
def ReportError(self, im_id):
"""
im_id:报错题目的图片ID
"""
params = {
'id': im_id,
}
params.update(self.base_params)
r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
return r.json()
def get_img_code(img_path, img_type):
chaojiying = Chaojiying_Client('liushuo', 'liushuo', '904154') # 用户中心>>软件ID 找到或生成软件ID
im = open(img_path, 'rb').read()
return chaojiying.PostPic(im, img_type)['pic_str'] # 验证码类型 官方网站>>价格体系
余票检测是通过 ajax 发起的动态数据请求。直接访问页面是拿不到数据的。另外,需要携带 Cookie 才能获得正确的响应结果。
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
# 示例的热门城市,全部城市在底下
city = {
'北京北': 'VAP',
'北京东': 'BOP',
'北京': 'BJP',
'北京南': 'VNP',
'北京西': 'BXP',
'广州南': 'IZQ',
'重庆北': 'CUW',
'重庆': 'CQW',
'重庆南': 'CRW',
'广州东': 'GGQ',
'上海': 'SHH',
'上海南': 'SNH',
'上海虹桥': 'AOH'
}
url = 'https://kyfw.12306.cn/otn/leftTicket/query'
params = {
'leftTicketDTO.train_date': input('请输入出发日期【yyyy-mm-dd】:'),
'leftTicketDTO.from_station': city[input('请输入始发站城市:')],
'leftTicketDTO.to_station': city[input('请输入终点站城市:')],
'purpose_codes': 'ADULT',
}
session = requests.Session()
session.get(url='https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E5%8C%97%E4%BA%AC,BJP&ts=%E9%95%BF%E6%B2%99,CSQ&date=2020-03-26&flag=N,N,Y')
response = session.get(url, params=params, headers=headers)
print(response.json())
获取到的数据,经过处理,即可实现余票信息的监测。
附:12306 全部城市缩写:
city = {
'北京北': 'VAP',
'北京东': 'BOP',
'北京': 'BJP',
'北京南': 'VNP',
'北京西': 'BXP',
'广州南': 'IZQ',
'重庆北': 'CUW',
'重庆': 'CQW',
'重庆南': 'CRW',
'广州东': 'GGQ',
'上海': 'SHH',
'上海南': 'SNH',
'上海虹桥': 'AOH',
'上海西': 'SXH',
'天津北': 'TBP',
'天津': 'TJP',
'天津南': 'TIP',
'天津西': 'TXP',
'长春': 'CCT',
'长春南': 'CET',
'长春西': 'CRT',
'成都东': 'ICW',
'成都南': 'CNW',
'成都': 'CDW',
'长沙': 'CSQ',
'长沙南': 'CWQ',
'福州': 'FZS',
'福州南': 'FYS',
'贵阳': 'GIW',
'广州': 'GZQ',
'广州西': 'GXQ',
'哈尔滨': 'HBB',
'哈尔滨东': 'VBB',
'哈尔滨西': 'VAB',
'合肥': 'HFH',
'呼和浩特东': 'NDC',
'呼和浩特': 'HHC',
'海口东': 'HMQ',
'海口': 'VUQ',
'杭州东': 'HGH',
'杭州': 'HZH',
'杭州南': 'XHH',
'济南': 'JNK',
'济南东': 'JAK',
'济南西': 'JGK',
'昆明': 'KMM',
'昆明西': 'KXM',
'拉萨': 'LSO',
'兰州东': 'LVJ',
'兰州': 'LZJ',
'兰州西': 'LAJ',
'南昌': 'NCG',
'南京': 'NJH',
'南京南': 'NKH',
'南宁': 'NNZ',
'石家庄北': 'VVP',
'石家庄': 'SJP',
'沈阳': 'SYT',
'沈阳北': 'SBT',
'沈阳东': 'SDT',
'太原北': 'TBV',
'太原东': 'TDV',
'太原': 'TYV',
'武汉': 'WHN',
'王家营西': 'KNM',
'乌鲁木齐南': 'WMR',
'西安北': 'EAY',
'西安': 'XAY',
'西安南': 'CAY',
'西宁西': 'XXO',
'银川': 'YIJ',
'郑州': 'ZZF',
'阿尔山': 'ART',
'安康': 'AKY',
'阿克苏': 'ASR',
'阿里河': 'AHX',
'阿拉山口': 'AKR',
'安平': 'APT',
'安庆': 'AQH',
'安顺': 'ASW',
'鞍山': 'AST',
'安阳': 'AYF',
'北安': 'BAB',
'蚌埠': 'BBH',
'白城': 'BCT',
'北海': 'BHZ',
'白河': 'BEL',
'白涧': 'BAP',
'宝鸡': 'BJY',
'滨江': 'BJB',
'博克图': 'BKX',
'百色': 'BIZ',
'白山市': 'HJL',
'北台': 'BTT',
'包头东': 'BDC',
'包头': 'BTC',
'北屯市': 'BXR',
'本溪': 'BXT',
'白云鄂博': 'BEC',
'白银西': 'BXJ',
'亳州': 'BZH',
'赤壁': 'CBN',
'常德': 'VGQ',
'承德': 'CDP',
'长甸': 'CDT',
'赤峰': 'CFD',
'茶陵': 'CDG',
'苍南': 'CEH',
'昌平': 'CPP',
'崇仁': 'CRG',
'昌图': 'CTT',
'长汀镇': 'CDB',
'曹县': 'CXK',
'楚雄': 'COM',
'陈相屯': 'CXT',
'长治北': 'CBF',
'长征': 'CZJ',
'池州': 'IYH',
'常州': 'CZH',
'郴州': 'CZQ',
'长治': 'CZF',
'沧州': 'COP',
'崇左': 'CZZ',
'大安北': 'RNT',
'大成': 'DCT',
'丹东': 'DUT',
'东方红': 'DFB',
'东莞东': 'DMQ',
'大虎山': 'DHD',
'敦煌': 'DHJ',
'敦化': 'DHL',
'德惠': 'DHT',
'东京城': 'DJB',
'大涧': 'DFP',
'都江堰': 'DDW',
'大连北': 'DFT',
'大理': 'DKM',
'大连': 'DLT',
'定南': 'DNG',
'大庆': 'DZX',
'东胜': 'DOC',
'大石桥': 'DQT',
'大同': 'DTV',
'东营': 'DPK',
'大杨树': 'DUX',
'都匀': 'RYW',
'邓州': 'DOF',
'达州': 'RXW',
'德州': 'DZP',
'额济纳': 'EJC',
'二连': 'RLC',
'恩施': 'ESN',
'福鼎': 'FES',
'风陵渡': 'FLV',
'涪陵': 'FLW',
'富拉尔基': 'FRX',
'抚顺北': 'FET',
'佛山': 'FSQ',
'阜新': 'FXD',
'阜阳': 'FYH',
'格尔木': 'GRO',
'广汉': 'GHW',
'古交': 'GJV',
'桂林北': 'GBZ',
'古莲': 'GRX',
'桂林': 'GLZ',
'固始': 'GXN',
'广水': 'GSN',
'干塘': 'GNJ',
'广元': 'GYW',
'广州北': 'GBQ',
'赣州': 'GZG',
'公主岭': 'GLT',
'公主岭南': 'GBT',
'淮安': 'AUH',
'鹤北': 'HMB',
'淮北': 'HRH',
'淮滨': 'HVN',
'河边': 'HBV',
'潢川': 'KCN',
'韩城': 'HCY',
'邯郸': 'HDP',
'横道河子': 'HDB',
'鹤岗': 'HGB',
'皇姑屯': 'HTT',
'红果': 'HEM',
'黑河': 'HJB',
'怀化': 'HHQ',
'汉口': 'HKN',
'葫芦岛': 'HLD',
'海拉尔': 'HRX',
'霍林郭勒': 'HWD',
'海伦': 'HLB',
'侯马': 'HMV',
'哈密': 'HMR',
'淮南': 'HAH',
'桦南': 'HNB',
'海宁西': 'EUH',
'鹤庆': 'HQM',
'怀柔北': 'HBP',
'怀柔': 'HRP',
'黄石东': 'OSN',
'华山': 'HSY',
'黄石': 'HSN',
'黄山': 'HKH',
'衡水': 'HSP',
'衡阳': 'HYQ',
'菏泽': 'HIK',
'贺州': 'HXZ',
'汉中': 'HOY',
'惠州': 'HCQ',
'吉安': 'VAG',
'集安': 'JAL',
'江边村': 'JBG',
'晋城': 'JCF',
'金城江': 'JJZ',
'景德镇': 'JCG',
'嘉峰': 'JFF',
'加格达奇': 'JGX',
'井冈山': 'JGG',
'蛟河': 'JHL',
'金华南': 'RNH',
'金华西': 'JBH',
'九江': 'JJG',
'吉林': 'JLL',
'荆门': 'JMN',
'佳木斯': 'JMB',
'济宁': 'JIK',
'集宁南': 'JAC',
'酒泉': 'JQJ',
'江山': 'JUH',
'吉首': 'JIQ',
'九台': 'JTL',
'镜铁山': 'JVJ',
'鸡西': 'JXB',
'蓟县': 'JKP',
'绩溪县': 'JRH',
'嘉峪关': 'JGJ',
'江油': 'JFW',
'锦州': 'JZD',
'金州': 'JZT',
'库尔勒': 'KLR',
'开封': 'KFF',
'岢岚': 'KLV',
'凯里': 'KLW',
'喀什': 'KSR',
'昆山南': 'KNH',
'奎屯': 'KTR',
'开原': 'KYT',
'六安': 'UAH',
'灵宝': 'LBF',
'芦潮港': 'UCH',
'隆昌': 'LCW',
'陆川': 'LKZ',
'利川': 'LCN',
'临川': 'LCG',
'潞城': 'UTP',
'鹿道': 'LDL',
'娄底': 'LDQ',
'临汾': 'LFV',
'良各庄': 'LGP',
'临河': 'LHC',
'漯河': 'LON',
'绿化': 'LWJ',
'隆化': 'UHP',
'丽江': 'LHM',
'临江': 'LQL',
'龙井': 'LJL',
'吕梁': 'LHV',
'醴陵': 'LLG',
'柳林南': 'LKV',
'滦平': 'UPP',
'六盘水': 'UMW',
'灵丘': 'LVV',
'旅顺': 'LST',
'陇西': 'LXJ',
'澧县': 'LEQ',
'兰溪': 'LWH',
'临西': 'UEP',
'龙岩': 'LYS',
'耒阳': 'LYQ',
'洛阳': 'LYF',
'洛阳东': 'LDF',
'连云港东': 'UKH',
'临沂': 'LVK',
'洛阳龙门': 'LLF',
'柳园': 'DHR',
'凌源': 'LYD',
'辽源': 'LYL',
'立志': 'LZX',
'柳州': 'LZZ',
'辽中': 'LZD',
'麻城': 'MCN',
'免渡河': 'MDX',
'牡丹江': 'MDB',
'莫尔道嘎': 'MRX',
'满归': 'MHX',
'明光': 'MGH',
'漠河': 'MVX',
'茂名东': 'MDQ',
'茂名': 'MMZ',
'密山': 'MSB',
'马三家': 'MJT',
'麻尾': 'VAW',
'绵阳': 'MYW',
'梅州': 'MOQ',
'满洲里': 'MLX',
'宁波东': 'NVH',
'宁波': 'NGH',
'南岔': 'NCB',
'南充': 'NCW',
'南丹': 'NDZ',
'南大庙': 'NMP',
'南芬': 'NFT',
'讷河': 'NHX',
'嫩江': 'NGX',
'内江': 'NJW',
'南平': 'NPS',
'南通': 'NUH',
'南阳': 'NFF',
'碾子山': 'NZX',
'平顶山': 'PEN',
'盘锦': 'PVD',
'平凉': 'PIJ',
'平凉南': 'POJ',
'平泉': 'PQP',
'坪石': 'PSQ',
'萍乡': 'PXG',
'凭祥': 'PXZ',
'郫县西': 'PCW',
'攀枝花': 'PRW',
'蕲春': 'QRN',
'青城山': 'QSW',
'青岛': 'QDK',
'清河城': 'QYP',
'黔江': 'QNW',
'曲靖': 'QJM',
'前进镇': 'QEB',
'齐齐哈尔': 'QHX',
'七台河': 'QTB',
'沁县': 'QVV',
'泉州东': 'QRS',
'泉州': 'QYS',
'衢州': 'QEH',
'融安': 'RAZ',
'汝箕沟': 'RQJ',
'瑞金': 'RJG',
'日照': 'RZK',
'双城堡': 'SCB',
'绥芬河': 'SFB',
'韶关东': 'SGQ',
'山海关': 'SHD',
'绥化': 'SHB',
'三间房': 'SFX',
'苏家屯': 'SXT',
'舒兰': 'SLL',
'三明': 'SMS',
'神木': 'OMY',
'三门峡': 'SMF',
'商南': 'ONY',
'遂宁': 'NIW',
'四平': 'SPT',
'商丘': 'SQF',
'上饶': 'SRG',
'韶山': 'SSQ',
'宿松': 'OAH',
'汕头': 'OTQ',
'邵武': 'SWS',
'涉县': 'OEP',
'三亚': 'SEQ',
'邵阳': 'SYQ',
'十堰': 'SNN',
'双鸭山': 'SSB',
'松原': 'VYT',
'深圳': 'SZQ',
'苏州': 'SZH',
'随州': 'SZN',
'宿州': 'OXH',
'朔州': 'SUV',
'深圳西': 'OSQ',
'塘豹': 'TBQ',
'塔尔气': 'TVX',
'潼关': 'TGY',
'塘沽': 'TGP',
'塔河': 'TXX',
'通化': 'THL',
'泰来': 'TLX',
'吐鲁番': 'TFR',
'通辽': 'TLD',
'铁岭': 'TLT',
'陶赖昭': 'TPT',
'图们': 'TML',
'铜仁': 'RDQ',
'唐山北': 'FUP',
'田师府': 'TFT',
'泰山': 'TAK',
'唐山': 'TSP',
'天水': 'TSJ',
'通远堡': 'TYT',
'太阳升': 'TQT',
'泰州': 'UTH',
'桐梓': 'TZW',
'通州西': 'TAP',
'五常': 'WCB',
'武昌': 'WCN',
'瓦房店': 'WDT',
'威海': 'WKK',
'芜湖': 'WHH',
'乌海西': 'WXC',
'吴家屯': 'WJT',
'武隆': 'WLW',
'乌兰浩特': 'WWT',
'渭南': 'WNY',
'威舍': 'WSM',
'歪头山': 'WIT',
'武威': 'WUJ',
'武威南': 'WWJ',
'无锡': 'WXH',
'乌西': 'WXR',
'