Configurar el acceso desde Laravel a una segunda base de datos, en SQL Server Express en un servidor remoto.
Primero configuramos la instancia de SQL Server para que sea accesible de forma remota:
Acceso a SQL Server con usuario y contraseña
Con Microsoft SQL Server Management Studio, propiedades del servidor -> Security -> Server authentication, activamos la opción SQL Server and Windows Authentication Mode.
A continuación reiniciamos el servicio SQL Server(SQLEXPRESS), desde Servicios de Windows o desde SQL Server Configuration Manager.
Creamos un usuario y contraseña para acceder a SQL Server:
Establecemos el nombre de usuario (Login name), y marcamos la opción SQL Server authenticacion. A continuación establecemos una contraseña segura y desmarcamos la opción Enforce password policy
Configurar el Firewall de Windows
A continuación abrimos el Firewall de Windows, Configuración Avanzada y creamos una nueva Regla de Entrada, de puerto, TCP, 2021, por no usar el puerto por defecto 1433, por motivos de seguridad.
Las siguientes pantallas las dejamos por defecto «Permitir conexión» y en la siguiente todas las opciones marcadas, en la última pantalla ponemos el nombre que queramos, por ejemplo, SQL Server remote.
Si vamos a acceder desde fuera de la red doméstica debemos añadir un puerto NAT TCP
Permitir a SQL Server recibir llamadas remotas
En el SQL Server Configuration Manager, en la opción SQL Server Network Configuration -> Protocols for SQLEXPRESS activamos TCP/IP
Y configuramos para leer las direcciones IP, pudiendo seleccionar una IP en concreto y marcar como Habilitado, o si tenemos la dirección IP por DHCP, podemos seleccionar la ultima opción IPAll, y establecer el puerto que estamos utilizando, en este caso 2021.
A continuación reiniciamos el servicio SQL Server (SQLEXPRESS)
Conectar a la BBDD en remoto
Ahora ya podemos acceder al servidor de forma remota, para comprobarlo desde el Microsoft SQL Server Management Studio, especificando ip,puerto usuario y contraseña.
Preparar el archivo Dockerfile
Publicamos el archivo Dockerfile:
sail artisan sail:publish
Este comando crea los archivos Dockerfile en la raíz del proyecto. Modificamos el correspondiente a la versión que estamos utilizando, la que especifica docker-compose.yml
En la configuración del Dockerfile he añadido la configuración necesaria para instalar los drivers para que Linux acceda a SQL Server, unixodbc, msodbcsql17, mssql-tools, sqlsrv, pdo_sqlsrv. La parte en negrita es la que se ha añadido.
FROM ubuntu:20.04
LABEL maintainer="Taylor Otwell"
ARG WWWGROUP
ARG NODE_VERSION=16
ARG POSTGRES_VERSION=13
WORKDIR /var/www/html
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC
SHELL ["/bin/bash", "-c"]
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update \
&& apt-get install -y unixodbc \
&& apt-get install -y unixodbc-dev \
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu focal main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
&& apt-get update \
...
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt focal-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
&& curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list \
&& apt-get update \
&& apt-get install -y yarn \
&& apt-get install -y mysql-client \
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
&& ACCEPT_EULA=Y apt-get install -y msodbcsql17 \
&& ACCEPT_EULA=Y apt-get install -y mssql-tools \
&& apt-get install -y gcc \
musl-dev \
make \
&& apt-get -y autoremove \
...
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
RUN source ~/.bashrc
RUN pecl install sqlsrv
RUN pecl install pdo_sqlsrv
RUN printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini
RUN printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini
RUN phpenmod sqlsrv pdo_sqlsrv
COPY start-container /usr/local/bin/start-container
...
A continuación recompilamos el Dockerfile
sail build --no-cache
Segunda BD en Laravel
Configuramos en el archivo .env los datos de acceso para una segunda Base de Datos.
...
DB_HOST_SS=10.20.10.120
DB_PORT_SS=2021
DB_DATABASE_SS=NOM_BD
DB_USERNAME_SS=usuario
DB_PASSWORD_SS=contraseña
...
Y los leemos desde la configuración de bases de datos de Laravel config\database.php
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST_SS', 'localhost'),
'port' => env('DB_PORT_SS', '1433'),
'database' => env('DB_DATABASE_SS', 'forge'),
'username' => env('DB_USERNAME_SS', 'forge'),
'password' => env('DB_PASSWORD_SS', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
],
Para testear si funciona la conexión, podemos establecer una ruta en routes\web.php
Route::get('/pruebaBD', function() {
dd(DB::connection('sqlsrv')->getPdo());
});
Una vez que está todo funcionando, podemos acceder a esa base de datos de distintas maneras, incluso utilizando Eloquent
$users = DB::connection('mysql2')->select(...);
...
Schema::connection('mysql2')->create('some_table', function($table)
{
$table->increments('id'):
});
...
class SomeModel extends Eloquent {
protected $connection = 'mysql2';
}
...
class SomeController extends BaseController {
public function someMethod()
{
$someModel = new SomeModel;
$someModel->setConnection('mysql2');
$something = $someModel->find(1);
return $something;
}
}