{"id":267,"date":"2023-10-23T21:57:06","date_gmt":"2023-10-23T21:57:06","guid":{"rendered":"http:\/\/kinori.tech\/blog\/?p=267"},"modified":"2026-03-07T11:56:41","modified_gmt":"2026-03-07T11:56:41","slug":"laravel-sail-in-windows-with-docker-and-powershell","status":"publish","type":"post","link":"https:\/\/kinori.tech\/blog\/en\/2023\/10\/23\/laravel-sail-in-windows-with-docker-and-powershell\/","title":{"rendered":"Laravel + Sail in Windows with Docker and PowerShell."},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><a href=\"https:\/\/github.com\/laravel\/sail\">Laravel Sail<\/a>&nbsp;is a light-weight command-line interface for interacting with Laravel&#8217;s default Docker development environment.<\/p>\n<cite><a href=\"https:\/\/laravel.com\/docs\/10.x\/sail\">Laravel Sail &#8211; Laravel 10.x &#8211; The PHP Framework For Web Artisans<\/a><\/cite><\/blockquote>\n\n\n\n<p>For me, it was the answer to the issues I faced on my Mac laptop with Brew deciding it had to update my PHP and no easy way to stop it. However, I also have a Windows PC on which I sometimes work and was left in shock when I realized that it wasn&#8217;t that easy on Windows.<\/p>\n\n\n\n<p>The actual issue, in Linux, Windows or Mac, is that although Sail commands are executed inside the Docker image, you need PHP in your machine to do the initial composer install to get Laravel\/Sail. To avoid headaches, the PHP version must match the version expected by Laravel and the packages you are using. When managing multiple Laravel applications, handling the PHP versions can be complex and time-consuming. Enter docker.<\/p>\n\n\n\n<p>The benefit of docker, in this scenario, is that you can have a separate container for each Laravel application, each with its matching PHP version. The issue is that you have a chicken-and-egg problem; you need sail to create and start the container, but you need the container to run composer and install sail. The first part of this tutorial solves the chicken-egg problem.<\/p>\n\n\n\n<p>The second issue (more like an annoyance) is that since Sail is a bash tool, you will need to install a Linux Subsystem in your Windows machine and use it to run your Sail commands. The main issue with this approach is that IDEs cannot easily use the WSL terminal to run commands, resulting in having to switch between applications while working with Laravel apps. The second part of this tutorial introduces a native PowerShell version of Sail that can be used directly in a PowerShell terminal and\/or from within your IDE.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Bootstrap the (new) Laravel application with Docker Compose<\/h2>\n\n\n\n<p>To solve the chicken-and-egg problem, we can use a bootstrap container with PHP, from which we can execute <a href=\"https:\/\/getcomposer.org\/\">Composer<\/a>, the PHP dependency management tool. This container can be used to create a new Laravel project or to work on an existing one (e.g. in my case I pulled the code from a repository). You will use this container to run composer and populate the application&#8217;s vendor folder. Once the vendor folder is populated, you can use Laravel&#8217;s Sail.<\/p>\n\n\n\n<p>If you have an existing application, clone it (or get a copy) to your Windows machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git&gt; git clone git@laravel-app.git\nCloning into &#039;laravel-app&#039;...\nPS C:\\git&gt; cd laravel-app\nPS C:\\git\\laravel-app&gt;\n<\/pre><\/div>\n\n\n<p>If you are starting a new Larvel application, create a new folder for it:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git&gt; mkdir laravel-app\n\n    Directory: C:\\git\n\nMode                 LastWriteTime         Length Name\n----                 -------------         ------ ----\nd----           9\/26\/2023  9:09 AM                laravel-app\n\nPS C:\\git&gt; cd .\\laravel-app\\\nPS C:\\git\\laravel-app&gt;\n<\/pre><\/div>\n\n\n<p>To avoid mixing the bootstrap files with your Laravel application files, create a folder called <kbd>dev<\/kbd>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app&gt; mkdir dev\n\n    Directory: C:\\git\\laravel-app\n\nMode                 LastWriteTime         Length Name\n----                 -------------         ------ ----\nd----           9\/26\/2023 10:06 AM                dev\n\nPS C:\\git\\laravel-app&gt; cd dev\nPS C:\\git\\laravel-app\\dev&gt;\n<\/pre><\/div>\n\n\n<p>Next, you\u2019ll create the&nbsp;<kbd>docker-compose.yml<\/kbd>&nbsp;file that will define the containerized environment with PHP. In this file, you\u2019ll set up a service named&nbsp;<kbd>bootstrap<\/kbd>, which will be based on a custom Docker image built with a Dockerfile you\u2019ll set up later on. <\/p>\n\n\n\n<p>Create a new\u00a0<kbd>docker-compose.yml<\/kbd>\u00a0file using your text editor of choice. Here,\u00a0notepad++\u00a0is used (I highly recommend NOT to use Windows&#8217; Notepad because it does not like files without extension and will automatically add the txt extension if you don&#8217;t use one).<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; Start notepad++ docker-compose.yml\nPS C:\\git\\laravel-app\\dev&gt;\n<\/pre><\/div>\n\n\n<p>Copy the following content to this file, and don\u2019t forget to replace the <kbd>WWWGROUP<\/kbd> value with the result from the previous command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\nversion: &quot;3.7&quot;\n\nservices:\n  #Bootstrap Container\n  bootstrap:\n    build:\n      dockerfile: Dockerfile\n    extra_hosts:\n      - &#039;host.docker.internal:host-gateway&#039;\n    ports:\n      - &#039;${APP_PORT:-80}:80&#039;\n    volumes:\n      - &#039;..:\/var\/www\/html&#039;\n    networks:\n      - sail\nnetworks:\n    sail:\n        driver: bridge\n<\/pre><\/div>\n\n\n<p>Save and close the file when you are done. If you are using&nbsp;<kbd>notepad<\/kbd>, you can do that by pressing&nbsp;<kbd>CTRL+S<\/kbd>, and then closing the app. <\/p>\n\n\n\n<p>The <kbd>docker-compose.yml<\/kbd>\u00a0requires a Dockerfile (line 5). We use the Dockerfile to install a few PHP dependencies that are required to install Laravel, and the Composer executable. To avoid version issues, you need to modify the first line to match the PHP version required by the <a href=\"https:\/\/laravel.com\/docs\/10.x\/releases#support-policy\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel version<\/a> you are using. As opposed to Unix systems, docker in Windows will run your containers as root, not as your user in the host machine. So there is no need to create groups or users.<\/p>\n\n\n\n<p>Create a new <em>Dockerfile<\/em> file using your text editor of choice (I am using notepad++).<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; Start notepad++ Dockerfile\nPS C:\\git\\laravel-app\\dev&gt;\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\nFROM php:8.1-fpm\n\n# Install system dependencies\nRUN apt-get update &amp;&amp; apt-get install -y \\\n    git \\\n    curl \\\n    libpng-dev \\\n    libonig-dev \\\n    libxml2-dev \\\n    zip \\\n    unzip\n\n# Clear cache\nRUN apt-get clean &amp;&amp; rm -rf \/var\/lib\/apt\/lists\/*\n\n# Install PHP extensions\nRUN docker-php-ext-install mbstring exif pcntl bcmath gd\n\n# Use the default production configuration\nRUN mv &quot;$PHP_INI_DIR\/php.ini-production&quot; &quot;$PHP_INI_DIR\/php.ini&quot;\n\n# Get latest Composer\nCOPY --from=composer:latest \/usr\/bin\/composer \/usr\/bin\/composer\n\n# Set working directory\nWORKDIR \/var\/www\/html\n<\/pre><\/div>\n\n\n<p>Save and close the file when you\u2019re done.  Windows does not like files without extensions, so it probably added &#8220;.txt&#8221; to your file when saving it. You can check and remove the extension if needed:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; dir\n\n    Directory: C:\\git\\laravel-app\\dev\n\nMode                 LastWriteTime         Length Name\n----                 -------------         ------ ----\n-a---           9\/27\/2023  8:54 AM            366 docker-compose.yml\n-a---           9\/27\/2023  8:54 AM            720 Dockerfile.txt\n\nPS C:\\git\\laravel-app\\dev&gt; mv .\\Dockerfile.txt Dockerfile\nPS C:\\git\\laravel-app\\dev&gt; dir\n\n    Directory: C:\\git\\laravel-app\\dev\n\nMode                 LastWriteTime         Length Name\n----                 -------------         ------ ----\n-a---           9\/27\/2023  8:54 AM            366 docker-compose.yml\n-a---           9\/27\/2023  8:54 AM            720 Dockerfile\n<\/pre><\/div>\n\n\n<p>Next, you can bring your environment up with:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker-compose up -d\n<\/pre><\/div>\n\n\n<p>This command will execute Docker Compose in&nbsp;<em>detached mode<\/em>, which means it will run in the background. The first time you bring an environment up with a custom image, Docker Compose will automatically build the image for you before creating the required containers. This might take a few moments to finish. You\u2019ll see output similar to this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n&#x5B;+] Building 61.2s (16\/16) FINISHED                                                                      docker:default\n =&gt; &#x5B;bootstrap internal] load build definition from Dockerfile                                                     0.0s\n =&gt; =&gt; transferring dockerfile: 795B                                                                               0.0s\n =&gt; &#x5B;bootstrap internal] load .dockerignore                                                                        0.0s\n =&gt; =&gt; transferring context: 2B                                                                                    0.0s\n =&gt; &#x5B;bootstrap internal] load metadata for docker.io\/library\/php:8.1-fpm                                           0.5s\n =&gt; &#x5B;bootstrap internal] load metadata for docker.io\/library\/composer:latest                                       0.5s\n =&gt; CACHED &#x5B;bootstrap stage-0  1\/10] FROM docker.io\/library\/php:8.1-fpm@sha256:d94c26a8632c0c87557dbb1839a395fa5b  0.0s\n =&gt; =&gt; resolve docker.io\/library\/php:8.1-fpm@sha256:d94c26a8632c0c87557dbb1839a395fa5b69b5f8fbd944b025c5a5783a0dc  0.0s\n =&gt; CACHED &#x5B;bootstrap] FROM docker.io\/library\/composer:latest@sha256:1ac7a547cb88acb0de62663b70f2b3d80ad273552882  0.0s\n =&gt; &#x5B;bootstrap stage-0  3\/10] RUN apt-get update &amp;&amp; apt-get install -y     git     curl     libpng-dev     libon  17.3s\n =&gt; &#x5B;bootstrap stage-0  4\/10] RUN apt-get clean &amp;&amp; rm -rf \/var\/lib\/apt\/lists\/*                                     0.5s\n =&gt; &#x5B;bootstrap stage-0  5\/10] RUN docker-php-ext-install mbstring exif pcntl bcmath gd                            40.1s\n =&gt; &#x5B;bootstrap stage-0  6\/10] RUN mv &quot;\/usr\/local\/etc\/php\/php.ini-production&quot; &quot;\/usr\/local\/etc\/php\/php.ini&quot;          0.4s\n =&gt; &#x5B;bootstrap stage-0  7\/10] COPY --from=composer:latest \/usr\/bin\/composer \/usr\/bin\/composer                      0.1s\n =&gt; &#x5B;bootstrap stage-0  8\/10] RUN groupadd --force -g 1001 sail                                                    0.5s\n =&gt; &#x5B;bootstrap stage-0  9\/10] RUN useradd -ms \/bin\/bash --no-user-group -g 1001 -u 1337 sail                       0.8s\n =&gt; &#x5B;bootstrap stage-0 10\/10] WORKDIR \/var\/www\/html                                                                0.0s\n =&gt; &#x5B;bootstrap] exporting to image                                                                                 0.5s\n =&gt; =&gt; exporting layers                                                                                            0.5s\n =&gt; =&gt; writing image sha256:21d0a638d751287c2dc7361b8c04f3563d3c96338cef44c4c98cffde5f91f108                       0.0s\n =&gt; =&gt; naming to docker.io\/library\/dev-bootstrap                                                                   0.0s\ntime=&quot;2023-09-27T09:22:39-06:00&quot; level=warning msg=&quot;Found orphan containers (&#x5B;dev-app-1]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.&quot;\n&#x5B;+] Running 1\/1\n \u2714 Container dev-bootstrap-1  Started\n<\/pre><\/div>\n\n\n<p>You can verify that your environment is up and running with:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker-compose ps\nNAME              IMAGE           COMMAND                           SERVICE     CREATED         STATUS         PORTS\ndev-bootstrap-1   dev-bootstrap   &quot;docker-php-entrypoint php-fpm&quot;   bootstrap   2 minutes ago   Up 2 minutes   0.0.0.0:80-&gt;80\/tcp, 9000\/tcp\nPS C:\\git\\laravel-app\\dev&gt;\n<\/pre><\/div>\n\n\n<p>Once the&nbsp;bootstrap&nbsp;service is up, you can run Composer, to bootstrap an existing or new Laravel application. In order to do that, you\u2019ll use&nbsp;docker compose exec&nbsp;to run commands on the&nbsp;bootstrap&nbsp;service, where PHP is installed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">New Laravel Application<\/h3>\n\n\n\n<p>For a new Laravel application, the following command will use Docker Compose to execute&nbsp;<kbd>composer create-project<\/kbd>, which will bootstrap a fresh installation of Laravel based on the&nbsp;<kbd>laravel\/laravel<\/kbd>&nbsp;package:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt;docker-compose exec bootstrap composer create-project laravel\/laravel --prefer-dist temp\nCreating a &quot;laravel\/laravel&quot; project at &quot;.\/temp&quot;\nInfo from https:\/\/repo.packagist.org: #StandWithUkraine\nInstalling laravel\/laravel (v10.2.6)\n  - Installing laravel\/laravel (v10.2.6): Extracting archive\nCreated project in \/var\/www\/html\/temp\n&gt; @php -r &quot;file_exists(&#039;.env&#039;) || copy(&#039;.env.example&#039;, &#039;.env&#039;);&quot;\nLoading composer repositories with package information\nUpdating dependencies\nLock file operations: 110 installs, 0 updates, 0 removals\n...\n82 packages you are using are looking for funding.\nUse the `composer fund` command to find out more!\n&gt; @php artisan vendor:publish --tag=laravel-assets --ansi --force\n\n   INFO  No publishable resources for tag &#x5B;laravel-assets].\n\nNo security vulnerability advisories found.\n&gt; @php artisan key:generate --ansi\n\n   INFO  Application key set successfully.\n<\/pre><\/div>\n\n\n<p>The Laravel application will be created in the <em>temp<\/em> folder, so next, you will have to move the files to the root of your <kbd>laravel-app<\/kbd> folder:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; cd ..\nPS C:\\git\\laravel-app&gt; Copy-Item -Path &quot;temp\\*&quot; -Destination &quot;.\\&quot; -Recurse\nPS C:\\git\\laravel-app&gt; Remove-Item -Recurse -Force temp\nPS C:\\git\\laravel-app&gt; dir\n\n    Directory: C:\\git\\laravel-app\n\nMode                 LastWriteTime         Length Name\n----                 -------------         ------ ----\nd----           9\/27\/2023  1:36 PM                app\nd----           9\/27\/2023  1:36 PM                bootstrap\nd----           9\/27\/2023  1:36 PM                config\nd----           9\/27\/2023  1:36 PM                database\nd----           9\/27\/2023  9:21 AM                dev\nd----           9\/27\/2023  1:36 PM                public\nd----           9\/27\/2023  1:36 PM                resources\nd----           9\/27\/2023  1:36 PM                routes\nd----           9\/27\/2023  1:36 PM                storage\nd----           9\/27\/2023  1:36 PM                tests\nd----           9\/27\/2023  1:36 PM                vendor\n-a---           8\/10\/2023  1:19 AM            258 .editorconfig\n-a---           9\/27\/2023  1:36 PM           1148 .env\n-a---           8\/10\/2023  1:19 AM           1097 .env.example\n-a---           8\/10\/2023  1:19 AM            186 .gitattributes\n-a---           8\/10\/2023  1:19 AM            243 .gitignore\n-a---           8\/10\/2023  1:19 AM           1686 artisan\n-a---           8\/10\/2023  1:19 AM           1882 composer.json\n-a---           9\/27\/2023  1:31 PM         296013 composer.lock\n-a---           8\/10\/2023  1:19 AM            248 package.json\n-a---           8\/10\/2023  1:19 AM           1084 phpunit.xml\n-a---           8\/10\/2023  1:19 AM           4158 README.md\n-a---           8\/10\/2023  1:19 AM            263 vite.config.js\n\n<\/pre><\/div>\n\n\n<p>The next step is for you to install Sail (remember that the docker-compose commands must be executed from the <em>dev<\/em> folder):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app&gt; cd dev\nPS C:\\git\\laravel-app\\dev&gt; docker-compose exec bootstrap composer require laravel\/sail --dev\nInfo from https:\/\/repo.packagist.org: #StandWithUkraine\n.\/composer.json has been updated\nRunning composer update laravel\/sail\n...\nUsing version ^1.25 for laravel\/sail\n<\/pre><\/div>\n\n\n<p>After Sail has been installed, you may run the&nbsp;<kbd>sail:install<\/kbd>&nbsp;Artisan command. This command will publish Sail&#8217;s&nbsp;<kbd>docker-compose.yml<\/kbd>&nbsp;file to the root of your application. You need to select the services you want to install:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker-compose exec bootstrap php artisan sail:install\n\n \u250c Which services would you like to install? \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 mariadb                                                      \u2502\n \u2502 redis                                                        \u2502\n \u2502 meilisearch                                                  \u2502\n \u2502 mailpit                                                      \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nSail scaffolding installed successfully.\nPS C:\\git\\laravel-app\\dev&gt;\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Existing Laravel Application<\/h3>\n\n\n\n<p>For an existing Laravel application, the following command will use Docker Compose to execute&nbsp;<kbd>composer install<\/kbd>, which will install Laravel with all the dependencies defined in the <kbd>composer.json<\/kbd> file.:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker-compose exec bootstrap composer install\nInstalling dependencies from lock file (including require-dev)\nVerifying lock file contents can be installed on current platform.\nPackage operations: 191 installs, 0 updates, 0 removals\n...\nGenerating optimized autoload files\n&gt; Illuminate\\Foundation\\ComposerScripts::postAutoloadDump\n&gt; @php artisan package:discover --ansi\n...\n126 packages you are using are looking for funding.\nUse the `composer fund` command to find out more!\n<\/pre><\/div>\n\n\n<p>Depending on the packages you are using on the Laravel project, it is possible that the composer command will fail due to missing PHP extensions. For example, this project uses the *intl* package which is missing. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt;docker-compose exec bootstrap composer install\nInstalling dependencies from lock file (including require-dev)\nVerifying lock file contents can be installed on current platform.\nYour lock file does not contain a compatible set of packages. Please run composer update.\n\n  Problem 1\n    - Root composer.json requires PHP extension ext-intl * but it is missing from your system. Install or enable PHP&#039;s intl extension.\n...\n<\/pre><\/div>\n\n\n<p>As pointed out by the error, the reason for failure can be either because there is a missing PHP extension (not installed) or it has not been enabled in the PHP configuration. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installing additional  PHP packages<\/h3>\n\n\n\n<p>In order to install a missing PHP package, you need to modify the docker file provided previously. For this, you must modify the <kbd>RUN docker-php-ext-install<\/kbd> command and add missing extensions. In this case, you will need to add the <kbd>intl<\/kbd> extension. Open the Docker file and modify line 19 (just after the <kbd># Install PHP extensions<\/kbd> comment):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nRUN docker-php-ext-install mbstring exif pcntl bcmath gd intl\n<\/pre><\/div>\n\n\n<p>Since you need to modify the container, you need Docker to create it again. So first, you need to delete it. Open your Docker desktop app, select the Containers view in the left pane. Find the dev-bootstrap container and delete it.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1023\" height=\"389\" src=\"http:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image.png\" alt=\"\" class=\"wp-image-288\" srcset=\"https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image.png 1023w, https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image-300x114.png 300w, https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image-768x292.png 768w\" sizes=\"auto, (max-width: 1023px) 100vw, 1023px\" \/><\/figure>\n\n\n\n<p>Next, select the Images view in the left pane, and delete the <kbd>dev\/bootstrap<\/kbd> image:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1002\" height=\"546\" src=\"http:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image-1.png\" alt=\"\" class=\"wp-image-289\" srcset=\"https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image-1.png 1002w, https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image-1-300x163.png 300w, https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2023\/10\/image-1-768x418.png 768w\" sizes=\"auto, (max-width: 1002px) 100vw, 1002px\" \/><\/figure>\n\n\n\n<p>Finally, you need to create the container again and run the composer install command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker-compose up -d\nPS C:\\git\\eventastic\\web\\dev&gt; docker-compose up -d\n&#x5B;+] Building 110.7s (15\/15) FINISHED                                                                     docker:default\n...\n =&gt; &#x5B;bootstrap stage-0 4\/9] RUN docker-php-ext-install mbstring exif pcntl bcmath gd intl                        106.9s\n...\nPS C:\\git\\laravel-app\\dev&gt;docker-compose exec bootstrap composer install\nInstalling dependencies from lock file (including require-dev)\nVerifying lock file contents can be installed on current platform.\nYour lock file does not contain a compatible set of packages. Please run composer update.\n\n  Problem 1\n    - openspout\/openspout is locked to version v4.15.0 and an update of this package was not requested.\n    - openspout\/openspout v4.15.0 requires ext-zip * -&gt; it is missing from your system. Install or enable PHP&#039;s zip extension.\n\n<\/pre><\/div>\n\n\n<p>So, the <kbd>intl<\/kbd> package error is gone, but the command still fails due to the zip package. You need to repeat the previous steps till no more errors due to missing packages are found. <\/p>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>NOTE<\/summary>\n<p>Additional PHP packages can require additional system libraries. When adding a PHP package, make sure to search the forums to determine if additional system libraries are needed. In this case, the RUN apt-get update &amp;&amp; apt-get install -y \\ also needs to be modified in order to install the additional system libraries.<\/p>\n<\/details>\n\n\n\n<p>The second type of issue can be related to the required extension not enabled in the PHP configuration. In this case, we need to modify the <kbd>php.ini<\/kbd> file. Although it is technically possible to directly edit the <kbd>php.ini<\/kbd> file in the Docker container, it can be easier to modify the file in the Windows host. For this, we need to copy the <kbd>php.ini<\/kbd> file from the container to the host machine. The easiest way to do this is to use the <kbd>docker cp<\/kbd> command.  You will first need to get the name of your bootstrap container. For this, you can use the <kbd>docker ps<\/kbd> command.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker ps\nCONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS          PORTS                          NAMES\n7598a58575ab   dev-bootstrap   &quot;docker-php-entrypoi\u2026&quot;   12 seconds ago   Up 10 seconds   0.0.0.0:80-&gt;80\/tcp, 9000\/tcp   dev-bootstrap-1\n<\/pre><\/div>\n\n\n<p>In this case, the container name is <kbd>dev-bootstrap-1<\/kbd>. The other piece of information you need, is the destination path in the Windows host. You can use the <kbd>pwd<\/kbd> command to do this. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; $pwd.path\nC:\\git\\laravel-app\\dev\n<\/pre><\/div>\n\n\n<p>Next, you will use the cp command to copy the php.ini file to the Windows host. Three pieces of information are used in the command. First, the name of the docker container must be replaced with your specific value. Second, the location of the <kbd>php.ini<\/kbd> file is specific to the fpm Docker images. Third, the file destination depends on where your project is located in the Windows host. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker cp dev-bootstrap-1:\/usr\/local\/etc\/php\/php.ini C:\\git\\laravel-app\\dev\nSuccessfully copied 75.3kB to C:\\git\\laravel-app\\dev\n<\/pre><\/div>\n\n\n<p>Once you know what to change and made the changes, you can copy the php.ini file back to the container. For that, you need to invert the order of the cp arguments:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker cp  C:\\git\\laravel-app\\dev\\php.ini dev-bootstrap-1:\/usr\/local\/etc\/php\nSuccessfully copied 75.3kB to dev-bootstrap-1:\/usr\/local\/etc\/php\n<\/pre><\/div>\n\n\n<p>For extension added via the Dockerfile using the <kbd>docker-php-ext-install<\/kbd> there is no need to edit the php.ini file, as the extensions are enabled using the PHP config extension mechanism.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Switching to Development<\/h2>\n\n\n\n<p>One you have bootstrapped your laravel application you can turn down your bootstrap container.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; docker-compose down\n&#x5B;+] Running 2\/2\n  Container dev-bootstrap-1 Removed 1.4s\n  Network dev_sail Removed\n<\/pre><\/div>\n\n\n<p>You no longer need the image, so you can go to your Docker panel an delete it. You can also delete the <kbd>dev <\/kbd>folder.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Native Sail via PowerShell<\/h2>\n\n\n\n<p><a href=\"https:\/\/github.com\/laravel\/sail\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel Sail<\/a> is available in Windows by using the WSL2. However, that means that you will need some extra work to configure your IDE to integrate with WSL. To avoid the hassle, and for cases where your IDE does not play nice with WSL2, I have written a PowerShell version of Sail called <a href=\"https:\/\/www.powershellgallery.com\/packages\/Jib\" target=\"_blank\" rel=\"noreferrer noopener\">Jib<\/a>. To start using it, all you need to do is to install the script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS&gt; Install-Script -Name Jib\n<\/pre><\/div>\n\n\n<p>If it is the first time you are installing scripts from the PowerShell Gallery, it is possible that you get a warning about configuring your PATH so installed scripts are available globally. <\/p>\n\n\n\n<p>If you want to use Jib, you would need to run the installed script every time you open a PowerShell terminal. In order for Jib to be available in all your sessions, you add the script to your PowerShell profile. Windows creates the $PROFILE environment variable to point to the current user profile. You can open it with Notepad++ to edit it (if it does not exist, Notepad++ will ask you if you want to create the file):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt;Start notepad++ $profile\n<\/pre><\/div>\n\n\n<p>Edit the profile PS file to load the Jib script. You can add this line to the end of the profile:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n...\n$Path = Split-Path $Profile\n. $Path\\Scripts\\Jib.ps1\n<\/pre><\/div>\n\n\n<p>After saving the changes, go back to the PowerShell terminal and reload your profile:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt;. $profile\n<\/pre><\/div>\n\n\n<p>It is possible that you get an error message while reloading the profile: <kbd><code>Management_Install.ps1<\/code>&nbsp;cannot be loaded because the execution of scripts is disabled on this system<\/kbd>. This <a href=\"https:\/\/stackoverflow.com\/a\/26955050\/3837873\" target=\"_blank\" rel=\"noreferrer noopener\">stackoverflow post<\/a> provides a great summary of why and how to fix it. After your profile has been reloaded, you should be able to check if Jib is correctly loaded:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; Get-Help Invoke-Jib\n\nNAME\n    Invoke-Jib\n\nSYNOPSIS\n    Jib is PowerShell replacement for the Laravel Sail bash\/shell command.\n ...\n\n<\/pre><\/div>\n\n\n<p>No you can use any of the supported Sail commands, for example, you can start your application:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nPS C:\\git\\laravel-app\\dev&gt; Invoke-Jib up\nSetting the ENVIRONMENT from the &#039;.env&#039; file\nDeciding what docker compose to use.\nEnsure that Docker is running...\nDetermine if Sail is currently up...\nPass thru to docker-compose up\nExecuting command in container: docker compose up\n&#x5B;+] Building 0.0s (0\/0)\n&#x5B;+] Running 4\/0\n \u2714 Container laravel-app-mailhog-1       Created                                                                    0.0s\n \u2714 Container laravel-app-mariadb-1       Created                                                                    0.0s\n \u2714 Container laravel-app-redis-1         Created                                                                    0.0s\n \u2714 Container laravel-app-laravel.test-1  Created                                                                    0.0s\n...\nlaravel-app-laravel.test-1  |    INFO  Server running on &#x5B;http:\/\/0.0.0.0:80].\nlaravel-app-laravel.test-1  |\nlaravel-app-laravel.test-1  |   Press Ctrl+C to stop the server\nlaravel-app-laravel.test-1  |\nlaravel-app-mailhog-1       | &#x5B;APIv1] KEEPALIVE \/api\/v1\/events\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>You learned how to bootstrap a Laravel application using Docker, so we develop against a particular version of PHP in a Windows machine without requiring a local PHP installation (e.g. via XAMPP). You also installed the Jib PowerShell script, a Laravel Sail drop-in replacement, so we can interact with the Laravel container from the PowerShell terminal.<\/p>\n\n\n\n<p>I hope you find this information useful!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Laravel Sail&nbsp;is a light-weight command-line interface for interacting with Laravel&#8217;s default Docker development environment. Laravel Sail &#8211; Laravel 10.x &#8211; The PHP Framework For Web Artisans For me, it was the answer to the issues I faced on my Mac [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[22,19,21,23,20],"series":[],"class_list":["post-267","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-docker","tag-laravel","tag-php","tag-powershell","tag-sail"],"_links":{"self":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts\/267","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/comments?post=267"}],"version-history":[{"count":44,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions"}],"predecessor-version":[{"id":408,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions\/408"}],"wp:attachment":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/media?parent=267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/categories?post=267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/tags?post=267"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/series?post=267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}