使用containerlab搭建cilium BGP环境解析
使用 Containerlab + Kind 快速部署 Cilium BGP 环境一文中使用Containerlab和Cilium实现了模拟环境下的Cilium BGP网络。它使用Containerlab模拟外部BGP路由器,使用Cilium BGP的
CiliumBGPPeeringPolicy
与外部路由器建立BGP关系。
containerLab的简单用法
containerLab支持很多节点和类型设置,相对比较复杂。实际使用中只需要掌握基本的组网即可
安装
网络布线
如果没有指定网络模式,则使用默认的bridge
。
container mode用于于其他容器共享网络命名空间
my-node:
kind: linux
sidecar-node:
kind: linux
network-mode: container:my-node #my-node为另一个容器
startup-delay: 10
name: srl02
topology:
kinds:
srl:
type: ixrd3 #srlinux支持的类型,用于模拟硬件
image: ghcr.io/nokia/srlinux #使用的容器镜像
nodes:
srl1: #节点1信息
kind: srl
srl2: #节点2信息
kind: srl
links:
- endpoints: ["srl1:e1-1", "srl2:e1-1"] #节点1和节点2的点对点连接信息
上述配置包含两个SR Linux节点srl1
和srl2
,它们通过以下两种方式互通:
- 都通过接口
mgmt
连接到了默认的容器网桥clab
(使用docker network ls
查看) - 通过接口
e1-1
进行了点到点连接。点到点连接是通过一对veth实现的。enpoints
描述了一对veth
,因此数组中有且只能有2个元素
执行如下命令部署网络:
# containerlab deploy -t srl02.clab.yml
生成的容器网络如下:
IPv4: subnet 172.20.20.0/24, gateway 172.20.20.1
IPv6: subnet 2001:172:20:20::/64, gateway 2001:172:20:20::1
配置管理网络
用户自定义网络
一般情况下使用默认默认配置即可,但如果默认的网络于现有网络出现冲突,则可以手动指定网段:
mgmt:
network: custom_mgmt # management network name
ipv4_subnet: 172.100.100.0/24 # ipv4 range
ipv6_subnet: 2001:172:100:100::/80 # ipv6 range (optional)
topology:
# the rest of the file is omitted for brevity
可以手动给节点指定特定IP,相当于静态IP,但此时需要给所有容器手动指定IP:
mgmt:
network: fixedips #指定容器网络名称(默认的容器网络名称为clab)
bridge: mybridge #指定网桥名称(默认的网桥名称为 br-<network-id>)
ipv4_subnet: 172.100.100.0/24
ipv6_subnet: 2001:172:100:100::/80
topology:
nodes:
n1:
kind: srl
mgmt_ipv4: 172.100.100.11 # set ipv4 address on management network
mgmt_ipv6: 2001:172:100:100::11 # set ipv6 address on management network
查看拓扑图
执行如下命令可以查看拓扑图:
# containerlab graph -t srl02.clab.yml
重新配置网络
如果修改了配置文件可以使用如下命令重新配置网络:
# containerlab deploy -t srl02.clab.yml --reconfigure
例子
官方给出了很多配置组网的例子。组网中一般涉及两种实例:VM和路由器,后者可以使用FRR组件模拟。
原文配置解析
Kubernetes配置
下面使用kind创建了一个kubernetes集群,其中包含一个控制节点和3个工作节点,并分配和节点IP和pod网段。
注意配置中禁用了默认的CNI,因此使用kind部署之后,节点之间由于无法通信而不会Ready
。
# cluster.yaml
kind: Cluster
name: clab-bgp-cplane-demo
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true # 禁用默认 CNI
podSubnet: "10.1.0.0/16" # Pod CIDR
nodes:
- role: control-plane # 节点角色
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.1.2 # 节点 IP
node-labels: "rack=rack0" # 节点标签
- role: worker
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.2.2
node-labels: "rack=rack0"
- role: worker
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.3.2
node-labels: "rack=rack1"
- role: worker
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.0.4.2
node-labels: "rack=rack1"
Cilium安装
原文中的验证步骤可能不大合理,应该是先启动kubernetes和cilium,然后再启动containerlab,否则kubernetes因为没有CNI,也无法生成路由。
# values.yaml
tunnel: disabled
ipam:
mode: kubernetes
ipv4NativeRoutingCIDR: 10.0.0.0/8
# 开启 BGP 功能支持,等同于命令行执行 --enable-bgp-control-plane=true
bgpControlPlane:
enabled: true
k8s:
requireIPv4PodCIDR: true
helm repo add cilium https://helm.cilium.io/
helm install -n kube-system cilium cilium/cilium --version v1.12.1 -f values.yaml
完成上述配置之后kubernetes集群就启动了,节点也Ready
了,下面进行BGP的配置。
BPG配置
原文中使用frrouting/frr:v8.2.2
镜像来实现BGP路由发现。更多参数配置可以参见官方手册。文中的containerlab的topo文件如下:
# topo.yaml
name: bgp-cplane-demo
topology:
kinds:
linux:
cmd: bash
nodes:
router0:
kind: linux
image: frrouting/frr:v8.2.2
labels:
app: frr
exec:
- iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
- ip addr add 10.0.0.0/32 dev lo
- ip route add blackhole 10.0.0.0/8
- touch /etc/frr/vtysh.conf
- sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
- usr/lib/frr/frrinit.sh start
- >-
vtysh -c 'conf t'
-c 'router bgp 65000'
-c ' bgp router-id 10.0.0.0'
-c ' no bgp ebgp-requires-policy'
-c ' neighbor ROUTERS peer-group'
-c ' neighbor ROUTERS remote-as external'
-c ' neighbor ROUTERS default-originate'
-c ' neighbor net0 interface peer-group ROUTERS'
-c ' neighbor net1 interface peer-group ROUTERS'
-c ' address-family ipv4 unicast'
-c ' redistribute connected'
-c ' exit-address-family'
-c '!'
tor0:
kind: linux
image: frrouting/frr:v8.2.2
labels:
app: frr
exec:
- ip link del eth0
- ip addr add 10.0.0.1/32 dev lo
- ip addr add 10.0.1.1/24 dev net1
- ip addr add 10.0.2.1/24 dev net2
- touch /etc/frr/vtysh.conf
- sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
- /usr/lib/frr/frrinit.sh start
- >-
vtysh -c 'conf t'
-c 'frr defaults datacenter'
-c 'router bgp 65010'
-c ' bgp router-id 10.0.0.1'
-c ' no bgp ebgp-requires-policy'
-c ' neighbor ROUTERS peer-group'
-c ' neighbor ROUTERS remote-as external'
-c ' neighbor SERVERS peer-group'
-c ' neighbor SERVERS remote-as internal'
-c ' neighbor net0 interface peer-group ROUTERS'
-c ' neighbor 10.0.1.2 peer-group SERVERS'
-c ' neighbor 10.0.2.2 peer-group SERVERS'
-c ' address-family ipv4 unicast'
-c ' redistribute connected'
-c ' exit-address-family'
-c '!'
tor1:
kind: linux
image: frrouting/frr:v8.2.2
labels:
app: frr
exec:
- ip link del eth0
- ip addr add 10.0.0.2/32 dev lo
- ip addr add 10.0.3.1/24 dev net1
- ip addr add 10.0.4.1/24 dev net2
- touch /etc/frr/vtysh.conf
- sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
- /usr/lib/frr/frrinit.sh start
- >-
vtysh -c 'conf t'
-c 'frr defaults datacenter'
-c 'router bgp 65011'
-c ' bgp router-id 10.0.0.2'
-c ' no bgp ebgp-requires-policy'
-c ' neighbor ROUTERS peer-group'
-c ' neighbor ROUTERS remote-as external'
-c ' neighbor SERVERS peer-group'
-c ' neighbor SERVERS remote-as internal'
-c ' neighbor net0 interface peer-group ROUTERS'
-c ' neighbor 10.0.3.2 peer-group SERVERS'
-c ' neighbor 10.0.4.2 peer-group SERVERS'
-c ' address-family ipv4 unicast'
-c ' redistribute connected'
-c ' exit-address-family'
-c '!'
server0:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:control-plane
exec:
- ip addr add 10.0.1.2/24 dev net0
- ip route replace default via 10.0.1.1
server1:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:worker
exec:
- ip addr add 10.0.2.2/24 dev net0
- ip route replace default via 10.0.2.1
server2:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:worker2
exec:
- ip addr add 10.0.3.2/24 dev net0
- ip route replace default via 10.0.3.1
server3:
kind: linux
image: nicolaka/netshoot:latest
network-mode: container:worker3
exec:
- ip addr add 10.0.4.2/24 dev net0
- ip route replace default via 10.0.4.1
links:
- endpoints: ["router0:net0", "tor0:net0"]
- endpoints: ["router0:net1", "tor1:net0"]
- endpoints: ["tor0:net1", "server0:net0"]
- endpoints: ["tor0:net2", "server1:net0"]
- endpoints: ["tor1:net1", "server2:net0"]
- endpoints: ["tor1:net2", "server3:net0"]
该topo中涉及3个路由器:router0、tor0、tor1。以及4个普通节点:server0、server1、server2、server3,这4个节点与kubernetes的节点(容器部署)共享相同的网络命名空间。
下面看下各个节点是如何
router0的配置
下面是router0的bgp配置,其地址为10.0.0.0
:
vtysh -c 'conf t'
-c 'router bgp 65000'
-c ' bgp router-id 10.0.0.0'
-c ' no bgp ebgp-requires-policy'
-c ' neighbor ROUTERS peer-group'
-c ' neighbor ROUTERS remote-as external'
-c ' neighbor ROUTERS default-originate'
-c ' neighbor net0 interface peer-group ROUTERS'
-c ' neighbor net1 interface peer-group ROUTERS'
-c ' address-family ipv4 unicast'
-c ' redistribute connected'
-c ' exit-address-family'
-c '!'
vtysh -c 'conf t'
:通过vtysh命令进入交互界面,然后进入配置界面'router bgp 65000'
:配置BGP路由器的ASN(AS number),BGP协议使用该数值来判断BGP连接的是内部还是外部。输入该命令之后就可以执行BGP命令。'bgp router-id 10.0.0.0'
:指定router-ID,用于标识路由器。此处使用IP作为路由标识'no bgp ebgp-requires-policy'
:不需要使用策略来交换路由信息。'neighbor ROUTERS peer-group'
:定义一个peer group,用于交换路由,一个peer group中可以有多个peer'neighbor ROUTERS remote-as external'
:router0的邻居为tor0和tor1,它们都使用不同的ASN,因此将tor0和tor1作为EBGP,EBGP会在传播路由的时候修改下一跳。参考:EBGP vs IBGP'neighbor ROUTERS default-originate'
:将默认路由0.0.0.0
发送给邻居。'neighbor net0 interface peer-group ROUTERS'
/'neighbor net0 interface peer-group ROUTERS'
:将对端绑定到一个peer group。这里的对端可以是接口名称或是邻居标签'address-family ipv4 unicast'
:进入IPv4单播配置界面'redistribute connected'
:将路由从其他协议重新分发到BGP,此处为系统的直连路由。'exit-address-family'
:退出地址族配置。
上述配置中,为router0
添加了邻居net0
(连接到tor0
)和net1
(连接到tor1
),并在BGP中引入了ipv4的直连路由。此时组网如下:
tor0配置
vtysh -c 'conf t'
-c 'frr defaults datacenter'
-c 'router bgp 65010'
-c ' bgp router-id 10.0.0.1'
-c ' no bgp ebgp-requires-policy'
-c ' neighbor ROUTERS peer-group'
-c ' neighbor ROUTERS remote-as external'
-c ' neighbor SERVERS peer-group'
-c ' neighbor SERVERS remote-as internal'
-c ' neighbor net0 interface peer-group ROUTERS'
-c ' neighbor 10.0.1.2 peer-group SERVERS'
-c ' neighbor 10.0.2.2 peer-group SERVERS'
-c ' address-family ipv4 unicast'
-c ' redistribute connected'
-c ' exit-address-family'
此处配置与router0
大体相同,它同样创建了一个EBGP类型的peer group ROUTERS
,将net0(连接到router0
)作为邻居。同时它创建一个IBGP类型的peer group SERVERS
,并将server0
和server1
的地址作为邻居。
tor1
与tor0
的配置类似,此处不再详述。最后的组网如下。其中tor0
、tor1
和router0
建立了邻居关系。另外需要注意的是,containerlab网络中的server0~3分别与kubernetes的对应节点共享网络命名空间。
在router0
上查看bgp邻居关系,可以看到router0
与tor0
(net0)、tor1
(net1)建立了邻居关系:
router0# show bgp summary
IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.0, local AS number 65000 vrf-id 0
BGP table version 8
RIB entries 15, using 2760 bytes of memory
Peers 2, using 1433 KiB of memory
Peer groups 1, using 64 bytes of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
net0 4 65010 15 15 0 0 0 00:00:20 3 9 N/A
net1 4 65011 15 15 0 0 0 00:00:20 3 9 N/A
Total number of neighbors 2
在tor0
上查看邻居关系,可以看到,tor0
并没有与kubernetes节点建立邻居关系,因此无法获取kubernetes pod节点的路由信息。
tor0# show bgp summary
IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.1, local AS number 65010 vrf-id 0
BGP table version 9
RIB entries 15, using 2760 bytes of memory
Peers 3, using 2149 KiB of memory
Peer groups 2, using 128 bytes of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
router0(net0) 4 65000 19 20 0 0 0 00:00:33 6 9 N/A
10.0.1.2 4 0 0 0 0 0 0 never Active 0 N/A
10.0.2.2 4 0 0 0 0 0 0 never Active 0 N/
Total number of neighbors 3
在router0
上查看bgp发现的路由,可以看到不存在pod网段(10.1.0.0/16
)的路由
router0# show bgp ipv4 all
For address family: IPv4 Unicast
BGP table version is 8, local router ID is 10.0.0.0, vrf id 0
Default local pref 100, local AS 65000
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/32 0.0.0.0 0 32768 ?
*> 10.0.0.1/32 net0 0 0 65010 ?
*> 10.0.0.2/32 net1 0 0 65011 ?
*> 10.0.1.0/24 net0 0 0 65010 ?
*> 10.0.2.0/24 net0 0 0 65010 ?
*> 10.0.3.0/24 net1 0 0 65011 ?
*> 10.0.4.0/24 net1 0 0 65011 ?
*> 172.20.20.0/24 0.0.0.0 0 32768 ?
Displayed 8 routes and 8 total paths
与kubernetes建立BGP
上述配置中,tor0
和tor1
已经将kubernetes的节点作为IBGP,下面进行kubernetes侧BPG配置。cilium的CiliumBGPPeeringPolicy CRD中可以配置BGP peer信息。
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: rack0
spec:
nodeSelector:
matchLabels:
rack: rack0
virtualRouters:
- localASN: 65010
exportPodCIDR: true # 自动宣告 Pod CIDR
neighbors:
- peerAddress: "10.0.0.1/32" # tor0 的 IP 地址
peerASN: 65010
---
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: rack1
spec:
nodeSelector:
matchLabels:
rack: rack1
virtualRouters:
- localASN: 65011
exportPodCIDR: true
neighbors:
- peerAddress: "10.0.0.2/32" # tor1 的 IP 地址
peerASN: 65011
上述配置中将标签为rack=rack0
的节点(即control-plane
和worker
)与tor0
建立邻居,将标签为rack=rack1
的节点(即worker
和worker2
)与tor1
建立邻居:
# k get node -l rack=rack0
NAME STATUS ROLES AGE VERSION
clab-bgp-cplane-demo-control-plane Ready control-plane 2d11h v1.24.0
clab-bgp-cplane-demo-worker Ready <none> 2d11h v1.24.0
# k get node -l rack=rack1
NAME STATUS ROLES AGE VERSION
clab-bgp-cplane-demo-worker2 Ready <none> 2d11h v1.24.0
clab-bgp-cplane-demo-worker3 Ready <none> 2d11h v1.24.0
CiliumBGPPeeringPolicy
各个字段的说明如下
nodeSelector: Nodes which are selected by this label selector will apply the given policy
virtualRouters: One or more peering configurations outlined below. Each peering configuration can be thought of as a BGP router instance.
virtualRouters[*].localASN: The local ASN for this peering configuration
virtualRouters[*].exportPodCIDR: Whether to export the private pod CIDR block to the listed neighbors
virtualRouters[*].neighbors: A list of neighbors to peer with
neighbors[*].peerAddress: The address of the peer neighbor
neighbors[*].peerASN: The ASN of the peer
完成上述配置之后,containerlab的router0
、tor0
、tor1
就学习到了kubernetes的路由信息:
查看tor0的bgp邻居,可以看到它与clab-bgp-cplane-demo-control-plane(10.0.1.2)
和clab-bgp-cplane-demo-worker(10.0.2.2)
成功建立了邻居关系:
tor0# show bgp summary
IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.1, local AS number 65010 vrf-id 0
BGP table version 13
RIB entries 23, using 4232 bytes of memory
Peers 3, using 2149 KiB of memory
Peer groups 2, using 128 bytes of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
router0(net0) 4 65000 1430 1431 0 0 0 01:10:58 8 13 N/A
clab-bgp-cplane-demo-control-plane(10.0.1.2) 4 65010 46 52 0 0 0 00:02:12 1 11 N/A
clab-bgp-cplane-demo-worker(10.0.2.2) 4 65010 47 53 0 0 0 00:02:15 1 11 N/A
Total number of neighbors 3
查看tor1
的bgp邻居,可以看到它与clab-bgp-cplane-demo-worker2(10.0.3.2)
和clab-bgp-cplane-demo-worker3(10.0.4.2)
成功建立了邻居关系:
tor1# show bgp summary
IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.2, local AS number 65011 vrf-id 0
BGP table version 13
RIB entries 23, using 4232 bytes of memory
Peers 3, using 2149 KiB of memory
Peer groups 2, using 128 bytes of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
router0(net0) 4 65000 1436 1437 0 0 0 01:11:15 8 13 N/A
clab-bgp-cplane-demo-worker2(10.0.3.2) 4 65011 53 60 0 0 0 00:02:31 1 11 N/A
clab-bgp-cplane-demo-worker3(10.0.4.2) 4 65011 54 61 0 0 0 00:02:33 1 11 N/A
Total number of neighbors 3
查看route0
的配置可以发现其获取到了Pod的路由信息:
router0# show bgp ipv4 all
For address family: IPv4 Unicast
BGP table version is 12, local router ID is 10.0.0.0, vrf id 0
Default local pref 100, local AS 65000
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/32 0.0.0.0 0 32768 ?
*> 10.0.0.1/32 net0 0 0 65010 ?
*> 10.0.0.2/32 net1 0 0 65011 ?
*> 10.0.1.0/24 net0 0 0 65010 ?
*> 10.0.2.0/24 net0 0 0 65010 ?
*> 10.0.3.0/24 net1 0 0 65011 ?
*> 10.0.4.0/24 net1 0 0 65011 ?
*> 10.1.0.0/24 net0 0 65010 i
*> 10.1.1.0/24 net1 0 65011 i
*> 10.1.2.0/24 net0 0 65010 i
*> 10.1.3.0/24 net1 0 65011 i
*> 172.20.20.0/24 0.0.0.0 0 32768 ?
Displayed 12 routes and 12 total paths
kubernetes的Pod网络
本环境下,kubernetes的Pod通过分别连接到pod命名空间和系统命名空间的一对veth实现互通,当报文从pod命名空间传递到系统命名空间之后就会通过系统路由进行报文分发。
思考
如果将router0
、tor0
、tor1
和kubernetes的所有节点作为一个IBGP会怎么样(即所有的ASN都相同,都是internal类型的)?
答:此时由于tor0
和tor1
无法将学习到的路由转发给router0
,将导致router0
缺少pod路由,进而导致网络tor0
和tor1
不通
EBGP和IBGP在技术实现上的第三个区别在路由转发的行为上。通过IBGP学习到的路由,不能传递给其他的IBGP。这么作是为了防止路由环路(loop)。EBGP通过BGP协议里面的AS_PATH和其他元素过滤来自于自己的路由,但是IBGP运行在一个AS内部,没有AS_PATH,所以IBGP干脆不转发来自于其他IBGP的路由。
由于不能转发路由,这要求所有的IBGP router两两相连,组成一个full-mesh的网络。Full-mesh的连接数与节点的关系是n*(n-1),连接数随着节点数的增加而迅速增加,这给配置和管理带来了问题。
参考
TIPs:
- BGP简单调试:首先使用
show bgp summary
查看本节点与邻居是否协商成功,然后使用show bgp ipv4 wide
查看本节点学习到的路由即可 - 此外还可以通过
show bgp neighbor
查看邻居状态,以及通过show bgp peer-group
查看peer group的信息,使用show bgp nexthop
查看下一跳表
使用containerlab搭建cilium BGP环境解析的更多相关文章
- Windows下搭建PHP开发环境
PHP集成开发环境有很多,如XAMPP.AppServ......只要一键安装就把PHP环境给搭建好了.但这种安装方式不够灵活,软件的自由组合不方便,同时也不利于学习.所以我还是喜欢手工搭建PHP开发 ...
- 使用Apache+Dreamweaver(或者H-builder)搭建php开发环境
使用得工具说明 php+Apache服务器+Dreamweaver+mysql数据库 下载安装好wamp,可以在网上直接百度下载,为了方便,我给放个百度云的链接.wamp下载:链接:http://pa ...
- mac搭建PHP开发环境
在Mac系统上搭建Php服务器环境: LAMP: Linux Apache MySQL PHP MAMP: MACOS APACHE(自带) MYSQL(需自己安装) PHP(自带) 一.APACHE ...
- (一)Windows下搭建PHP开发环境及相关注意事项
PHP集成开发环境有很多,如XAMPP.AppServ......只要一键安装就把PHP环境给搭建好了.但这种安装方式不够灵活,软件的自由组合不方便,同时也不利于学习.所以我还是喜欢手工搭建PHP开发 ...
- [转]Windows下搭建PHP开发环境
原文:http://www.cnblogs.com/pharen/archive/2012/02/06/2340628.html PHP集成开发环境有很多,如XAMPP.AppServ......只要 ...
- docker 搭建 web 服务环境
docker容器虽然早就听说过,但是本人还真的没去用过,刚好看到相关的文章,就分享了下,有机会可以实践下...... 做过开发的人对开发环境的安装.配置应该都不会太陌生,不管你做什么开发,对开发环境都 ...
- 使用IntelliJ IDEA和Maven管理搭建Web开发环境(以Spring MVC为例)(二)
前言:在使用IntelliJ IDEA和Maven管理搭建Web开发环境(以Spring MVC为例)(一)中已经介绍了如何对web基础环境进行搭建,这里主要演示,如何对spring环境进行搭建,然后 ...
- [转载]使用VS2015搭建Lua开发环境
参考原文请看: Lua学习笔记1:Windows7下使用VS2015搭建Lua开发环境(一) Lua学习笔记2:Windows7下使用VS2015搭建Lua开发环境(二) 本篇主要分以下几个部分: 一 ...
- 如何在 Windows 10 中搭建 Node.js 环境?
[编者按]本文作者为 Szabolcs Kurdi,主要通过生动的实例介绍如何在 Windows 10 中搭建 Node.js 环境.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 在本文中 ...
随机推荐
- ASPNET Core笔试题
1.如何在ASP.NET Core中激活Session功能? 首先要添加session包. 其次要在configservice方法里面添加session.然后又在configure方法里面调用 use ...
- 没想到吧,Spring中还有一招集合注入的写法
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra. Spring作为项目中不可缺少的底层框架,提供的最基础的功能就是bean的管理了.bean的注入相信大家都比较熟 ...
- 深度学习基础-基于Numpy的多层前馈神经网络(FFN)的构建和反向传播训练
本文是深度学习入门: 基于Python的实现.神经网络与深度学习(NNDL)以及花书的读书笔记.本文将以多分类任务为例,介绍多层的前馈神经网络(Feed Forward Networks,FFN)加上 ...
- 数据结构-二叉树(Binary Tree)
1.二叉树(Binary Tree) 是n(n>=0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根节点和两棵互不相交的,分别称为根节点的左子树和右子树的二叉树组成. 2.特数二 ...
- Idea Maven调试properties 找不到报错
问题:maven执行package命令打包时,src/main/java路径下的properties文件偶尔丢失 解决方式:pom.xml中加入resources配置 <build> &l ...
- Go 接口:深入内部原理
接口的基本概念不在这里赘述,详情请看第十六章:接口 nil 非空? package main func main() { var obj interface{} obj = 1 println(obj ...
- [USACO 2009 Mar S]Look Up_via牛客网
题目 链接:https://ac.nowcoder.com/acm/contest/28537/N 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言 ...
- k8s配置集ConfigMap详解
ConfigMap介绍 ConfigMap和Secret是Kubernetes系统上两种特殊类型的存储卷,ConfigMap对象用于为容器中的应用提供配置文件等信息.但是比较敏感的数据,例如密钥.证书 ...
- 第二天python3 set常用方法
set set的元素要求set的元素必须可hash,目前学过的不可hash的类型有list.set: 1.元素不可以被索引 可变的.无序的.不重复的元素的集合 2.set可以被迭代 set增加 add ...
- c语言中的gets和fgets的使用差别
gets和fgets的差别 2022年6月30日 #include<stdio.h> #include<string.h> #define STLEN 8 int main(i ...