Costumávamos executar um site social, em uma configuração padrão do LAMP. Tínhamos um servidor ao vivo, um servidor de teste e um servidor de desenvolvimento, além de máquinas de desenvolvedores locais. Todos foram gerenciados usando o GIT.
Em cada máquina, tínhamos os arquivos PHP, mas também o serviço MySQL, e uma pasta com imagens que os usuários carregavam. O servidor Live cresceu para ter cerca de 100K (!) Usuários recorrentes, o despejo era de cerca de 2GB (!), A pasta Image era de cerca de 50GB (!). Quando saí, nosso servidor estava atingindo o limite de sua CPU, Ram e, acima de tudo, os limites de conexão de rede simultâneos (até compilamos nossa própria versão do driver da placa de rede para maximizar o servidor 'lol'). Não foi possível ( nem você deve assumir com seu site ) colocar 2 GB de dados e 50 GB de imagens no GIT.
Para gerenciar tudo isso no GIT com facilidade, ignoraríamos as pastas binárias (as pastas que contêm as imagens) inserindo esses caminhos de pasta no .gitignore. Também tínhamos uma pasta chamada SQL fora do caminho da raiz do documento Apache. Nessa pasta SQL, colocaríamos nossos arquivos SQL dos desenvolvedores em numerações incrementais (001.florianm.sql, 001.johns.sql, 002.florianm.sql, etc). Esses arquivos SQL também foram gerenciados pelo GIT. O primeiro arquivo sql realmente conteria um grande conjunto de esquemas de banco de dados. Não adicionamos dados do usuário no GIT (por exemplo, os registros da tabela de usuários ou da tabela de comentários), mas dados como configurações, topologia ou outros dados específicos do site foram mantidos nos arquivos sql (e, portanto, pelo GIT). Principalmente, são os desenvolvedores (que conhecem melhor o código) que determinam o que e o que não é mantido pelo GIT com relação ao esquema e aos dados SQL.
Quando chegou a uma versão, o administrador efetua login no servidor dev, mescla a ramificação ativa com todos os desenvolvedores e ramificações necessárias na máquina dev em uma ramificação de atualização e a envia ao servidor de teste. No servidor de teste, ele verifica se o processo de atualização do servidor Live ainda é válido e, em rápida sucessão, aponta todo o tráfego no Apache para um site de espaço reservado, cria um dump de banco de dados, aponta o diretório de trabalho da atualização 'ao vivo' para ' ', executa todos os novos arquivos sql no mysql e redireciona o tráfego para o site correto. Quando todas as partes interessadas concordaram após revisar o servidor de teste, o Administrador fez o mesmo do servidor de Teste ao servidor Live. Posteriormente, ele mescla a ramificação ativa no servidor de produção, para a ramificação mestre em todos os servidores, e refaz o rebase de todas as ramificações ativas.
Se houve problemas no servidor de teste, por exemplo. as mesclagens tiveram muitos conflitos, o código foi revertido (apontando o ramo de trabalho de volta para 'live') e os arquivos sql nunca foram executados. No momento em que os arquivos sql foram executados, isso foi considerado uma ação não reversível na época. Se os arquivos SQL não estavam funcionando corretamente, o banco de dados foi restaurado usando o Dump (e os desenvolvedores informaram, por fornecer arquivos SQL mal testados).
Hoje, mantemos uma pasta sql-up e sql-down, com nomes de arquivos equivalentes, onde os desenvolvedores precisam testar se os arquivos sql de atualização podem ser igualmente rebaixados. Em última análise, isso poderia ser executado com um script bash, mas é uma boa idéia se os olhos humanos continuem monitorando o processo de atualização.
Não é ótimo, mas é administrável. Espero que isso dê uma ideia de um site prático, prático e com relativamente alta disponibilidade. Seja um pouco desatualizado, mas ainda seguido.