openshift 4.3 Istio的搭建(istio 系列一)
openshift 4.3 Istio的搭建
本文档覆盖了官方文档的Setup的所有章节
安装Istio
本次安装的Istio版本为1.6.0,环境为openshift 4.3
注:不建议使用openshift 1.11(即kubernetes 3.11)安装istio,可能会出现如下兼容性问题,参见此issue
must only have "properties", "required" or "description" at the root if the status subresource is enabled
openshift安装Istio
istio的安装涉及到两个文件:profile和manifest。前者用于控制组件的安装和组件的参数,profile配置文件所在的目录为install/kubernetes/operator/profiles
;后者为安装所使用的yaml文件,如service,deployment等,会用到profile提供的参数,manifest配置文件所在的目录为install/kubernetes/operator/charts
。因此可以通过两种方式安装istio,一种是通过profile进行安装,istio默认使用这种方式,如:
$ istioctl manifest apply --set profile=default
第二种是通过导出的manifest进行安装,如:
$ kubectl apply -f $HOME/generated-manifest.yaml
参考不同平台可以参考对应的SetUp。在openshift下面部署istio需要注意版本:
OpenShift 4.1 and above use
nftables
, which is incompatible with the Istioproxy-init
container. Make sure to use CNI instead.
首先创建istio-system
命名空间
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: istio-system
labels:
istio-injection: disabled
EOF
允许istio的serviceaccount使用UID为0的用户,使用的命名空间为istio-system
$ oc adm policy add-scc-to-group anyuid system:serviceaccounts:istio-system
istio默认会注入一个名为istio-init
的initContainer
,用于将pod的网络流量导向istio的sidecar proxy,该initContainer
需要用到完整的NET_ADMIN
和NET_RAW
capabilities来配置网络,由此可能造成安全问题,使用istio CNI插件可以替换istio-init
,且无需提升kubernetes RBAC权限,区别见下:
# with istio-cni
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsGroup: 1337
runAsNonRoot: true
runAsUser: 1337
# without istio-cni
capabilities:
add:
- NET_ADMIN
- NET_RAW
drop:
- ALL
privileged: false
readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0
由于openshift 4.1以上版本不再使用iptables,转而使用nftables,因此需要安装istio CNI插件,否则在sidecar注入时会出现如下istio iptables-restore: unable to initialize table 'nat'
的错误,即无法执行iptables-resotre
命令。
执行如下命令安装istio-cni并使用default类型的profile(见下)安装istio,具体参数含义参见官方文档。
cat <<'EOF' > cni-annotations.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
components:
cni:
enabled: true
namespace: kube-system
values:
cni:
excludeNamespaces:
- istio-system
- kube-system
chained: false
cniBinDir: /var/lib/cni/bin
cniConfDir: /etc/cni/multus/net.d
cniConfFileName: istio-cni.conf
sidecarInjectorWebhook:
injectedAnnotations:
"k8s.v1.cni.cncf.io/networks": istio-cni
EOF
$ istioctl manifest apply -f cni-annotations.yaml
安装结果如下:
# oc get pod
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-64f6f9d5c6-lwcp8 1/1 Running 0 41m
istiod-5bb879d86c-6ttml 1/1 Running 0 42m
prometheus-77b9c64b9c-r2pld 2/2 Running 0 41m
# oc get pod -nkube-system
NAME READY STATUS RESTARTS AGE
istio-cni-node-2xzl8 2/2 Running 0 41m
istio-cni-node-4nb6k 2/2 Running 0 41m
istio-cni-node-7j5ck 2/2 Running 0 41m
istio-cni-node-f9bnf 2/2 Running 0 41m
istio-cni-node-lp7v6 2/2 Running 0 41m
为ingress gateway暴露router:
$ oc -n istio-system expose svc/istio-ingressgateway --port=http2
至此istio的基本组件已经安装完毕,可以使用如下方式导出本次安装的profile
$ istioctl profile dump -f cni-annotations.yaml > generated-profile.yaml
使用如下命令导出安装istio的manefest
的内容
$ istioctl manifest generate -f cni-annotations.yaml > generated-manifest.yaml
校验安装结果
$ istioctl verify-install -f generated-manifest.yaml
istio会使用UID为1337的用户将sidecar注入到应用中,openshift默认不允许使用该用户,执行如下命令进行授权。target-namespace
为应用所在的命名空间。
$ oc adm policy add-scc-to-group privileged system:serviceaccounts:<target-namespace>
$ oc adm policy add-scc-to-group anyuid system:serviceaccounts:<target-namespace>
当清理应用pod后,需要删除添加的权限
$ oc adm policy remove-scc-from-group privileged system:serviceaccounts:<target-namespace>
$ oc adm policy remove-scc-from-group anyuid system:serviceaccounts:<target-namespace>
openshift下使用multus
管理CNI,它需要在应用的命名空间中部署NetworkAttachmentDefinition
来使用istio-cni插件,使用如下命令创建NetworkAttachmentDefinition
,target-namespace
替换为实际应用所在的命名空间。
$ cat <<EOF | oc -n <target-namespace> create -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: istio-cni
EOF
移除应用后,使用如下方式移除NetworkAttachmentDefinition
$ oc -n <target-namespace> delete network-attachment-definition istio-cni
更新istio配置
例如可以使用如下方式卸载已经安装的第三方工具Prometheus,注意必须带上文件cni-annotations.yaml
,否则会使用默认的profile重新配置istio,这样会导致删除istio-cni。如果组件的配置没有改变,则不会重新该组件的pod
$ istioctl manifest apply -f cni-annotations.yaml --set addonComponents.prometheus.enabled=false
openshif卸载istio
$ istioctl manifest generate -f cni-annotations.yaml | kubectl delete -f -
标准安装istio
istioctl
使用内置的charts生成manifest,这些charts位于目录install/kubernetes/operator/charts
。
# ll
total 36
drwxr-xr-x. 4 root root 4096 Apr 21 06:51 base
drwxr-xr-x. 4 root root 4096 Apr 21 06:51 gateways
drwxr-xr-x. 3 root root 4096 Apr 21 06:51 istio-cni
drwxr-xr-x. 5 root root 4096 Apr 21 06:51 istio-control
drwxr-xr-x. 3 root root 4096 Apr 21 06:51 istiocoredns
drwxr-xr-x. 3 root root 4096 Apr 21 06:51 istio-operator
drwxr-xr-x. 3 root root 4096 Apr 21 06:51 istio-policy
drwxr-xr-x. 8 root root 4096 Apr 21 06:51 istio-telemetry
drwxr-xr-x. 4 root root 4096 Apr 21 06:51 security
直接执行如下命令即可安装官方默认配置的istio。
$ istioctl manifest apply --set profile=default
istio默认支持如下6种profile
# istioctl profile list
Istio configuration profiles:
default
demo
empty
minimal
preview
remote
安装的组件的区别如下:
default | demo | minimal | remote | |
---|---|---|---|---|
Core components | ||||
istio-egressgateway |
X | |||
istio-ingressgateway |
X | X | ||
istio-pilot |
X | X | X | |
Addons | ||||
grafana |
X | |||
istio-tracing |
X | |||
kiali |
X | |||
prometheus |
X | X | X |
使用如下方式可以查看某个profile的配置信息,profile类型helm的values.yaml,用于给部署用的yaml提供配置参数。每个组件包含两部分内容:components下的组件以及组件的参数value
istio提倡使用IstioOperator API
进行定制化配置。
$ istioctl profile dump default
使用如下方式可以查看某个组件的配置:
$ istioctl profile dump --config-path components.pilot default
在安装前可以使用如下方式导出需要安装的所有yaml信息 ,包括CRD,deployment,service等
$ istioctl manifest generate --set profile=default --set hub=docker-local.com/openshift4 > $HOME/generated-manifest.yaml
在进行确认或修改之后可以使用apply
命令执行安装
$ kubectl apply -f $HOME/generated-manifest.yaml
使用如下方式校验安装结果
$ istioctl verify-install -f $HOME/generated-manifest.yaml
自定义配置:
使用
--set
选项进行设置,如下面用于设置profile中的global.controlPlaneSecurityEnabled
为true$ istioctl manifest apply --set values.global.controlPlaneSecurityEnabled=true
如果修改的参数比较多,可以使用yaml文件统一进行配置,实际使用
IstioOperator API
进行profile的修改$ istioctl manifest apply -f samples/operator/pilot-k8s.yaml
istio的核心组件定义在 IstioOperator
API的components下面:
Components |
---|
base |
pilot |
proxy |
sidecarInjector |
telemetry |
policy |
citadel |
nodeagent |
galley |
ingressGateways |
egressGateways |
cni |
第三方插件可以在IstioOperator API
的addonComponents下指定,如:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
addonComponents:
grafana:
enabled: true
每个组件都有一个KubernetesResourceSpec
,用于设置如下k8s属性
- Resources
- Readiness probes
- Replica count
- HorizontalPodAutoscaler
- PodDisruptionBudget
- Pod annotations
- Service annotations
- ImagePullPolicy
- Priority class name
- Node selector
- Affinity and anti-affinity
- Service
- Toleration
- Strategy
- Env
标准卸载istio
$ istioctl manifest generate <your original installation options> | kubectl delete -f -
更新Istio
金丝雀升级
revision
安装方式支持同时部署多个版本的istio,在升级时可以将流量逐步转移到新版本的istio上。每个修订revision
都是一个完整的istio控制面,具有独立的Deployment
, Service
等。
控制面升级
使用如下方式可以安装一个名为canary
的istio修订版本。下面方式默认会使用default
profile创建一套新的istio,如果新的istio和老的istio有组件重叠,则可能导致组件重建。从下面的AGE
字段可以看出,新的Prometheus
覆盖了老的Prometheus
,ingressgateway
也一样,因此最好的方式是指定文件,参见istio install
$ istioctl install --set revision=canary
命令执行成功后,可以看到存在2个控制面,每个控制面有各自的Deployment
,Service
等。
$ oc get pod
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-c9648ffbd-9pmwk 1/1 Running 0 113m
istiod-788cf6c878-cmn47 1/1 Running 0 139m
istiod-canary-79599d745b-ph7gj 1/1 Running 0 113m
prometheus-597596ffdd-v28hk 2/2 Running 0 113m
$ oc get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
istio-ingressgateway 1/1 1 1 138m
istiod 1/1 1 1 139m
istiod-canary 1/1 1 1 113m
prometheus 1/1 1 1 138m
sidecar注入配置也有2套
$ oc get mutatingwebhookconfigurations
NAME CREATED AT
istio-sidecar-injector 2020-05-22T02:42:57Z
istio-sidecar-injector-canary 2020-05-22T03:08:28Z
数据面升级
创建新的istio修订版本并不会影响现有的代理。为了升级代理,需要将代理的配置指向新的控制面。通过命名空间标签istio.io/rev
设置控制sidecar注入的控制面。
下面操作升级了test-ns
命名空间,移除标签istio-injection
,并增加标签istio.io/rev
,指向新的istio canary
。注意必须移除标签istio-injection
,否则istio会优先处理istio-injection
(原因是为了向后兼容)
$ kubectl label namespace test-ns istio-injection- istio.io/rev=canary
在升级命名空间后,需要重启pod来触发sidecar的注入,如下使用滚动升级
$ kubectl rollout restart deployment -n test-ns
通过如下方式可以查看使用canary
istio修订版的pod
$ kubectl get pods -n test-ns -l istio.io/rev=canary
为了验证test-ns命名空间中的新pod使用了istiod-canary服务,可以选择一个pod使用如下命令进行验证。从输出中可以看到其使用了istiod-canary
控制面
$ istioctl proxy-config endpoints ${pod_name}.test-ns --cluster xds-grpc -ojson | grep hostname
"hostname": "istiod-canary.istio-system.svc"
可以通过如下方式导出canary
修订版的配置信息
$ istioctl manifest generate --revision=canary >canary.yaml
替换升级
升级过程中可能会造成流量中断,为了最小化影响,需要确保istio中的各个组件(除Citadel)至少有两个副本正在运行,此外需要通过PodDistruptionBudgets保证至少有一个可用的pod
首先下载最新的istio
校验当前环境中支持的升级到的版本,如下命令会给出推荐的版本
$ istioctl manifest versions
确认需要升级的cluster是否正确
$ kubectl config view
通过如下命令执行升级,
<your-custom-configuration-file>
为当前版本的 IstioOperator API 配置 文件$ istioctl upgrade -f `<your-custom-configuration-file>`
istioctl upgrade不支持
--set
命令在更新完毕之后,需要手动重启带有istio sidecar的pod来更新istio数据面
$ kubectl rollout restart deployment
sidecar注入
为了使用Istio的特性,pods必须运行在istio sidecar proxy的网格中。下面介绍两种注入istio sidecar的方式:手动注入和自动注入。
手动注入通过直接修改,如deployment的配置信息,将proxy配置注入到配置中;当应用所在的命名空间启用自动注入时,会在pod创建时通过mutating webhook admission controller 注入proxy配置。
sidecar的(手动或自动)注入会用到istio-sidecar-injector
configmap。
手动注入
当前版本手动注入时有一个问题,就是使用istio CNI之后无法将annotation
k8s.v1.cni.cncf.io/networks
注入(或导出)到配置文件中,导致出现如下问题,参见该issue:in new validator: 10.80.2.222
Listening on 127.0.0.1:15001
Listening on 127.0.0.1:15006
Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused
Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused
Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused
Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused
Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused
手动注入需要满足一个条件,即在应用所在的命名空间中创建NetworkAttachmentDefinition
一种是直接使用
istio-sidecar-injector
的默认配置直接注入sidecar$ istioctl kube-inject -f samples/sleep/sleep.yaml | kubectl apply -f -
可以使用如下方式直接先导出注入sidecar的deployment,然后使用kubectl直接部署
$ istioctl kube-inject -f samples/sleep/sleep.yaml -o sleep-injected.yaml --injectConfigMapName istio-sidecar-injector
$ kubectl apply -f deployment-injected.yaml
另一种是先导出
istio-sidecar-injector
的默认配置,可以修改后再手动注入sidecar导出配置:
$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml
$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.values}' > inject-values.yaml
$ kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml
手动注入:
$ istioctl kube-inject \
--injectConfigFile inject-config.yaml \
--meshConfigFile mesh-config.yaml \
--valuesFile inject-values.yaml \
--filename samples/sleep/sleep.yaml \
| kubectl apply -f -
自动注入
自动注入时需要满足两个条件:
给应用所在的命名空间打上标签
istio-injection=enabled
$ kubectl label namespace <app-namespace> istio-injection=enabled
与手动注入相同,需要在应用所在的命名空间中创建NetworkAttachmentDefinition,然后在该命名空间下面正常创建(或删除并重建)pod即可自动注入sidecar。需要注意的是自动注入发生在pod层,并不体现在deployment上面,可以使用
describe pod
查看注入的sidecar。自动注入通过mutatingwebhookconfiguration定义了注入sidecar的规则,当前是istio-injection=enabled
namespaceSelector:
matchLabels:
istio-injection: enabled
可以通过如下命令修改注入的规则,修改后需要重启已经注入sidecar的pod,使规则生效
$ kubectl edit mutatingwebhookconfiguration istio-sidecar-injector
自动注入下,sidecar inject的webhook默认是打开的,如果要禁用该webhook,可以在上面cni-annotations.yaml文件中将
sidecarInjectorWebhook.enabled
置为false
,这样就不会自动注入。
sidecar的注入控制
有两种方式可以控制sidecar的注入:
第一种是修改pod template spec的
sidecar.istio.io/inject
annotation:当该annotation为true
时会进行自动注入sidecar,为false
则不会注入sidecar。默认为true
。这种情况需要修改应用的deployment。apiVersion: apps/v1
kind: Deployment
metadata:
name: ignored
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: ignored
image: tutum/curl
command: ["/bin/sleep","infinity"]
第二种是修改
istio-sidecar-injector
configmap,通过在neverInjectSelector
数组中罗列出标签,并禁止对匹配这些标签的pod注入sidecar(各个匹配项的关系为OR
)。如下内容中不会对具有标签openshift.io/build.name
或openshift.io/deployer-pod-for.name
的pod注入sidecar。这种方式不需要修改应用的deployment。类似地,可以使用alwaysInjectSelector
对某些具有特殊标签的pod注入sidecarapiVersion: v1
kind: ConfigMap
metadata:
name: istio-sidecar-injector
data:
config: |-
policy: enabled
neverInjectSelector:
- matchExpressions:
- {key: openshift.io/build.name, operator: Exists}
- matchExpressions:
- {key: openshift.io/deployer-pod-for.name, operator: Exists}
template: |-
initContainers:
...
更多istio CNI与sidecar注入和流量重定向相关的参数参见官方文档
卸载自动注入
使用如下方式可以卸载自动注入功能:
$ kubectl delete mutatingwebhookconfiguration istio-sidecar-injector
$ kubectl -n istio-system delete service istio-sidecar-injector
$ kubectl -n istio-system delete deployment istio-sidecar-injector
$ kubectl -n istio-system delete serviceaccount istio-sidecar-injector-service-account
$ kubectl delete clusterrole istio-sidecar-injector-istio-system
$ kubectl delete clusterrolebinding istio-sidecar-injector-admin-role-binding-istio-system
注意上面命令并不会卸载已经注入到pod的sidecar,需要通过滚动更新或直接删除pod来生效
或者使用如下方式对某个命名空间禁用自动注入(推荐):
$ kubectl label namespace <target-namespace> istio-injection-
Istio CNI的兼容
与init容器的兼容
当使用istio CNI的时候,kubelet会按照如下步骤启动注入sidecar的pod:
- 使用istio CNI插件进行配置,将流量导入到pod中的istio sidecar proxy容器
- 执行所有init容器,并成功运行结束
- 启动pod中的istio sidecar proxy和其他容器
由于init容器会在sidecar proxy容器之前运行,因此可能导致应用本身的init容器的通信中断。为了避免发生这种情况,可以通过如下配置避免重定向应用的init容器的流量:
- 设置
traffic.sidecar.istio.io/excludeOutboundIPRanges
annotation来禁用将流量重定向到与init容器通信的任何cidr。 - 设置
traffic.sidecar.istio.io/excludeOutboundPorts
annotation来禁止将流量重定向到init容器使用的出站端口
与其他CNI插件的兼容
istio CNI插件作为CNI插件链中的一环,当创建或删除一个pod时,会按照顺序启动插件链上的每个插件,istio CNI插件仅仅(通过pod的网络命名空间中的iptables)将应用的pod流量重定向到注入的istio proxy sidecar容器。
istio CNI插件不会干涉配置pod网络的基本CNI插件。
更多细节参见CNI specification reference
TIPs:
不同平台下使用istio CNI执行initContainer时可能会出现istio-validation无法启动的错误,这种情况下默认会导致kubelet删除并重建pod,为了定位问题,可以将
repair.deletePods
配置为false,这样就不会立即删除podapiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
components:
cni:
...
values:
cni:
repair:
enabled: true
deletePods: false
...
openshift 4.3 Istio的搭建(istio 系列一)的更多相关文章
- 搭建Istio基础环境
需求 搭建istio基础环境(基于1.5.1版本) 安装步骤 在安装 Istio 之前,需要一个运行着 Kubernetes 的环境,安装步骤可以参考前面的文章 下载istio,然后解压,然后将 is ...
- Istio 运维实战系列(2):让人头大的『无头服务』-上
本系列文章将介绍用户从 Spring Cloud,Dubbo 等传统微服务框架迁移到 Istio 服务网格时的一些经验,以及在使用 Istio 过程中可能遇到的一些常见问题的解决方法. 什么是『无头服 ...
- Istio 运维实战系列(3):让人头大的『无头服务』-下
本系列文章将介绍用户从 Spring Cloud,Dubbo 等传统微服务框架迁移到 Istio 服务网格时的一些经验,以及在使用 Istio 过程中可能遇到的一些常见问题的解决方法. 失败的 Eur ...
- Istio安全-认证(istio 系列七)
Istio安全-认证 目录 Istio安全-认证 认证策略 配置 自动mutual TLS 全局启用istio的mutual TLS STRIC模式 卸载 针对单个命名空间或负载启用mutual TL ...
- Istio(九):istio安全之授权
目录 一.模块概览 二.系统环境 三.istio授权 3.1 istio授权 3.2 来源 3.3 操作 3.4 条件 四.实战:授权(访问控制) 4.1 访问控制 4.2 清理 一.模块概览 在Ku ...
- istio环境搭建for macbook
首先需要搭建docker+k8s环境,如何搭建这里就不再赘述,可以自行搜索. 打开命令行,运行命令: curl -L https://git.io/getLatestIstio | ISTIO_VER ...
- Istio 运维实战系列(1):应用容器对 Envoy Sidecar 的启动依赖问题
本系列文章将介绍用户从 Spring Cloud,Dubbo 等传统微服务框架迁移到 Istio 服务网格时的一些经验,以及在使用 Istio 过程中可能遇到的一些常见问题的解决方法. 故障现象 该问 ...
- ABP框架搭建项目系列教程基础版完结篇
返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...
- [转]Ubuntu10下MySQL搭建Amoeba系列(文章索引)
一.前言(Introduction) 使用了Amoeba有一段时间了,发现官方博客:Amoeba使用指南有很多地方都是错误的,在我实战中给到一些错误的指示,所以我想写些在搭建的实战中给大家一点指引.欢 ...
随机推荐
- CVPR2020|3D-VID:基于LiDar Video信息的3D目标检测框架
作者:蒋天园 Date:2020-04-18 来源:3D-VID:基于LiDar Video信息的3D目标检测框架|CVPR2020 Brief paper地址:https://arxiv.org/p ...
- Python数据可视化---pygal模块
目录 pygal模块 安装pygal模块 pygal模块介绍 柱状图 单列柱状图 堆叠柱状图 横向柱状图 折线图 简单折线图 纵向折线图 堆叠折线图 饼状图 简单饼状图 多级饼状图 圆环图 半圆图 雷 ...
- Connections in Galaxy War ZOJ - 3261 (并查集)
点权并查集的反向离线操作 题目大意:有n个stars,每一个都一定的“颜值”.然后stars与stars之间可以相连,query c表示再与c相连的stars中,颜值比c高的,stars的标号,如果有 ...
- B2 - TV Subscriptions (Hard Version)
题目连接:https://codeforces.com/contest/1247/problem/B2 题解:双指针,,一个头,一个尾,头部进入,尾部退出,一开始先记录1到k,并记录每个数字出现的次数 ...
- nginx配置虚拟主机、反向代理和负载均衡
为了实现这个功能,需要修改nginx的配置文件,将nginx.conf清理一下,使结构更清晰. worker_processes ; events { worker_connections ; } h ...
- 关于C++线程池的实现的思考
今天突然对前些日子一直很疑惑的c++线程池有了新的想法.其实所谓的线程池无非就是两个技术点,一个,多线程,指工作线程和主线程分离,或者说数据接收和处理分两个线程,一般就是讲需要运行的函数放到子线程执行 ...
- 虚拟机体验NAS私人云全揭秘:序言——虚拟机体验NAS私人云缘由
"世界在新冠肺炎疫情后将永远改变",对于2020春天在全球蔓延的新冠肺炎疫情,美国前国务卿基辛格做了这样的评价.确实,也改变了我们.春节期间,本着少添乱的原则,响应国家号召,自我隔 ...
- [V&N2020 公开赛]TimeTravel 复现
大佬友链(狗头):https://www.cnblogs.com/p201821440039/ 参考博客: https://www.zhaoj.in/read-6407.html https://cj ...
- 2020-MRCTF
ez_bypass I put something in F12 for you include 'flag.php'; $flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx} ...
- [XML] XML格式【有道翻译】API 的数据转化输出
<?php header("content-type:text/html;charset=utf-8"); //echo "飞飞仔超级智障"; $cont ...