We have our own gateway that we use for pictures (snap1.d.tube).
These IPFS gateways are a bit like a CDN system. The same file will load through any gateway. example https://ipfs.io/ipfs/Qmb14Qr2Jk55SDu3dtUNccZw7GDpzCHa8VeoZok... is the same as https://snap1.d.tube/ipfs/Qmb14Qr2Jk55SDu3dtUNccZw7GDpzCHa8V... or through any IPFS gateway.
Long term we plan to get rid of these gateways, by using js-ipfs in our player. Works, but not really stable as of my last try (memory leaks that cause the tab to crash after X minutes). With js-ipfs (native javascript IPFS node), we can load files directly from all nodes that have the file pinned, without going through gateways.
Also if you run ipfs locally and use the localhost:8080 gateway, then it's also going full p2p.
you can even mount ipfs as a readonly filesystem and cat that hash and get the content.
Once you've managed to connect to a node you can usually explore the topology of the network and find other peers so you only need the centralized resource temporarily to bootstrap new nodes. I'm not too familiar with IPFS but I imagine it works in a similar way.
Yeah, "Bootstrapping" a distributed network requires some sort of entrypoint. There are a couple of solutions, I'll share what IPFS is using.
First we have mDNS for local discovery. When you start a IPFS node, it starts announcing it's addresses over the local network. So this solution is pretty decentralized, as it'll connect with any node it can find. This doesn't work over the backbone though.
Secondly, we (Protocol Labs) run a couple of "bootstrap" nodes. They are normal IPFS nodes, but they run behind DNS and a static IP. Then in the standard distribution of IPFS Core (go-ipfs and js-ipfs) we hardcode the addresses. So when you start your node, it connects to the bootstrap nodes, which then shares which nodes they are connected with, so everyone ends up connected. This ends up introducing a bit of centralization, but because they are normal IPFS nodes, the community could agree to also connect to other bootstrap nodes, the only thing needed is a static address (optional really, but "Good to have") and a IPFS node running there.
Lastly, we have Signalling servers for webrtc and websocket connections (mainly for js-ipfs in the browser). This basically acts as a centralized endpoint for nodes to find each other. This is probably the most centralized solution to the bootstrapping problem.