{"id":14955759,"url":"https://github.com/loftwah-demo/linux-for-pirates-2","last_synced_at":"2025-10-24T08:31:19.275Z","repository":{"id":247595972,"uuid":"826127293","full_name":"loftwah-demo/linux-for-pirates-2","owner":"loftwah-demo","description":"DevOps with Docker, Ruby on Rails and Linux for Pirates!","archived":false,"fork":false,"pushed_at":"2024-07-17T13:00:47.000Z","size":245,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-29T09:08:44.380Z","etag":null,"topics":["docker","docker-compose","linux","npm","ruby","ruby-on-rails","tutorial"],"latest_commit_sha":null,"homepage":"https://loftwah-demo.github.io/linux-for-pirates-2/","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loftwah-demo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"loftwah","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2024-07-09T06:26:01.000Z","updated_at":"2024-08-29T19:19:10.000Z","dependencies_parsed_at":"2024-07-17T15:56:24.215Z","dependency_job_id":"c6c57fd4-4f4c-4897-8cd6-a22da50a25b4","html_url":"https://github.com/loftwah-demo/linux-for-pirates-2","commit_stats":{"total_commits":12,"total_committers":1,"mean_commits":12.0,"dds":0.0,"last_synced_commit":"448eb5d8e9248a6db101b4b31c4b512ec7b0e78d"},"previous_names":["loftwah-demo/linux-for-pirates-2"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loftwah-demo%2Flinux-for-pirates-2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loftwah-demo%2Flinux-for-pirates-2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loftwah-demo%2Flinux-for-pirates-2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loftwah-demo%2Flinux-for-pirates-2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loftwah-demo","download_url":"https://codeload.github.com/loftwah-demo/linux-for-pirates-2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237937826,"owners_count":19390545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-compose","linux","npm","ruby","ruby-on-rails","tutorial"],"created_at":"2024-09-24T13:11:41.079Z","updated_at":"2025-10-24T08:31:13.917Z","avatar_url":"https://github.com/loftwah-demo.png","language":null,"funding_links":["https://github.com/sponsors/loftwah"],"categories":[],"sub_categories":[],"readme":"# Linux for Pirates! Ruby on Whales\n\n![DevOps with Docker, Ruby on Rails and Linux for Pirates!](https://github.com/user-attachments/assets/2732a87d-2b4f-421a-9828-ab31f8ab9156)\n\n\n## Introduction\n\nAhoy, mateys! Welcome aboard the grand adventure that be \"Linux for Pirates! Ruby on Whales\" This here tome be yer trusty map through the treacherous seas of Ruby on Rails, Docker, and the mystical arts of DevOps. Whether ye be a scallywag just learning the ropes or a seasoned buccaneer, this book be the compass to guide ye through the stormy waters of modern application deployment.\n\n### What Ye Will Learn:\n\n#### Setting Sail with Ruby on Rails:\n\n* **Introduction to Rails**: Discover the lore and legend of Rails in web development.\n* **Creating Your Rails Application**: Hoist the Jolly Roger and set up a new Rails project, configure PostgreSQL, and rig the sails with Tailwind CSS.\n\n#### Treasure Mapping Your Project Structure:\n\n* **Project Structure Overview**: Chart the directory layout of a Rails application.\n* **Version Control with Git**: Best practices for organizing yer Git repository, managing sensitive data, and handling private gems and npm packages.\n\n#### Docker – Yer Ship for the Journey:\n\n* **Introduction to Docker**: Learn why Docker be the vessel of choice and master key concepts like images, containers, and Dockerfiles.\n* **Creating a Dockerfile for Rails**: Write a Dockerfile from scratch, optimize with multi-stage builds, and understand workflows for existing Rails projects.\n* **Running Yer Rails App with Docker**: Build and run Docker containers locally.\n\n#### Docker Compose – Coordinatin' Yer Fleet:\n\n* **Introduction to Docker Compose**: Explore the advantages of Docker Compose for multi-service applications.\n* **Setting Up Docker Compose**: Write a docker-compose.yml file, configure services for Rails, PostgreSQL, and Redis, and manage environment variables like a true pirate captain.\n\n#### Guardin' Yer Treasure – Private Dependencies:\n\n* **Managing Private Ruby Gems**: Create and use private gems in yer Rails application, and authenticate with GitHub for secure access.\n* **Handling Private npm Packages**: Create and use private npm packages, integrating them seamlessly with yer Rails application.\n\n#### Secure Authentication with SSH and HTTPS:\n\n* **SSH Key Management**: Set up and use SSH keys in Docker, understand the security implications, and explore better alternatives like PATs.\n* **HTTPS Authentication**: Use GitHub Personal Access Tokens (PATs) for secure access, managing them securely in yer environment.\n\n#### Automatin' Yer Deployment – CI/CD:\n\n* **Introduction to CI/CD**: Understand the importance of continuous integration and deployment.\n* **Setting Up GitHub Actions**: Write workflows for automated testing and deployment, and follow best practices for secure and efficient CI/CD pipelines.\n* **Deploying with GitHub Actions and Cloud**: Step-by-step guide to deploying Rails applications with GitHub Actions and a cloud provider.\n\n#### Advanced Docker Techniques:\n\n* **Multi-Stage Builds**: Implement multi-stage builds for optimized Docker images.\n* **Docker Volumes and Networks**: Manage data persistence with Docker volumes, purge data safely, and configure Docker networks for inter-container communication.\n\n#### Monitoring and Scaling Yer Application:\n\n* **Application Monitoring**: Tools and techniques for monitoring a Rails application, including Raygun, Honeybadger, Axiom, Datadog, and Vector.\n* **Scaling with Docker and the cloud**: Strategies for scaling yer application, auto-scaling, and load balancing considerations.\n\n#### Security Best Practices:\n\n* **Securing Yer Docker Containers**: Identify and mitigate common security vulnerabilities.\n* **Managing Secrets and Sensitive Data**: Best practices for handling sensitive information in Docker and CI/CD pipelines.\n\n#### Troubleshootin' and Debuggin':\n\n* **Common Issues and Solutions**: Troubleshoot common problems in Dockerized Rails applications.\n* **Debuggin' Techniques**: Tools and methods for effective debugging in a Docker environment.\n\n### Who This Book Be For:\n\n\"Rails and DevOps with Docker for Pirates!\" be perfect for:\n\n* **Developers and DevOps Engineers**: Lookin' to deepen their understanding of Rails, Docker, and CI/CD practices.\n* **Intermediate to Advanced Practitioners**: With a basic knowledge of Ruby, Rails, Docker, and DevOps, aim to level up their skills.\n* **Tech Enthusiasts and Innovators**: Passionate about modern deployment practices and efficient application management.\n\n#### Prerequisites\n\nBefore ye embark on this grand adventure, make sure ye have the following knowledge and tools at yer disposal:\n\n##### Knowledge:\n\n1. **Basic Programming Skills**: Ye should be comfortable with basic programming concepts and syntax.\n2. **Ruby and Rails**: Familiarity with the Ruby programming language and basic Rails framework. Ye should know how to create a simple Rails application and understand MVC (Model-View-Controller) architecture.\n3. **Command Line Proficiency**: Experience with using the command line interface (CLI) for navigating directories, running scripts, and managing files.\n4. **Version Control with Git**: Basic understanding of Git, including creating repositories, committing changes, and pushing to remote repositories.\n5. **Docker Fundamentals**: Knowledge of Docker concepts like containers, images, and Dockerfiles. Ye should be able to build and run a basic Docker container.\n6. **DevOps Concepts**: Familiarity with DevOps practices, including continuous integration and deployment (CI/CD), and infrastructure as code (IaC).\n\n##### Tools:\n\n1. **Development Environment**: A computer running macOS, Linux, or Windows with a Unix-like shell (e.g., Git Bash, WSL for Windows).\n2. **Ruby and Rails**: Ensure Ruby (version 3.3.0 or later) and Rails are installed on yer machine. Use version managers like RVM or rbenv for managing Ruby versions.\n3. **Docker**: Install Docker Desktop for container management. Make sure Docker Compose is also installed.\n4. **Git**: Have Git installed and configured with yer GitHub account for version control and accessing repositories.\n5. **Code Editor**: A code editor or integrated development environment (IDE) like Visual Studio Code, Sublime Text, NeoVim or RubyMine.\n6. **Package Managers**: Ensure you have package managers like npm (Node Package Manager) and yarn for managing JavaScript dependencies.\n\nBy having these prerequisites, ye’ll be well-prepared to navigate the treacherous seas of modern application deployment with \"Rails and DevOps with Docker for Pirates!\" Ready yerself, and let the adventure begin!\n\n### Why This Book?\n\nIn this fast-paced world of tech, mastering the integration of development and operations be crucial. Docker be revolutionizin' application deployment, makin' it easier to build, ship, and run applications consistently across different environments. This book provides a hands-on, practical approach to implementin' these technologies, ensuring ye can deliver reliable, scalable, and secure applications.\n\nJoin the adventure with \"Rails and DevOps with Docker for Pirates!\" and embark on a journey to become a master of modern web development and deployment. Whether ye be settin' sail for the first time or seekin' to enhance yer skills, this book be yer ultimate guide to navigatin' the digital seas.\n\n### About the Author\n\nAhoy, me hearties! Gather 'round and let me spin ye a yarn about Dean Lofts, the legendary Loftwah of the tech and music seas. Dean be a seasoned DevOps Engineer, currently plundering the digital waves at Operoo. With over a decade of swashbuckling experience, Dean has amassed a treasure trove of skills in infrastructure management, network security, and cloud computing, with a particular prowess in AWS. His journey through various industries and roles has forged him into a versatile and formidable force, capable of tackling the most complex technical challenges.\n\n#### Professional Background\n\nDean's voyage began in the Royal Australian Navy, where he served as a Communications and Information Systems Sailor. For six years, he braved the high seas of satellite communication, radio operation, and LAN administration. His valor and skill earned him prestigious medals, such as the Australian Active Service Medal, the Iraq Medal, and the Australian Defence Medal. This military stint laid a strong keel for his technical expertise and disciplined approach to problem-solving.\n\nAfter his naval adventures, Dean set sail into civilian waters, taking on roles like System Engineer at Unisys and Solutions Consultant at UXC Connect. At UXC Connect, he navigated high-profile projects for clients like Chevron and the Department of Defence, ensuring their systems stayed afloat and their infrastructure was shipshape.\n\nDean's prowess grew with roles such as Senior Test \u0026 Integration Technician at Thales and System Administrator at PVS Australia Pty Ltd. He maintained IT infrastructure, implemented network security measures, and optimized system performance, honing his skills in troubleshooting, infrastructure management, and cloud computing.\n\nIn his recent voyages, including Site Reliability Engineer at PlayHQ Sports and DevOps Engineer at CorpCloud Pty Ltd, Dean bridged the gap between development and IT operations. He wielded automation tools to create scalable and reliable software systems, championing the importance of continuous integration and continuous deployment (CI/CD) practices.\n\n#### Skills and Endorsements\n\nDean's technical arsenal be extensive and highly endorsed. Key skills include:\n\n* **Infrastructure and Networking**: Proven capabilities in designing and maintaining robust infrastructure and networks, with endorsements in network security and DNS.\n* **DevOps and CI/CD**: Expertise in deploying and automating processes with tools like Docker, Jenkins, and GitHub Actions, ensuring efficient and secure software delivery.\n* **Cloud Computing**: Skilled in leveraging AWS services for scalable and efficient solutions, demonstrated by his AWS Certified Solutions Architect – Professional certification.\n* **Programming and Scripting**: Proficient in languages such as Ruby, Python, Bash, and more, with a strong focus on creating maintainable and efficient code.\n* **Security**: In-depth knowledge of network security, ensuring secure and reliable operations, with certifications like CompTIA Security+.\n\nDean's skills have been recognized and endorsed by shipmates and landlubbers alike, highlighting his expertise and reliability.\n\n#### Contributions and Achievements\n\nDean be a passionate advocate for open source, making significant contributions to numerous projects, including Appwrite, EddieHub, BioDrop, NASA, and WordPress. He served as an ambassador for these communities, driving technological advancement and fostering a collaborative environment. His open-source contributions reflect his commitment to sharing knowledge and improving the tech ecosystem.\n\nOne of Dean's notable feats be his integration of the yjit compiler, which delivered a 15% performance boost and substantial cost savings. This innovation showcases his ability to identify and implement improvements that have a meaningful impact on performance and efficiency.\n\n#### Creative Pursuits\n\nBeyond the tech realm, Dean be an accomplished music producer known as Loftwah The Beatsmiff. He has produced albums and collaborated with artists like Grind Mode Cypher and OptiMystic MC. His musical projects, including \"Salty Waterz\" and \"Day of the Guiding Light,\" demonstrate his creative prowess and ability to blend technical precision with artistic expression.\n\n#### Published Works\n\nDean be the author of \"Linux for Pirates!\", a unique and engaging book that demystifies Linux for enthusiasts and professionals alike. The book's innovative approach and accessible style have made it a valuable resource for those looking to deepen their understanding of Linux. Dean's ability to break down complex concepts into understandable content be evident in his writing and teaching.\n\n#### Personal Life\n\nIn his personal life, Dean be a dedicated father and mental health advocate. He balances his professional and creative pursuits with a commitment to his family and personal well-being. Dean enjoys beat making, reading, and curating tech-focused content on his YouTube channel, where he shares insights and tutorials with a broad audience.\n\nDean's journey be a testament to his relentless pursuit of excellence and his commitment to sharing knowledge with the community. His work ethic and innovative approach have earned him accolades and recognition in both the tech and music industries.\n\n#### Discover More\n\nTo learn more about Dean's multifaceted journey, check out his contributions on platforms like GitHub, listen to his music on Spotify, and read his insightful tech articles. Welcome to Dean's world—a blend of rhythm, code, and a relentless drive for excellence.\n\n## Chapter 1: Setting Sail with Ruby on Rails\n\n### Introduction to Ruby on Rails\n\nAhoy, mateys! Before we hoist the sails and embark on our grand adventure with Ruby on Rails, let’s take a moment to understand the history and significance of this mighty framework.\n\nRuby on Rails, often simply called Rails, was forged by the brilliant mind of David Heinemeier Hansson (DHH) back in 2004. Rails be a powerful web application framework written in the Ruby programming language, designed to make the development of web applications smoother than a calm sea. It follows the principles of Convention over Configuration (CoC) and Don’t Repeat Yourself (DRY), allowing buccaneers like ye to write less code and achieve more.\n\nRails has charted the course for many popular web applications, including Basecamp, GitHub, and Shopify. Its treasure lies in its simplicity and productivity, enabling developers to build complex applications swiftly and efficiently.\n\n### Creating Your Rails Application\n\nNow, let’s set sail and create our Rails application. Follow these steps to ensure your ship is well-equipped for the journey ahead.\n\n#### Step 1: Installing Ruby and Rails\n\nTo begin our voyage, we need to install Ruby. There be several ways to manage Ruby versions on your system. We’ll cover the most popular methods: RVM, rbenv, ruby-install, and chruby. Choose the one that best suits your needs.\n\n#### Using RVM (Ruby Version Manager)\n\n1. **Install RVM**:\n\n   Head over to the [RVM website](https://rvm.io/) for the latest installation instructions. As of now, you can use this command to install RVM:\n\n   ```bash\n   curl -sSL https://get.rvm.io | bash -s stable\n   ```\n\n2. **Load RVM into your shell session**:\n\n   ```bash\n   source ~/.rvm/scripts/rvm\n   ```\n\n3. **Add RVM to your shell configuration file (e.g., .zshrc)**:\n\n   ```bash\n   echo 'source ~/.rvm/scripts/rvm' \u003e\u003e ~/.zshrc\n   ```\n\n4. **Install Ruby using RVM**:\n\n   ```bash\n   rvm install 3.3.0\n   rvm use 3.3.0 --default\n   ```\n\n5. **Verify the installation**:\n\n   ```bash\n   ruby -v\n   ```\n\n#### Other Ruby Version Managers\n\nWhile RVM be a popular choice, there be other ways to manage Ruby versions. Here be a quick overview:\n\n* **rbenv**: Lightweight and simpler to set up. Visit the [rbenv GitHub page](https://github.com/rbenv/rbenv) for installation details.\n* **ruby-install and chruby**: For those who prefer more control and flexibility. Visit the [ruby-install GitHub page](https://github.com/postmodern/ruby-install) and [chruby GitHub page](https://github.com/postmodern/chruby) for instructions.\n\nEach of these tools has its own way of configuring your shell (e.g., .zshrc). Here’s what to do:\n\n* **rbenv**:\n\n  ```bash\n  echo 'export PATH=\"$HOME/.rbenv/bin:$PATH\"' \u003e\u003e ~/.zshrc\n  echo 'eval \"$(rbenv init - zsh)\"' \u003e\u003e ~/.zshrc\n  ```\n\n* **chruby**:\n\n  ```bash\n  echo 'source /usr/local/share/chruby/chruby.sh' \u003e\u003e ~/.zshrc\n  echo 'source /usr/local/share/chruby/auto.sh' \u003e\u003e ~/.zshrc\n  echo 'chruby ruby-3.3.0' \u003e\u003e ~/.zshrc\n  ```\n\nOnce ye’ve configured yer shell, restart it or run `source ~/.zshrc` to apply the changes.\n\n#### Checking Your Shell Configuration\n\nTo ensure yer shell be properly set up, ye can check if the Ruby version manager is working correctly:\n\n1. **Open a new terminal session** or run:\n\n   ```bash\n   source ~/.zshrc\n   ```\n\n2. **Verify the Ruby version**:\n\n   ```bash\n   ruby -v\n   ```\n\n   This should return `ruby 3.3.0` if everything be set up correctly.\n\n#### Step 2: Install Rails\n\nWith Ruby ready to set sail, it’s time to install Rails.\n\n1. **Install Rails**:\n\n   ```bash\n   gem install rails\n   ```\n\n2. **Verify the installation**:\n\n   ```bash\n   rails -v\n   ```\n\n#### Step 3: Creating Your Rails Application\n\nNow, it’s time to create our Rails application. We’ll set it up to use PostgreSQL as the database and Tailwind CSS for styling.\n\n1. **Create a new Rails application with PostgreSQL and Tailwind CSS**:\n\n   ```bash\n   rails new pirate_app -d postgresql --css tailwind\n   cd pirate_app\n   ```\n\n2. **Configure PostgreSQL**: Open the `config/database.yml` file and configure it for PostgreSQL:\n\n   ```yaml\n   default: \u0026default\n     adapter: postgresql\n     encoding: unicode\n     pool: \u003c%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %\u003e\n     username: postgres\n     password: postgres\n     host: localhost\n\n   development:\n     \u003c\u003c: *default\n     database: pirate_app_development\n\n   test:\n     \u003c\u003c: *default\n     database: pirate_app_test\n\n   production:\n     \u003c\u003c: *default\n     database: pirate_app_production\n     username: pirate_app\n     password: \u003c%= ENV['PIRATE_APP_DATABASE_PASSWORD'] %\u003e\n   ```\n\n   \u003e Note: your configuration for username and password may be different so if you have issues here that is where you'll need to look\n\n3. **Create the database**:\n\n   ```bash\n   rails db:create\n   ```\n\n4. **Start the Rails server**:\n\n   ```bash\n   rails server\n   ```\n\n### Step 4: Generating a Home Controller and View\n\n1. **Generate a Home Controller**:\n\n   ```bash\n   rails generate controller Home index\n   ```\n\n2. **Set the root route**: Open the `config/routes.rb` file and set the root route to the `index` action of the `Home` controller:\n\n   ```ruby\n   Rails.application.routes.draw do\n     root 'home#index'\n   end\n   ```\n\n3. **Create the Landing Page Content**: Open the `app/views/home/index.html.erb` file and add the following HTML code with Tailwind CSS classes to create a pirate-themed landing page:\n\n   ```html\n   \u003cdiv class=\"min-h-screen bg-blue-900 flex items-center justify-center\"\u003e\n     \u003cdiv class=\"max-w-2xl bg-gray-800 text-white p-10 rounded-lg shadow-lg\"\u003e\n       \u003ch1 class=\"text-5xl font-bold mb-4 text-center\"\u003eAhoy, Matey!\u003c/h1\u003e\n       \u003cp class=\"text-xl mb-6 text-center\"\u003eWelcome to Pirate App, the ultimate pirate-themed adventure on the high seas!\u003c/p\u003e\n       \n       \u003cdiv class=\"flex justify-center mb-6\"\u003e\n         \u003cimg src=\"https://example.com/pirate-ship.jpg\" alt=\"Pirate Ship\" class=\"w-full h-auto rounded-lg shadow-md\"\u003e\n       \u003c/div\u003e\n       \n       \u003cdiv class=\"text-center\"\u003e\n         \u003ca href=\"#get-started\" class=\"bg-yellow-500 text-black font-bold py-2 px-4 rounded hover:bg-yellow-600\"\u003eGet Started\u003c/a\u003e\n       \u003c/div\u003e\n     \u003c/div\u003e\n   \u003c/div\u003e\n   ```\n\n   \u003e Note: Replace the image with one of your own.\n\n### Step 5: Adding Navigation and Footer\n\n1. **Add Navigation Bar**: Update `app/views/layouts/application.html.erb` to include a simple navigation bar and footer:\n\n   ```html\n   \u003c!DOCTYPE html\u003e\n   \u003chtml\u003e\n     \u003chead\u003e\n       \u003ctitle\u003ePirateApp\u003c/title\u003e\n       \u003c%= csrf_meta_tags %\u003e\n       \u003c%= csp_meta_tag %\u003e\n\n       \u003c%= stylesheet_link_tag \"application\", \"data-turbo-track\": \"reload\" %\u003e\n       \u003c%= javascript_include_tag \"application\", \"data-turbo-track\": \"reload\", defer: true %\u003e\n     \u003c/head\u003e\n\n     \u003cbody class=\"bg-blue-900 text-white\"\u003e\n       \u003cheader class=\"bg-gray-800 p-4\"\u003e\n         \u003cdiv class=\"container mx-auto flex justify-between items-center\"\u003e\n           \u003ch1 class=\"text-2xl font-bold\"\u003ePirateApp\u003c/h1\u003e\n           \u003cnav\u003e\n             \u003cul class=\"flex space-x-4\"\u003e\n               \u003cli\u003e\u003ca href=\"/\" class=\"hover:text-yellow-500\"\u003eHome\u003c/a\u003e\u003c/li\u003e\n             \u003c/ul\u003e\n           \u003c/nav\u003e\n         \u003c/div\u003e\n       \u003c/header\u003e\n       \u003c%= yield %\u003e\n       \u003cfooter class=\"bg-gray-800 p-4 mt-10\"\u003e\n         \u003cdiv class=\"container mx-auto text-center\"\u003e\n           \u003cp\u003e\u0026copy; 2024 PirateApp. All rights reserved.\u003c/p\u003e\n         \u003c/div\u003e\n       \u003c/footer\u003e\n     \u003c/body\u003e\n   \u003c/html\u003e\n   ```\n\nWith these steps, you will have a simple pirate-themed landing page for your Rails application using Tailwind CSS, complete with navigation and footer.\n\nAvast! Ye now have a Rails application with PostgreSQL and Tailwind CSS ready to set sail!\n\n### Configuring PostgreSQL in Rails\n\nConfiguring PostgreSQL for a Rails application involves setting up the `config/database.yml` file. This file tells Rails how to connect to your PostgreSQL database in different environments (development, test, and production). Here's a detailed explanation of the configuration process and how it works in the context of a Rails application.\n\n#### Step-by-Step Explanation of `database.yml`\n\nThe `config/database.yml` file contains the database configuration for different environments. Each environment (development, test, and production) can have its own settings. Here's the structure and explanation:\n\n```yaml\ndefault: \u0026default\n  adapter: postgresql\n  encoding: unicode\n  pool: \u003c%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %\u003e\n  username: postgres\n  password: postgres\n  host: localhost\n\ndevelopment:\n  \u003c\u003c: *default\n  database: pirate_app_development\n\ntest:\n  \u003c\u003c: *default\n  database: pirate_app_test\n\nproduction:\n  \u003c\u003c: *default\n  database: pirate_app_production\n  username: pirate_app\n  password: \u003c%= ENV['PIRATE_APP_DATABASE_PASSWORD'] %\u003e\n```\n\n#### Default Configuration\n\n```yaml\ndefault: \u0026default\n  adapter: postgresql\n  encoding: unicode\n  pool: \u003c%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %\u003e\n  username: postgres\n  password: postgres\n  host: localhost\n```\n\n* **`default: \u0026default`**: Defines a set of default settings that can be reused across different environments. The `\u0026default` is a YAML anchor that allows these settings to be referenced elsewhere in the file.\n* **`adapter: postgresql`**: Specifies that PostgreSQL is the database adapter to be used.\n* **`encoding: unicode`**: Sets the character encoding for the database to Unicode, which supports international characters.\n* **`pool: \u003c%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %\u003e`**: Sets the database connection pool size. It fetches the value from the `RAILS_MAX_THREADS` environment variable, defaulting to 5 if not set. The connection pool is the number of connections Rails maintains to the database.\n* **`username: postgres`**: The database username for connecting to PostgreSQL.\n* **`password: postgres`**: The database password for the given username.\n* **`host: localhost`**: Specifies that the database is hosted on the local machine.\n\n#### Development Configuration\n\n```yaml\ndevelopment:\n  \u003c\u003c: *default\n  database: pirate_app_development\n```\n\n* **`\u003c\u003c: *default`**: Inherits all the settings from the `default` section using the YAML alias `*default`.\n* **`database: pirate_app_development`**: Specifies the name of the development database. Rails will connect to this database when running in development mode.\n\n#### Test Configuration\n\n```yaml\ntest:\n  \u003c\u003c: *default\n  database: pirate_app_test\n```\n\n* **`\u003c\u003c: *default`**: Inherits all the settings from the `default` section.\n* **`database: pirate_app_test`**: Specifies the name of the test database. Rails uses this database when running tests.\n\n#### Production Configuration\n\n```yaml\nproduction:\n  \u003c\u003c: *default\n  database: pirate_app_production\n  username: pirate_app\n  password: \u003c%= ENV['PIRATE_APP_DATABASE_PASSWORD'] %\u003e\n```\n\n* **`\u003c\u003c: *default`**: Inherits all the settings from the `default` section.\n* **`database: pirate_app_production`**: Specifies the name of the production database.\n* **`username: pirate_app`**: The database username for production. This should be different from the development and test usernames for security reasons.\n* **`password: \u003c%= ENV['PIRATE_APP_DATABASE_PASSWORD'] %\u003e`**: Fetches the database password from an environment variable. This ensures sensitive information is not hardcoded in the file.\n\n#### Environment Variables\n\nUsing environment variables for sensitive information (like database passwords) is a best practice. It keeps these details secure and allows for easier changes across different environments (e.g., staging, production).\n\n* **Setting Environment Variables**:\n\n  * On Unix-like systems (macOS, Linux), you can set environment variables in your shell configuration file (`.bashrc`, `.zshrc`, etc.):\n\n    ```bash\n    export PIRATE_APP_DATABASE_PASSWORD=your_secure_password\n    ```\n\n  * On Windows, you can set environment variables using the `set` command:\n\n    ```cmd\n    set PIRATE_APP_DATABASE_PASSWORD=your_secure_password\n    ```\n\n#### Creating and Managing the Database\n\nOnce the `config/database.yml` file is properly configured, you can create the database and start the Rails server.\n\n1. **Create the database**:\n\n   ```bash\n   rails db:create\n   ```\n\n   This command will create the databases specified in the `database.yml` file for the current environment.\n\n2. **Start the Rails server**:\n\n   ```bash\n   rails server\n   ```\n\n   This command starts the Rails application. The server will use the database configuration for the current environment (development by default).\n\n#### Summary\n\nThe `config/database.yml` file is a critical part of configuring your Rails application to work with PostgreSQL. It specifies how Rails connects to the database in different environments, using settings inherited from a default configuration. By leveraging environment variables, you can securely manage sensitive information like database passwords. Once configured, you can create the database and start the Rails server to begin development.\n\n### Rails Project Troubleshooting Steps\n\nEven the most seasoned pirates encounter rough seas. If ye run into trouble while setting up yer Rails project, here be some common issues and troubleshooting steps to help ye navigate through the storm.\n\n#### Troubleshooting Installation Issues\n\n**1. Ruby and Rails Installation Problems:**\n\n* **Issue:** Ruby or Rails not found after installation.\n  * **Solution:** Verify the installation with `ruby -v` and `rails -v`. Ensure the version manager (RVM, rbenv, etc.) is properly configured in your shell profile (`.zshrc` or `.bashrc`). Restart your terminal or run `source ~/.zshrc` or `source ~/.bashrc`.\n\n**2. Bundler Errors:**\n\n* **Issue:** Bundler fails to install gems.\n  * **Solution:** Ensure you have the correct version of Bundler installed. Run `gem install bundler` and then `bundle install`. Check for any specific gem installation errors and ensure all dependencies are met.\n\n#### Database Configuration Issues\n\n**1. PostgreSQL Connection Problems:**\n\n* **Issue:** Rails cannot connect to the PostgreSQL database.\n  * **Solution:** Verify that PostgreSQL is running. Check the `config/database.yml` file for correct database credentials. Test the connection with `psql -U postgres -h localhost`. Ensure the `pg` gem is installed by running `gem install pg`.\n\n**2. Database Creation Failures:**\n\n* **Issue:** Error running `rails db:create`.\n  * **Solution:** Ensure you have the necessary privileges to create databases. Check PostgreSQL user permissions and roles. Verify that `username` and `password` in `config/database.yml` match your PostgreSQL configuration.\n\n#### Rails Server Issues\n\n**1. Server Not Starting:**\n\n* **Issue:** Rails server fails to start.\n  * **Solution:** Check the server logs for error messages (`log/development.log`). Ensure all necessary gems are installed and the database is properly configured. Run `rails db:migrate` to apply any pending migrations.\n\n**2. Port Conflicts:**\n\n* **Issue:** Address already in use.\n  * **Solution:** Ensure no other process is using port 3000. Stop any running Rails servers or other services using the same port. Use `lsof -i :3000` to identify and kill conflicting processes.\n\n#### Docker-Related Issues\n\n**1. Docker Build Failures:**\n\n* **Issue:** Docker image build fails.\n  * **Solution:** Check the Dockerfile for syntax errors and correct paths. Ensure all dependencies are available and properly referenced. Use `docker build --no-cache .` to rebuild the image without using the cache.\n\n**2. Container Connection Problems:**\n\n* **Issue:** Rails application cannot connect to PostgreSQL in Docker.\n  * **Solution:** Verify the `docker-compose.yml` configuration. Ensure the services are correctly defined and linked. Use `docker-compose logs` to inspect service logs for errors. Check environment variables for proper database connection details.\n\n#### Common Errors and Solutions\n\n**1. Missing Gem Errors:**\n\n* **Issue:** `GemNotFound` or `LoadError`.\n  * **Solution:** Run `bundle install` to install missing gems. Ensure the gem is listed in the `Gemfile`. If using private gems, verify authentication settings.\n\n**2. Asset Compilation Failures:**\n\n* **Issue:** Errors during asset precompilation.\n  * **Solution:** Check for missing dependencies or incorrect paths in asset files. Ensure all necessary JavaScript and CSS libraries are installed. Run `RAILS_ENV=production rails assets:precompile` for a more detailed error output.\n\n#### Finding Help\n\n**1. Rails Guides and Documentation:**\n\n* Visit the [Rails Guides](https://guides.rubyonrails.org/) for comprehensive documentation and tutorials.\n\n**2. Stack Overflow:**\n\n* Search for similar issues on [Stack Overflow](https://stackoverflow.com/). Use tags like `ruby-on-rails`, `postgresql`, `docker`, and `tailwind-css` to find relevant solutions.\n\n**3. GitHub Issues:**\n\n* Check the GitHub repositories of gems and libraries for reported issues and solutions.\n\n**4. Community Forums and Chat:**\n\n* Join Rails, Docker, and DevOps communities on platforms like Reddit, Discord, Twitter/X and Slack. Engaging with these communities can provide quick help and insights from experienced developers.\n\nBy following these troubleshooting steps and utilizing available resources, ye'll be better equipped to handle any issues that arise during yer Rails and Docker adventure. Happy sailing!\n\n#### Summary\n\nYe’ve successfully set up Ruby and Rails on yer ship, configured PostgreSQL for yer database needs, and hoisted the Tailwind CSS sails. With yer environment shipshape, ye’re ready to embark on the next leg of yer Rails adventure. Now, it’s time to navigate the seas of development, deployment, and beyond!\n\n### Installing NodeJS\n\n#### Installing NodeJS with NVM\n\nTo manage multiple versions of Node.js efficiently, you can use Node Version Manager (NVM). Here’s how to install NVM and set it up with the LTS version of Node.js (v20.15.1):\n\n1. **Install \u0026 Update Script**:\n\n   You can install or update NVM using the install script. Use either of the following commands to download and run the script:\n\n   ```bash\n   curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash\n   ```\n\n   ```bash\n   wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash\n   ```\n\n   Running either of these commands will clone the NVM repository to `~/.nvm` and attempt to add the following lines to your profile file (`~/.bash_profile`, `~/.zshrc`, `~/.profile`, or `~/.bashrc`):\n\n   ```bash\n   export NVM_DIR=\"$([ -z \"${XDG_CONFIG_HOME-}\" ] \u0026\u0026 printf %s \"${HOME}/.nvm\" || printf %s \"${XDG_CONFIG_HOME}/nvm\")\"\n   [ -s \"$NVM_DIR/nvm.sh\" ] \u0026\u0026 \\. \"$NVM_DIR/nvm.sh\" # This loads nvm\n   ```\n\n2. **Load NVM**:\n\n   After installation, you might need to restart your terminal or source your profile file to load NVM:\n\n   ```bash\n   # For bash\n   source ~/.bashrc\n\n   # For zsh\n   source ~/.zshrc\n\n   # For ksh\n   . ~/.profile\n   ```\n\n3. **Verify Installation**:\n\n   To verify that NVM has been installed, run:\n\n   ```bash\n   command -v nvm\n   ```\n\n   This should print `nvm` if the installation was successful.\n\n4. **Install Node.js LTS Version (v20.15.1)**:\n\n   Once NVM is installed, you can install the LTS version of Node.js (v20.15.1):\n\n   ```bash\n   nvm install 20.15.1\n   ```\n\n5. **Use the LTS Node.js Version**:\n\n   To use the LTS version of Node.js, run:\n\n   ```bash\n   nvm use 20.15.1\n   ```\n\n6. **Set the LTS Node.js Version as Default**:\n\n   To set the LTS version of Node.js as the default, run:\n\n   ```bash\n   nvm alias default 20.15.1\n   ```\n\n#### Troubleshooting\n\nIf you encounter issues where `nvm` is not found after installation:\n\n* Ensure that the profile file is sourced properly.\n\n* Restart your terminal.\n\n* Manually add the following lines to your profile file and source it:\n\n  ```bash\n  export NVM_DIR=\"$([ -z \"${XDG_CONFIG_HOME-}\" ] \u0026\u0026 printf %s \"${HOME}/.nvm\" || printf %s \"${XDG_CONFIG_HOME}/nvm\")\"\n  [ -s \"$NVM_DIR/nvm.sh\" ] \u0026\u0026 \\. \"$NVM_DIR/nvm.sh\" # This loads nvm\n  ```\n\n#### Notes for macOS Users\n\nFor macOS users, especially those with Apple Silicon chips:\n\n* Ensure you have Xcode command line tools installed:\n\n  ```bash\n  xcode-select --install\n  ```\n\n* If you face issues, ensure you create the necessary profile files (`~/.bash_profile` or `~/.zshrc`) if they don’t exist, and then rerun the install script.\n\n#### Summary\n\nBy installing and configuring NVM, you can easily manage multiple versions of Node.js, making your development workflow more flexible and efficient. For this setup, we have used the LTS version v20.15.1 to ensure stability and long-term support.\n\n### Next Steps\n\nIn the next chapter, we’ll delve deeper into organizing yer Rails project structure, setting up version control with Git, and managing private gems and npm packages. Stay the course, and ye’ll be a Rails and DevOps pirate in no time!\n\n## Chapter 2: Treasure Mapping Your Project Structure\n\n### Project Structure Overview\n\nAhoy, me hearties! Now that we’ve set sail with our Ruby on Rails application, it’s time to chart the course of our project structure. Understanding the directory layout of a Rails application is crucial for navigating and managing your code effectively.\n\nWhen ye create a new Rails application, Rails generates a standard directory structure. Here’s a brief overview of the key directories and their purposes:\n\n* **app/**: Contains the core application code. This is where ye’ll find your models, views, controllers, helpers, mailers, and jobs.\n\n  * **assets/**: Manages your application’s front-end assets like images, JavaScript, and stylesheets.\n  * **controllers/**: Holds the controller classes responsible for handling requests and responses.\n  * **models/**: Contains the model classes that interact with the database.\n  * **views/**: Holds the view templates that render HTML.\n  * **helpers/**: Contains helper modules used to clean up your views.\n  * **mailers/**: Manages email delivery logic.\n  * **jobs/**: Contains background job classes.\n\n* **bin/**: Contains executable files like rails and rake.\n\n* **config/**: Houses configuration files for the application, including database, routes, initializers, and environments.\n\n  * **environments/**: Contains environment-specific settings (development, test, production).\n  * **initializers/**: Holds files that run during application initialization.\n  * **locales/**: Manages translation files for internationalization.\n\n* **db/**: Manages database-related files.\n\n  * **migrate/**: Contains migration files for altering the database schema.\n  * **seeds.rb**: Holds seed data for populating the database.\n\n* **lib/**: Used for extended modules and libraries.\n  * **tasks/**: Contains custom rake tasks.\n\n* **log/**: Stores application log files.\n\n* **public/**: Holds static files like error pages and assets.\n\n* **test/** or **spec/**: Manages test or spec files for testing the application.\n\n* **tmp/**: Contains temporary files like cache and pid files.\n\n* **vendor/**: Manages third-party code like plugins and gems.\n\nUnderstanding this structure will help ye navigate and organize yer code effectively.\n\n### Setting Up Version Control with Git\n\nNow, let’s set up version control to keep our codebase shipshape. Git be the tool of choice for version control, and GitHub be our treasure chest for storing code.\n\n#### Best Practices for Organizing Your Git Repository\n\n##### Creating a GitHub Repository\n\nIf ye haven’t already, head over to [GitHub](https://github.com/) and sign up for an account.\n\n**Create a New Repository**:\n\n* Navigate to [GitHub](https://github.com/).\n* Click on the “+” icon in the top-right corner and select “New repository”.\n* Fill in the repository name, description (optional), and choose whether to make it public or private.\n* Click “Create repository”.\n\nOnce ye have a repository, follow these steps to get yer code into the cloud.\n\n1. **Initialize Git**:\n\n   ```bash\n   git init --initial-branch=main\n   ```\n\n2. **Commit Early and Often**: It be best practice to commit yer changes frequently with clear and concise commit messages. This makes it easier to track changes and roll back if needed.\n\n   ```bash\n   git add .\n   git commit -m \"Yargh Mateys\"\n   ```\n\n3. **Add Remote Repository**: Add the GitHub repository as a remote to yer local repository. Replace `your-username` and `your-repo` with yer GitHub username and repository name.\n\n   ```bash\n   git remote add origin git@github.com:loftwah-demo/pirate_app.git\n   ```\n\n4. **Push to GitHub**: Push yer local commits to the remote repository on GitHub.\n\n   ```bash\n   git branch -M main\n   git push -u origin main\n   ```\n\n5. **Use Branches**: Create branches for new features or bug fixes. This keeps the main branch clean and stable.\n\n   ```bash\n   git checkout -b feature/new-feature\n   ```\n\n6. **Merge with Pull Requests**: Use pull requests to merge changes into the main branch. This allows for code review and discussion before changes are integrated.\n\n#### Importance of .gitignore and Managing Sensitive Data\n\nThe .gitignore file be crucial for managing what files Git tracks. It helps keep unnecessary files out of your repository, reducing clutter and protecting sensitive information.\n\nNever commit sensitive data such as API keys, passwords, or configuration files containing secrets. Use environment variables or a secrets management tool instead.\n\nFor Rails applications, the `.env` file is commonly used to manage environment-specific configurations. However, remember to add `.env` to your `.gitignore` to prevent it from being tracked by Git.\n\n```plaintext\n# .gitignore\n.env\n```\n\n### Creating and Using Private Gems and npm Packages\n\nIn our adventure, we’ll create our own private gems and npm packages that we can use in our Rails application. This be an essential skill for any Rails developer, as it allows for modular and reusable code across multiple projects.\n\n#### Creating a Private Ruby Gem\n\n1. **Set Up the Gem Structure**: Create a new directory for your gem:\n\n   ```bash\n   mkdir my_private_gem\n   cd my_private_gem\n   bundle gem .\n   ```\n\n2. **Edit the Gem Specification**: Open the `my_private_gem.gemspec` file and fill in the necessary details:\n\n   ```ruby\n   Gem::Specification.new do |spec|\n     spec.name          = \"my_private_gem\"\n     spec.version       = \"0.1.0\"\n     spec.authors       = [\"Your Name\"]\n     spec.email         = [\"your.email@example.com\"]\n     spec.summary       = \"A private gem for demonstration purposes\"\n     spec.description   = \"This gem is used to demonstrate using private gems in a Rails application\"\n     spec.homepage      = \"https://github.com/loftwah-demo/my_private_gem\"\n     spec.license       = \"MIT\"\n     spec.files         = Dir[\"lib/**/*.rb\"]\n     spec.require_paths = [\"lib\"]\n   end\n   ```\n\n3. **Add Functionality**: Create a simple functionality in `lib/my_private_gem.rb`:\n\n   ```ruby\n   module MyPrivateGem\n     class Error \u003c StandardError; end\n     \n     def self.hello\n       \"Hello from MyPrivateGem!\"\n     end\n   end\n   ```\n\n4. **Commit and Push to GitHub**: Initialize a new Git repository and push the gem to a private repository on GitHub:\n\n   ```bash\n   git init --initial-branch=main\n   git add .\n   git commit -m \"Initial commit\"\n   git remote add origin git@github.com:loftwah-demo/my_private_gem.git\n   git branch -M main\n   git push -u origin main\n   ```\n\n\u003e Note: the following changes are made in the Rails application you started earlier.\n\n#### Using the Private Gem in Rails\n\nTo use the private gem in your Rails application, ye’ll need to create a GitHub Personal Access Token (PAT) for authentication.\n\n1. **Create a GitHub PAT**:\n\n   * Go to GitHub and navigate to **Settings** \u003e **Developer settings** \u003e **Personal access tokens**.\n   * Click **Generate new token**.\n   * Select the scopes `repo` and `read:packages`, then generate the token.\n   * Copy the token and store it securely.\n\n2. **Add the Private Gem to Your Rails Application’s Gemfile**:\n\n   ```ruby\n   # Gemfile\n   gem 'my_private_gem', git: 'https://github.com/loftwah-demo/my_private_gem.git'\n   ```\n\n3. **Configure Bundler to Use the PAT**: Create or update your `.bundle/config` file to include the GitHub PAT:\n\n   ```bash\n   bundle config https://github.com/loftwah-demo \u003cyour_github_token\u003e\n   ```\n\n   Alternatively, set the environment variable in your shell:\n\n   ```bash\n   export BUNDLE_GITHUB__COM=\u003cyour_github_token\u003e\n   ```\n\n4. **Install the Gem**: Run `bundle install` to install the gem:\n\n   ```bash\n   bundle install\n   ```\n\n   \u003e Note: We will cover using this in your Rails application in chapter x\n\n### Creating a Private npm Package\n\n1. **Set Up the npm Package**: Create a new directory for your npm package:\n\n   ```bash\n   mkdir my-private-npm-package\n   cd my-private-npm-package\n   npm init -y\n   ```\n\n2. **Update `package.json`**: Edit `package.json` to include the necessary details:\n\n   ```json\n   {\n     \"name\": \"my-private-npm-package\",\n     \"version\": \"1.0.0\",\n     \"main\": \"index.js\",\n     \"scripts\": {\n       \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\"\n     },\n     \"keywords\": [\"loftwah\", \"linux\", \"for\", \"pirates\"],\n     \"author\": \"Dean Lofts\",\n     \"license\": \"ISC\",\n     \"description\": \"A private package for Linux for Pirates!\"\n   }\n   ```\n\n3. **Add Functionality**: Create a simple functionality in `index.js`:\n\n   ```javascript\n   function helloFromNpm() {\n     return \"Hello from my private npm package!\";\n   }\n\n   module.exports = { helloFromNpm };\n   ```\n\n4. **Commit and Push to GitHub**: Initialize a new Git repository and push the package to a private repository on GitHub:\n\n   ```bash\n   git init --initial-branch=main\n   git add .\n   git commit -m \"Initial commit\"\n   git remote add origin git@github.com:loftwah-demo/my-private-npm-package.git\n   git push -u origin main\n   ```\n\n#### Installing the Private Package in Your Rails Application\n\n1. **Navigate to Your Rails Application Directory**:\n\n   ```bash\n   cd ../pirate_app\n   ```\n\n2. **Create a `package.json` File**:\n\n   ```bash\n   npm init -y\n   ```\n\n3. **Update `package.json` to Include the Private Package**:\n\n   Open the generated `package.json` file in a text editor and modify it to include your private package:\n\n   ```json\n   {\n     \"name\": \"pirate_app\",\n     \"version\": \"1.0.0\",\n     \"description\": \"This README would normally document whatever steps are necessary to get the application up and running.\",\n     \"main\": \"index.js\",\n     \"directories\": {\n       \"lib\": \"lib\",\n       \"test\": \"test\"\n     },\n     \"scripts\": {\n       \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\"\n     },\n     \"keywords\": [],\n     \"author\": \"\",\n     \"license\": \"ISC\",\n     \"dependencies\": {\n       \"my-private-npm-package\": \"git+https://github.com/loftwah-demo/my-private-npm-package.git\"\n     }\n   }\n   ```\n\n4. **Configure npm for Authentication**:\n\n   Create an `.npmrc` file in your Rails application's root directory to authenticate with GitHub Packages:\n\n   ```plaintext\n   //npm.pkg.github.com/:_authToken=${GITHUB_PAT}\n   ```\n\n5. **Install the Dependencies**:\n\n   Run `npm install` to install the packages defined in `package.json`:\n\n   ```bash\n   npm install\n   ```\n\n\u003e Note: You will be able to see the package in your `node_modules` directory and we will set this up further in chapter 5.\n\n#### Summary\n\n1. **Set Up a Private npm Package**: Created a directory, added functionality, and pushed to a private GitHub repository. Also, updated `package.json` with the necessary details.\n2. **Create a `package.json` File in Rails App**: Initialized a `package.json` file and added the private package as a dependency.\n3. **Configure Authentication**: Created an `.npmrc` file for GitHub package authentication.\n4. **Install Dependencies**: Ran `npm install` to install the private package.\n\nBy following these steps, you’ve set up a private npm package, pushed it to GitHub, and configured your Rails application to use this package. This ensures your codebase is well-organized and secure, allowing you to smoothly develop your application.\n\n### Next Steps\n\nIn the next chapter, we’ll dive into Docker, the mighty ship that’ll carry our Rails application across the seas of deployment. We’ll learn how to write Dockerfiles, build Docker images, and run our Rails app within Docker containers. Stay the course, and ye’ll be a Rails and DevOps pirate in no time!\n\n### Chapter 3: Docker – Your Ship for the Journey\n\n### Introduction to Docker\n\nAhoy, me hearties! Docker be the sturdy ship that’ll carry ye across the treacherous seas of deployment and development. In this chapter, we’ll set sail with Docker, learnin’ its key concepts and why it’s the vessel of choice for modern developers.\n\n#### What is Docker and Why Use It?\n\nDocker be an open platform for developing, shipping, and running applications. It enables ye to separate yer applications from yer infrastructure, makin’ it easier to deploy and manage them across different environments. Here be why Docker be invaluable:\n\n* **Consistency**: Docker ensures yer application runs the same, regardless of where it be deployed.\n* **Isolation**: Each application runs in its own container, avoidin’ conflicts with other applications.\n* **Portability**: Docker containers can be easily moved between different environments and cloud providers.\n* **Efficiency**: Docker images be lightweight and start quickly, improvin’ resource utilization.\n\n#### Key Docker Concepts: Images, Containers, Dockerfiles\n\n* **Images**: Immutable snapshots of yer application, includin’ all dependencies and configurations.\n* **Containers**: Running instances of Docker images, providin’ isolated environments for yer application.\n* **Dockerfiles**: Scripts that define how to build Docker images, includin’ all necessary steps and configurations.\n\n### Using and Modifying the Provided Dockerfile for Rails\n\nWhen ye generate a new Rails project, it comes with a Dockerfile ready to use. However, we had to make some modifications to this default Dockerfile. These changes were necessary to install a private package from GitHub using a Personal Access Token (PAT). Let’s explore these modifications.\n\n### Commands Used\n\n1. To show Rails credentials using the nano editor:\n\n   ```bash\n   EDITOR=nano bin/rails credentials:show\n   ```\n\n   \u003e Note: you need this one to get your SECRET_KEY_BASE\n\n2. To run the Docker container:\n\n   ```bash\n   docker run -e SECRET_KEY_BASE=\u003cmy-key\u003e -p 3000:3000 pirate_app\n   ```\n\n3. To build the Docker image using a secret token:\n\n   ```bash\n   GITHUB_TOKEN=\u003cmy-token\u003e docker buildx build --secret id=GITHUB_TOKEN -t pirate_app .\n   ```\n\n### Modifications to the Dockerfile\n\nHere’s the modified Dockerfile with the necessary changes to handle secrets and build the application:\n\n```Dockerfile\n# syntax=docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\n# Rails app lives here\nWORKDIR /rails\n\n# Set production environment\nENV RAILS_ENV=\"production\" \\\n    BUNDLE_DEPLOYMENT=\"1\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n    BUNDLE_WITHOUT=\"development\"\n\n# Throw-away build stage to reduce size of final image\nFROM base as build\n\n# Install packages needed to build gems\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config\n\n# Install application gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use secret to access GitHub token to install private packages\nRUN --mount=type=secret,id=GITHUB_TOKEN \\\n    GITHUB_TOKEN=${GITHUB_TOKEN} \u0026\u0026 \\\n    git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n    bundle install \u0026\u0026 \\\n    rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n    bundle exec bootsnap precompile --gemfile\n\n# Copy application code\nCOPY . .\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Precompiling assets for production without requiring secret RAILS_MASTER_KEY\nRUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile\n\n# Final stage for app image\nFROM base\n\n# Install packages needed for deployment\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y curl libvips postgresql-client \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists /var/cache/apt/archives\n\n# Copy built artifacts: gems, application\nCOPY --from=build /usr/local/bundle /usr/local/bundle\nCOPY --from=build /rails /rails\n\n# Run and own only the runtime files as a non-root user for security\nRUN useradd rails --create-home --shell /bin/bash \u0026\u0026 \\\n    chown -R rails:rails db log storage tmp\nUSER rails:rails\n\n# Entrypoint prepares the database.\nENTRYPOINT [\"/rails/bin/docker-entrypoint\"]\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\"]\n```\n\n### Explanation of Changes\n\nThe changes we made are here:\n\n  ```dockerfile\n  # Use secret to access GitHub token to install private packages\n  RUN --mount=type=secret,id=GITHUB_TOKEN \\\n      GITHUB_TOKEN=${GITHUB_TOKEN} \u0026\u0026 \\\n      git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n      bundle install \u0026\u0026 \\\n      rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n      bundle exec bootsnap precompile --gemfile\n  ```\n\nWe made these changes to the Dockerfile to handle the installation of private packages from GitHub using a Personal Access Token (PAT). This approach ensures that our application can securely access and install these private packages during the Docker build process.\n\n### Running Yer Rails App with Docker\n\nNow that we’ve modified our Dockerfile, let’s build and run our Docker containers locally.\n\n1. **Build the Docker Image**:\n\n   ```bash\n   GITHUB_TOKEN=\u003cmy-token\u003e docker buildx build --secret id=GITHUB_TOKEN -t pirate_app .\n   ```\n\n2. **Run the Docker Container**:\n\n   ```bash\n   docker run -e SECRET_KEY_BASE=\u003cmy-key\u003e -p 3000:3000 pirate_app\n   ```\n\nYer Rails application should now be built into a Docker container. However, since our application relies on PostgreSQL, it won't be runnin' properly just yet. In the next chapter, we'll dive into Docker Compose to orchestrate multiple services, including our Rails app and PostgreSQL database.\n\n### Dockerfile Walkthrough\n\nLet’s walk through the Dockerfile step-by-step to understand each part and how it helps in building and running your Rails application.\n\n#### Base Stage\n\n```Dockerfile\n# syntax=docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\n# Rails app lives here\nWORKDIR /rails\n\n# Set production environment\nENV RAILS_ENV=\"production\" \\\n    BUNDLE_DEPLOYMENT=\"1\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n    BUNDLE_WITHOUT=\"development\"\n```\n\n* **Base Image**: We start with a base image for Ruby. The version is specified using the `ARG RUBY_VERSION` argument, allowing flexibility if you need to change the Ruby version.\n\n* **Working Directory**: The `WORKDIR /rails` command sets the working directory inside the container to `/rails`, where our Rails application will reside.\n\n* **Environment Variables**:\n\n  * `RAILS_ENV=\"production\"`: Sets the Rails environment to production.\n  * `BUNDLE_DEPLOYMENT=\"1\"` and `BUNDLE_PATH=\"/usr/local/bundle\"`: Configure Bundler to install gems in deployment mode and to a specific path.\n  * `BUNDLE_WITHOUT=\"development\"`: Excludes the development group from the bundle install.\n\n#### Build Stage\n\n```Dockerfile\n# Throw-away build stage to reduce size of final image\nFROM base as build\n\n# Install packages needed to build gems\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config\n\n# Install application gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use secret to access GitHub token to install private packages\nRUN --mount=type=secret,id=GITHUB_TOKEN \\\n    GITHUB_TOKEN=${GITHUB_TOKEN} \u0026\u0026 \\\n    git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n    bundle install \u0026\u0026 \\\n    rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n    bundle exec bootsnap precompile --gemfile\n\n# Copy application code\nCOPY . .\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Precompiling assets for production without requiring secret RAILS_MASTER_KEY\nRUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile\n```\n\n* **Build Stage**: This stage is used to build the application and its dependencies.\n\n* **Install Packages**: The `RUN apt-get install` command installs necessary packages for building Ruby gems, such as `build-essential`, `git`, `libpq-dev`, `libvips`, and `pkg-config`.\n\n* **Install Gems**:\n\n  * `COPY Gemfile Gemfile.lock ./`: Copies the Gemfile and Gemfile.lock into the container.\n  * `RUN --mount=type=secret,id=GITHUB_TOKEN ... bundle install`: Uses a GitHub token to install private gems, ensuring the token remains secret during the build.\n  * `rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git`: Cleans up unnecessary files to reduce the image size.\n  * `bundle exec bootsnap precompile --gemfile`: Precompiles bootsnap code for faster boot times.\n\n* **Copy Application Code**: `COPY . .` copies the entire application code into the container.\n\n* **Precompile Assets**: Precompiles Rails assets for production without requiring the master key by using a dummy key.\n\n#### Final Stage\n\n```Dockerfile\n# Final stage for app image\nFROM base\n\n# Install packages needed for deployment\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y curl libvips postgresql-client \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists /var/cache/apt/archives\n\n# Copy built artifacts: gems, application\nCOPY --from=build /usr/local/bundle /usr/local/bundle\nCOPY --from=build /rails /rails\n\n# Run and own only the runtime files as a non-root user for security\nRUN useradd rails --create-home --shell /bin/bash \u0026\u0026 \\\n    chown -R rails:rails db log storage tmp\nUSER rails:rails\n\n# Entrypoint prepares the database.\nENTRYPOINT [\"/rails/bin/docker-entrypoint\"]\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\"]\n```\n\n* **Final Stage**: This stage creates the final image that will be used to run the application.\n\n* **Install Deployment Packages**: Installs necessary packages for running the Rails application, such as `curl`, `libvips`, and `postgresql-client`.\n\n* **Copy Artifacts**: Copies the built artifacts (gems and application code) from the build stage to the final image.\n\n* **Set Up User and Permissions**:\n\n  * `useradd rails --create-home --shell /bin/bash`: Adds a non-root user named `rails` for security.\n  * `chown -R rails:rails db log storage tmp`: Changes ownership of important directories to the `rails` user.\n  * `USER rails:rails`: Switches to the `rails` user for running the application.\n\n* **Entrypoint and CMD**:\n\n  * `ENTRYPOINT [\"/rails/bin/docker-entrypoint\"]`: Sets the entrypoint script to prepare the database.\n  * `EXPOSE 3000`: Exposes port 3000 for the application.\n  * `CMD [\"./bin/rails\", \"server\"]`: Starts the Rails server by default.\n\n### Running Your Rails App with Docker\n\nNow that we’ve modified our Dockerfile, let’s build and run our Docker containers locally.\n\n1. **Build the Docker Image**:\n\n   ```bash\n   GITHUB_TOKEN=\u003cmy-token\u003e docker buildx build --secret id=GITHUB_TOKEN -t pirate_app .\n   ```\n\n2. **Run the Docker Container**:\n\n   ```bash\n   docker run -e SECRET_KEY_BASE=\u003cmy-key\u003e -p 3000:3000 pirate_app\n   ```\n\nYer Rails application should now be built into a Docker container. However, since our application relies on PostgreSQL, it won't be runnin' properly just yet. In the next chapter, we'll dive into Docker Compose to orchestrate multiple services, including our Rails app and PostgreSQL database.\n\n### Summary\n\nYe’ve successfully explored the provided Dockerfile for yer Rails application, made necessary modifications to handle private package installations, and run yer application within a Docker container. With Docker as yer ship, ye be ready to navigate the seas of deployment and beyond!\n\n### Next Steps\n\nIn the next chapter, we’ll dive into Docker Compose, coordinatin’ multiple services like a true pirate captain. We’ll set up a `docker-compose.yml` file, configure services for Rails, PostgreSQL, and Redis, and manage environment variables. Stay the course, and ye’ll be a Rails and DevOps pirate in no time!\n\n## Chapter 4: Docker Compose – Coordinating Your Fleet\n\n### Introduction to Docker Compose\n\nDocker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. This simplifies orchestration, streamlines the development process, and ensures consistency across different stages of development and deployment.\n\n### Setting Up Docker Compose\n\nDocker Compose uses a `docker-compose.yml` file to define and configure multiple services. We'll set up a multi-service application for Rails and PostgreSQL. Additionally, we'll handle environment variables securely using `.env` files.\n\n### Writing a docker-compose.yml File for a Multi-Service Application\n\nTo manage your development environment effectively, we'll create a `docker-compose.yml` file. This file will configure services for Rails, PostgreSQL, and handle secrets securely.\n\n#### Why the Original Dockerfile is Suitable for Production\n\nThe original Dockerfile is optimized for production environments:\n\n* **Multi-stage builds**: This reduces the size of the final image by only including necessary artifacts.\n* **Environment-specific configurations**: Ensures the environment variables are set for production.\n* **Security considerations**: Runs the application as a non-root user.\n\nHere's the production Dockerfile:\n\n```dockerfile\n# syntax=docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\n# Rails app lives here\nWORKDIR /rails\n\n# Set production environment\nENV RAILS_ENV=\"production\" \\\n    BUNDLE_DEPLOYMENT=\"1\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n    BUNDLE_WITHOUT=\"development\"\n\n# Throw-away build stage to reduce size of final image\nFROM base AS build\n\n# Install packages needed to build gems\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config\n\n# Install application gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use secret to access GitHub token\nRUN --mount=type=bind,target=. \\\n    --mount=type=secret,id=GITHUB_TOKEN \\\n    GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) \u0026\u0026 \\\n    git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n    bundle install \u0026\u0026 \\\n    rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n    bundle exec bootsnap precompile --gemfile\n\n# Copy application code\nCOPY . .\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Precompiling assets for production without requiring secret RAILS_MASTER_KEY\nRUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile\n\n# Final stage for app image\nFROM base\n\n# Install packages needed for deployment\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y curl libvips postgresql-client \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists /var/cache/apt/archives\n\n# Copy built artifacts: gems, application\nCOPY --from=build /usr/local/bundle /usr/local/bundle\nCOPY --from=build /rails /rails\n\n# Run and own only the runtime files as a non-root user for security\nRUN useradd rails --create-home --shell /bin/bash \u0026\u0026 \\\n    chown -R rails:rails db log storage tmp\nUSER rails:rails\n\n# Entrypoint prepares the database.\nENTRYPOINT [\"/rails/bin/docker-entrypoint\"]\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\"]\n```\n\n#### Why We Need a Separate Dockerfile for Development\n\nUsing the same Dockerfile for both production and development can lead to inefficiencies and complexities. The development Dockerfile (`Dockerfile.dev`) is optimized for:\n\n* **Rapid Iteration**: Allows for quick rebuilding and live code reloading.\n* **Development Tools**: Includes tools and dependencies needed for development, not required in production.\n\nHere's the development Dockerfile:\n\n```dockerfile\n# Dockerfile.dev\n# syntax=docker/dockerfile:1\n\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\nWORKDIR /rails\n\n# Set development environment\nENV RAILS_ENV=\"development\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n\n# Install packages needed to build gems and development tools\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config nodejs yarn\n\n# Copy only the Gemfiles for installing gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use secret to access GitHub token for private repositories and install gems\nRUN --mount=type=secret,id=GITHUB_TOKEN \\\n    GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) \u0026\u0026 \\\n    git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n    bundle install\n\n# Copy the rest of the application code\nCOPY . .\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Start the server by default\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\", \"-b\", \"0.0.0.0\"]\n```\n\n### Writing the docker-compose.yml File\n\nThe `docker-compose.yml` file coordinates multiple services needed for the application. Here's the complete file, which includes configurations for the Rails app and PostgreSQL:\n\n```yaml\nservices:\n  app:\n    build:\n      context: .\n      dockerfile: Dockerfile.dev\n      secrets:\n        - GITHUB_TOKEN\n    environment:\n      DATABASE_URL: postgres://postgres:postgres@db:5432/pirate_app_development\n    ports:\n      - \"3000:3000\"\n    volumes:\n      - .:/rails\n    depends_on:\n      - db\n\n  db:\n    image: postgres:16\n    environment:\n      POSTGRES_USER: postgres\n      POSTGRES_PASSWORD: postgres\n      POSTGRES_DB: pirate_app_development\n    volumes:\n      - db_data:/var/lib/postgresql/data\n\nsecrets:\n  GITHUB_TOKEN:\n    environment: GITHUB_TOKEN\n\nvolumes:\n  db_data:\n```\n\n### Managing Environment Variables\n\nUsing `.env` files for environment-specific configurations helps in maintaining different settings for development and production environments. Docker Compose automatically reads the `.env` file located in the same directory as the `docker-compose.yml` file and uses the variables defined within it.\n\nEnsure your `.env` file contains the necessary environment variables:\n\n```env\n# .env\nGITHUB_TOKEN=\u003cyour-github-token\u003e\nSECRET_KEY_BASE=\u003cyour-secret-key-base\u003e\n```\n\n### Running the Development Environment with Docker Compose\n\nWith the `docker-compose.yml` and `.env` files set up, you can build and run the development environment using Docker Compose.\n\nTo build the services:\n\n```bash\ndocker compose build\n```\n\nTo start the services:\n\n```bash\ndocker compose up\n```\n\n\u003e Note: Use `docker compose up -d` to run the application in the background.\n\n### Summary\n\n* **Production Dockerfile**: Optimized for production with multi-stage builds, security considerations, and environment-specific configurations.\n* **Development Dockerfile (`Dockerfile.dev`)**: Tailored for development with necessary development tools and rapid iteration support.\n* **Docker Compose**: Simplifies the orchestration of the development environment, ensuring consistency and ease of setup.\n* **Environment Variables**: Managed using an `.env` file for secure and environment-specific configurations.\n\nBy following these instructions, you can effectively use Docker Compose to manage your development environment, leveraging the power of Docker to ensure consistency and ease of setup.\n\n## Chapter 5: Guarding Your Treasure – Using Private Dependencies\n\nAhoy, me hearties! Now that we've set up our Rails application, it's time to put our private packages to use. This chapter covers integrating private Ruby gems and npm packages into our Rails application.\n\n### Using Private Ruby Gems\n\nLet's use the private Ruby gem we created earlier in our Rails application (part of this will already be done if you were following along).\n\n1. **Add the Gem to Your Gemfile**:\n\n   ```ruby\n   gem 'my_private_gem', git: 'https://github.com/loftwah-demo/my_private_gem.git'\n   ```\n\n2. **Configure Bundler to Use the PAT**:\n\n   ```bash\n   bundle config https://github.com \u003cyour_github_token\u003e\n   ```\n\n3. **Install the Gem**:\n\n   ```bash\n   bundle install\n   ```\n\n4. **Use the Gem in Your Rails Application**: In `app/controllers/application_controller.rb`, add:\n\n   ```ruby\n   class ApplicationController \u003c ActionController::Base\n     def test_my_private_gem\n       render plain: MyPrivateGem.hello\n     end\n   end\n   ```\n\n5. **Add a Route to Test the Gem**: In `config/routes.rb`, add:\n\n   ```ruby\n   Rails.application.routes.draw do\n     get 'test_my_private_gem', to: 'application#test_my_private_gem'\n   end\n   ```\n\n6. **Verify the Gem is Working**: Start your Rails server and navigate to `http://localhost:3000/test_my_private_gem`. You should see:\n\n   ```plaintext\n   Hello from MyPrivateGem!\n   ```\n\n### Using Private npm Packages\n\nLet's integrate the private npm package into our Rails application.\n\n1. **Navigate to Your Rails Application Directory**:\n\n   ```bash\n   cd ../pirate_app\n   ```\n\n2. **Create a `package.json` File** (we may have already done this if you're following along):\n\n   ```bash\n   npm init -y\n   ```\n\n3. **Update `package.json` to Include the Private Package**:\n\n   ```json\n   {\n     \"name\": \"pirate_app\",\n     \"version\": \"1.0.0\",\n     \"dependencies\": {\n       \"my-private-npm-package\": \"git+https://github.com/loftwah-demo/my-private-npm-package.git\"\n     }\n   }\n   ```\n\n4. **Configure npm for Authentication**: Create an `.npmrc` file in your Rails application's root directory:\n\n   ```plaintext\n   //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}\n   ```\n\n5. **Install the Dependencies**:\n\n   ```bash\n   npm install\n   ```\n\n### Setting Up Vite for JavaScript Bundling\n\n1. **Install the `vite_rails` Gem**:\n\n   Add the `vite_rails` gem to your Gemfile:\n\n   ```ruby\n   gem 'vite_rails'\n   ```\n\n   Then run `bundle install`:\n\n   ```bash\n   bundle install\n   ```\n\n2. **Install Vite with Rails**:\n\n   Initialize Vite in your Rails application:\n\n   ```bash\n   bundle exec vite install\n   ```\n\n   Install npm dependencies and build the Vite project:\n\n   ```bash\n   npm ci\n   npx vite build\n   ```\n\n3. **Run Rails and Check**:\n\n   Start the Rails server and Vite development server:\n\n   ```bash\n   rails s\n   bin/vite dev\n   ```\n\n1. **Shut Down Rails and Vite**:\n\n   Before proceeding, shut down the Rails server and Vite development server by pressing `Ctrl+C` in the terminal where they are running.\n\n2. **Install Foreman (Development Only)**:\n\n   Foreman is a tool to manage Procfile-based applications. Add it to your Gemfile for the development group:\n\n   ```ruby\n   group :development do\n     gem 'foreman'\n   end\n   ```\n\n   Then run `bundle install`:\n\n   ```bash\n   bundle install\n   ```\n\n3. **Set Up `Procfile.dev`**:\n\n   If not already present, create a `Procfile.dev` in the root of your project directory with the following content:\n\n   ```bash\n   web: bin/rails server\n   css: bin/rails tailwindcss:watch\n   vite: bin/vite dev\n   ```\n\n4. **Run Foreman**:\n\n   Use Foreman to start all processes defined in `Procfile.dev`:\n\n   ```bash\n   bin/bundle exec foreman start -f Procfile.dev\n   ```\n\nThis will start your Rails server, Tailwind CSS watcher, and Vite development server all at once, making your development workflow more efficient.\n\n5. **Shut Down Foreman**:\n\n   Before proceeding, shut down Foreman and any running processes by pressing `Ctrl+C` in the terminal where they are running.\n\n6. **Update `docker-compose.yml`**:\n\n   To run the necessary processes using Docker, update your `docker-compose.yml` file as follows:\n\n   ```yaml\n   services:\n     web:\n       build:\n         context: .\n         dockerfile: Dockerfile.dev\n         secrets:\n           - GITHUB_TOKEN\n       environment:\n         SECRET_KEY_BASE: ${SECRET_KEY_BASE}\n         DATABASE_URL: postgres://postgres:postgres@db:5432/pirate_app_development\n       ports:\n         - \"3000:3000\"\n       volumes:\n         - .:/rails\n       depends_on:\n         - db\n       command: bin/rails server -b 0.0.0.0\n\n     vite:\n       build:\n         context: .\n         dockerfile: Dockerfile.dev\n         secrets:\n           - GITHUB_TOKEN\n       volumes:\n         - .:/rails\n       depends_on:\n         - web\n       command: bin/vite dev\n\n     db:\n       image: postgres:16\n       environment:\n         POSTGRES_USER: postgres\n         POSTGRES_PASSWORD: postgres\n         POSTGRES_DB: pirate_app_development\n       volumes:\n         - db_data:/var/lib/postgresql/data\n\n   secrets:\n     GITHUB_TOKEN:\n       environment: GITHUB_TOKEN\n\n   volumes:\n     db_data:\n   ```\n\n   \u003e Note: I use `foreman` to develop locally and this is my preference, with `docker compose` being a secondary option.\n\n### Summary\n\nYou've successfully set up Vite with Rails using the `vite_rails` gem and integrated your development environment to use Docker for managing multiple processes. This setup ensures that your JavaScript is bundled correctly and can take advantage of Vite's features.\n\n### Next Steps\n\nIn the next chapter, we’ll dive into secure authentication with SSH and HTTPS, managing secrets, and using GitHub Personal Access Tokens (PATs) for secure access. Stay the course, and you'll be a Rails and DevOps expert in no time!\n\n## Chapter 6: Secure Authentication with SSH and HTTPS\n\n### Ahoy, Mateys! Welcome to the Treasure of Secure Authentication\n\n### SSH Key Management\n\n#### Setting up and Using SSH Keys in Docker\n\nArrr, ye landlubbers, we be needin' to set sail with secure authentication using SSH keys in Docker. Here be the steps to hoist the Jolly Roger and fetch private treasures (repositories):\n\n1. **Generate an SSH Key**: We be generatin' a new key so we don’t mess with yer existing `id_rsa`.\n\n   ```bash\n   ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_pirate_key -C \"your_email@example.com\"\n   ```\n\n   This command creates a new key pair (`id_pirate_key` and `id_pirate_key.pub`).\n\n2. **Add the SSH Key to Your SSH Agent**: The SSH agent be a daemon that holds yer private keys in memory. We be usin' it so yer private keys don’t be needin’ to be entered every time.\n\n   ```bash\n   eval $(ssh-agent -s)\n   ssh-add ~/.ssh/id_pirate_key\n   ```\n\n3. **Add Your SSH Key to GitHub**: Copy the public key to yer clipboard and add it to yer GitHub account.\n\n   ```bash\n   cat ~/.ssh/id_pirate_key.pub\n   ```\n\n#### Configuring SSH for Accessing Private Repositories\n\nSwab the decks and prepare to clone private repositories using SSH mounts in Docker. This be the Dockerfile we be usin' to fetch our private treasures.\n\n### Dockerfile for SSH Authentication\n\n```Dockerfile\n# syntax=docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\n# Rails app lives here\nWORKDIR /rails\n\n# Set production environment\nENV RAILS_ENV=\"production\" \\\n    BUNDLE_DEPLOYMENT=\"1\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n    BUNDLE_WITHOUT=\"development\"\n\n# Throw-away build stage to reduce size of final image\nFROM base AS build\n\n# Install packages needed to build gems\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config openssh-client\n\n# Add SSH key to the build environment\nADD id_pirate_key /root/.ssh/id_pirate_key\nRUN chmod 600 /root/.ssh/id_pirate_key \u0026\u0026 \\\n    ssh-keyscan github.com \u003e\u003e /root/.ssh/known_hosts\n\n# Install application gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use SSH to access private GitHub repo\nRUN --mount=type=ssh \\\n    GIT_SSH_COMMAND='ssh -i /root/.ssh/id_pirate_key' bundle install \u0026\u0026 \\\n    rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n    bundle exec bootsnap precompile --gemfile\n\n# Copy application code\nCOPY . .\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Precompiling assets for production without requiring secret RAILS_MASTER_KEY\nRUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile\n\n# Final stage for app image\nFROM base\n\n# Install packages needed for deployment\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y curl libvips postgresql-client \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists /var/cache/apt/archives\n\n# Copy built artifacts: gems, application\nCOPY --from=build /usr/local/bundle /usr/local/bundle\nCOPY --from=build /rails /rails\n\n# Run and own only the runtime files as a non-root user for security\nRUN useradd rails --create-home --shell /bin/bash \u0026\u0026 \\\n    chown -R rails:rails db log storage tmp\nUSER rails:rails\n\n# Entrypoint prepares the database.\nENTRYPOINT [\"/rails/bin/docker-entrypoint\"]\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\"]\n```\n\n### Explanation\n\n1. **Generate and Add SSH Key**: We create a new SSH key named `id_pirate_key` to avoid conflicts with existing keys. This key be added to yer SSH agent for secure use.\n2. **SSH Agent**: The SSH agent keeps yer keys in memory, makin' it easy to use 'em without repeatedly enterin' the passphrase.\n3. **Dockerfile**: We be usin' an `ADD` command to include the SSH key in the Docker build environment and `RUN --mount=type=ssh` to securely clone private repositories.\n\n### Why Use SSH?\n\n* **Alternative to PAT**: While we typically use PATs for secure access, SSH keys offer another method for those who prefer it.\n* **Automation**: Docker builds with SSH mounts allow seamless access to private repositories without manual intervention.\n\nWith this knowledge, ye be ready to set sail with secure SSH authentication in Docker. Remember, a true pirate guards his keys well and uses them wisely to fetch the richest treasures from the seas of code!\n\n\u003e Note: I tend to avoid using SSH in my Docker images and containers.\n\n## Chapter 7: CI/CD – Automating Your Deployment\n\n### Introduction to CI/CD\n\nAhoy, mateys! In this chapter, we'll dive into the importance of Continuous Integration (CI) and Continuous Deployment (CD). These practices ensure that your code is always in a deployable state, making it easier to catch bugs early and deploy new features quickly and reliably.\n\n**Why CI/CD?**\n\n* **Consistency**: Ensures code changes are integrated and tested frequently.\n* **Speed**: Automates the deployment process, reducing manual effort and errors.\n* **Quality**: Enhances code quality through automated testing and validation.\n\n### Setting Up RSpec Locally\n\n1. **Add RSpec to your `Gemfile`**:\n\n   ```ruby\n   group :development, :test do\n     gem \"rspec-rails\"\n   end\n\n   group :test do\n     gem \"capybara\"\n     gem \"selenium-webdriver\"\n     gem \"factory_bot_rails\"\n     gem \"faker\"\n   end\n   ```\n\n2. **Install the gems**:\n\n   ```bash\n   bundle install\n   ```\n\n3. **Generate RSpec configuration**:\n\n   ```bash\n   rails generate rspec:install\n   ```\n\n4. **Run RSpec to ensure it's set up correctly**:\n\n   ```bash\n   bundle exec rspec\n   ```\n\n### Setting Up GitHub Actions for CI/CD\n\n1. **Create a GitHub Actions Workflow**:\n\n   * Create a new file in the `.github/workflows` directory named `ci.yml`.\n\n2. **Define the Workflow for Testing**:\n\n   ```yaml\n   name: CI\n\n   on:\n     push:\n       branches:\n         - main\n     pull_request:\n       branches:\n         - main\n\n   jobs:\n     test:\n       runs-on: ubuntu-latest\n\n       services:\n         postgres:\n           image: postgres:16\n           ports:\n             - 5432:5432\n           env:\n             POSTGRES_DB: pirate_app_test\n             POSTGRES_USER: postgres\n             POSTGRES_PASSWORD: postgres\n\n       steps:\n         - uses: actions/checkout@v4\n\n         - name: Set up Ruby\n           uses: ruby/setup-ruby@v1\n           with:\n             ruby-version: 3.3.0\n\n         - name: Install dependencies\n           env:\n             BUNDLE_GITHUB__COM: ${{ secrets.GH_PAT }}\n           run: |\n             gem install bundler\n             bundle config set --local github.com \"x-access-token:${{ secrets.GH_PAT }}\"\n             bundle install\n\n         - name: Set up database\n           run: |\n             bundle exec rails db:create db:migrate\n           env:\n             RAILS_ENV: test\n             POSTGRES_USER: postgres\n             POSTGRES_PASSWORD: postgres\n\n         - name: Run tests\n           run: bundle exec rspec\n           env:\n             RAILS_ENV: test\n   ```\n\n3. **Add `GH_PAT` as a Repository Secret**:\n\n   * Navigate to your GitHub repository.\n   * Go to `Settings` \u003e `Secrets and variables` \u003e `Actions`.\n   * Click `New repository secret`.\n   * Name it `GH_PAT` and paste your personal access token.\n   * Ensure the token has `repo` and `package:read` scopes.\n\n### Explanation\n\n1. **Create a GitHub Actions Workflow**:\n\n   * Create a new file named `ci.yml` in the `.github/workflows` directory.\n\n2. **Define the Workflow for Testing**:\n\n   * Use `actions/checkout@v4` to ensure compatibility with the latest Node.js versions.\n   * Use `ruby/setup-ruby@v1` to set up Ruby 3.3.0.\n   * Use `BUNDLE_GITHUB__COM` environment variable to authenticate with the personal access token (`GH_PAT`).\n   * Install dependencies with `bundle install`.\n   * Set up the database with `bundle exec rails db:create db:migrate`.\n   * Run tests with `bundle exec rspec`.\n\n3. **Add `GH_PAT` as a Repository Secret**:\n\n   * Ensure the personal access token has the necessary permissions and add it as a secret to your repository.\n\nBy following these steps, you'll ensure that your CI/CD pipeline is set up correctly to test your Rails application with RSpec, and that your private gem repository is accessible using the provided personal access token.\n\n#### Best Practices for Secure and Efficient CI/CD Pipelines\n\n* **Secrets Management**: Store sensitive information like API keys and database passwords securely using GitHub Secrets.\n* **Environment Variables**: Use environment variables for configuration settings.\n* **Caching Dependencies**: Cache dependencies to speed up the build process.\n\n### Deploying with GitHub Actions and DigitalOcean using `doctl`\n\nTo automate the deployment of your Rails application, we'll use `doctl` to manage DigitalOcean and GitHub Actions to handle the deployment process.\n\n#### Setting Up `doctl` for DigitalOcean\n\n1. **Install `doctl`:**\n\n   * On macOS:\n\n     ```bash\n     brew install doctl\n     ```\n\n   * On Ubuntu:\n\n     ```bash\n     snap install doctl\n     ```\n\n   * Download and install from [GitHub](https://github.com/digitalocean/doctl/releases) for other systems.\n\n2. **Create a DigitalOcean API Token:**\n\n   * Go to the DigitalOcean [API page](https://cloud.digitalocean.com/account/api/tokens) and create a new token with read and write access.\n   * Save the token securely as it will be needed to authenticate `doctl`.\n\n3. **Authenticate `doctl`:**\n\n   ```bash\n   doctl auth init\n   ```\n\n   * Follow the prompts to enter your API token.\n\n* **Generate SSH Keys:**\n\n  If you don't already have SSH keys, you can generate them using the following command:\n\n  ```bash\n  ssh-keygen -t rsa -b 4096 -C \"your_email@example.com\"\n  ```\n\n  * Follow the prompts to save the keys in the default location (`~/.ssh/id_rsa`).\n\n* **Add SSH Key to DigitalOcean:**\n\n  ```bash\n  doctl compute ssh-key import loftwah --public-key-file ~/.ssh/id_rsa.pub\n  ➜  pirate_app git:(main) doctl compute ssh-key import loftwah --public-key-file ~/.ssh/id_rsa.pub\n  ID          Name       FingerPrint\n  42754072    loftwah    76:a5:d8:77:d2:86:52:14:f7:ea:9b:b6:94:f2:b7:fc\n  ```\n\n  \u003e Note: The ID from here is what you need below as \u003cSSH-KEY-ID\u003e.\n\n  * Replace `\u003cKEY-NAME\u003e` with a name for your SSH key.\n\n* **Create a Droplet:**\n\n  ```bash\n  doctl compute droplet create \u003cDROPLET-NAME\u003e --region syd1 --image ubuntu-22-04-x64 --size s-1vcpu-1gb --ssh-keys \u003cSSH-KEY-ID\u003e --wait\n  ```\n\n  * Replace `\u003cDROPLET-NAME\u003e` with your desired droplet name.\n  * Replace `\u003cSSH-KEY-ID\u003e` with your SSH key ID. You can find this by running `doctl compute ssh-key list`.\n\n  ```bash\n  doctl compute droplet create pirateapp --region syd1 --image ubuntu-22-04-x64 --size s-1vcpu-1gb --ssh-keys 42754072 --wait\n  ```\n\n  It will give you the following output or you can use the below command to retrieve the IP address if you need it.\n\n  ```bash\n    pirate_app git:(main) doctl compute droplet create pirateapp --region syd1 --image ubuntu-22-04-x64 --size s-1vcpu-1gb --ssh-keys 42754072 --wait\n    ID           Name         Public IPv4       Private IPv4    Public IPv6    Memory    VCPUs    Disk    Region    Image                     VPC UUID                                Status    Tags    Features                            Volumes\n    432279856    pirateapp    170.69.169.169    10.126.0.2                     1024      1        25      syd1      Ubuntu 22.04 (LTS) x64    102fec11-b9ca-4d95-9870-9619086e2408    active            droplet_agent,private_networking\n  ```\n\n* **Retrieve Droplet IP:**\n\n  ```bash\n  doctl compute droplet list\n  ```\n\n  * Note down the IP address of your newly created droplet.\n\n* **Delete your instance if you're not ready to use it**\n\n```bash\ndoctl compute droplet delete pirateapp -f\n```\n\n* ** If you are ready connect to the instance with SSH**\n\n```bash\nssh -i ~/.ssh/id_rsa root@\u003cyour-ip\u003e\n```\n\n### Configuring Your Droplet for Docker\n\n#### 1. Connect to Your Droplet\n\n```bash\nssh -i ~/.ssh/id_rsa root@\u003cyour-ip\u003e\n```\n\n#### 2. Update and Upgrade System\n\n```bash\nsudo apt-get update \u0026\u0026 sudo apt-get upgrade -y\n```\n\n#### 3. Install Docker Using the Script\n\n```bash\n# Download the Docker installation script\ncurl -fsSL https://get.docker.com -o install-docker.sh\n\n# Verify the script's content (optional but recommended)\ncat install-docker.sh\n\n# Run the script with --dry-run to verify the steps it executes (optional)\nsh install-docker.sh --dry-run\n\n# Run the script to install Docker\nsudo sh install-docker.sh\n```\n\n#### 4. Start Docker and Enable on Boot\n\n```bash\nsudo systemctl start docker\nsudo systemctl enable docker\n```\n\n#### 5. Add Your User to Docker Group\n\n```bash\nsudo usermod -aG docker ${USER}\nsu - ${USER}\n```\n\n#### 6. Verify Installations\n\n```bash\n# Check Docker\ndocker --version\ndocker run hello-world\n```\n\n### Vite in Docker\n\nIf you have been following along we have broken our `Dockerfile` for production. I will go through and figure this out but for now we will have this section that explains what we need for it to build properly for Vite. Please update your `Dockerfile` to the following.\n\n```dockerfile\n# syntax=docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\n# Rails app lives here\nWORKDIR /rails\n\n# Set production environment\nENV RAILS_ENV=\"production\" \\\n    BUNDLE_DEPLOYMENT=\"1\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n    BUNDLE_WITHOUT=\"development\"\n\n# Throw-away build stage to reduce size of final image\nFROM base AS build\n\n# Install packages needed to build gems and Node.js\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config curl \u0026\u0026 \\\n    curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \u0026\u0026 \\\n    apt-get install --no-install-recommends -y nodejs\n\n# Install application gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use secret to access GitHub token\nRUN --mount=type=bind,target=. \\\n    --mount=type=secret,id=GITHUB_TOKEN \\\n    GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) \u0026\u0026 \\\n    git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n    bundle install \u0026\u0026 \\\n    rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n    bundle exec bootsnap precompile --gemfile\n\n# Install Node.js packages\nCOPY package.json package-lock.json ./\nRUN npm install\n\n# Copy application code\nCOPY . .\n\n# Run Vite build\nRUN npx vite build\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Precompiling assets for production without requiring secret RAILS_MASTER_KEY\nRUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile\n\n# Final stage for app image\nFROM base\n\n# Install packages needed for deployment\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y curl libvips postgresql-client \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists /var/cache/apt/archives\n\n# Copy built artifacts: gems, application\nCOPY --from=build /usr/local/bundle /usr/local/bundle\nCOPY --from=build /rails /rails\n\n# Run and own only the runtime files as a non-root user for security\nRUN useradd rails --create-home --shell /bin/bash \u0026\u0026 \\\n    chown -R rails:rails db log storage tmp\nUSER rails:rails\n\n# Entrypoint prepares the database.\nENTRYPOINT [\"/rails/bin/docker-entrypoint\"]\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\"]\n```\n\n### Setting Up Docker Compose\n\nInstead of running on the system directly we can run the application using Docker Compose. Create a `docker-compose.yml` file in your application directory:\n\n\u003e Note: This is on the droplet you will be deploying to.\n\n```yaml\nservices:\n  db:\n    image: postgres:16\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n    environment:\n      POSTGRES_DB: pirate_app_production\n      POSTGRES_USER: pirate_app\n      POSTGRES_PASSWORD: ${PIRATE_APP_DATABASE_PASSWORD}\n\n  redis:\n    image: redis:7\n\n  web:\n    build: .\n    command: bundle exec rails server -b 0.0.0.0\n    volumes:\n      - .:/rails\n    ports:\n      - \"80:3000\"\n    environment:\n      RAILS_ENV: production\n      SECRET_KEY_BASE: ${SECRET_KEY_BASE}\n      DATABASE_URL: postgres://pirate_app:${PIRATE_APP_DATABASE_PASSWORD}@db:5432/pirate_app_production\n      REDIS_URL: redis://redis:6379/1\n    depends_on:\n      - db\n      - redis\n\nvolumes:\n  postgres_data:\n```\n\n### Setting Up GitHub Actions\n\nCreate a GitHub Actions workflow file (e.g., `.github/workflows/deploy.yml`):\n\n```yaml\nname: Deploy\n\non:\n  workflow_run:\n    workflows: [\"CI\"]\n    types:\n      - completed\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    if: ${{ github.event.workflow_run.conclusion == 'success' }}\n\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@v4\n\n    - name: Set up Docker Buildx\n      uses: docker/setup-buildx-action@v2\n\n    - name: Login to GitHub Container Registry\n      uses: docker/login-action@v2\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GH_PAT }}\n\n    - name: Build and push Docker image\n      run: |\n        echo \"${{ secrets.GH_PAT }}\" | docker login ghcr.io -u ${{ github.actor }} --password-stdin\n        GITHUB_TOKEN=${{ secrets.GH_PAT }} docker buildx build --secret id=GITHUB_TOKEN -t ghcr.io/loftwah-demo/pirate_app/pirateapp:latest --push .\n\n    - name: Deploy to droplet\n      uses: appleboy/ssh-action@master\n      with:\n        host: 170.64.189.40\n        username: root\n        key: ${{ secrets.DROPLET_SSH_PRIVATE_KEY }}\n        script: |\n          echo \"${{ secrets.GH_PAT }}\" | docker login ghcr.io -u ${{ github.actor }} --password-stdin\n          docker compose -f /root/docker-compose.prod.yml --env-file /root/.env down\n          docker compose -f /root/docker-compose.prod.yml --env-file /root/.env pull\n          docker compose -f /root/docker-compose.prod.yml --env-file /root/.env up -d\n```\n\n### Setting Up Environment Variables in GitHub Secrets\n\nAdd the following secrets to your GitHub repository:\n\n* `GH_PAT`\n* `DROPLET_SSH_PRIVATE_KEY`\n* `PIRATE_APP_DATABASE_PASSWORD`\n* `SECRET_KEY_BASE`\n\n#### How to Add Secrets:\n\n* **GITHUB\\_TOKEN**:\n\n  1. Go to your GitHub profile.\n  2. Navigate to Settings \u003e Developer settings \u003e Personal access tokens.\n  3. Generate a new token with `repo` and `write:packages` permissions.\n  4. Copy the token and add it as a secret in your repository settings.\n\n* **DIGITALOCEAN\\_API\\_TOKEN**:\n\n  1. Go to the DigitalOcean [API page](https://cloud.digitalocean.com/account/api/tokens) and create a new token.\n  2. Copy the token and add it as a secret in your repository settings.\n\n* **DIGITALOCEAN\\_SSH\\_KEY\\_ID**:\n\n  1. Add the public key to your DigitalOcean account under Security \u003e SSH Keys.\n  2. Retrieve the key ID using `doctl compute ssh-key list`.\n  3. Add the key ID as a secret in your repository settings.\n\n\u003e Note: Your application should be deployed but because we deployed the production environment we require a secure connection. You can modify the Rails config in your application if you want to see this in `config/environments/production.rb` where you need to change `config.force_ssl = false`. For info: I ended up updating this in my repo because it is only a demo application and who cares right? We can still set up SSL with this set to `false`.\n\n### Summary\n\nBy following these steps, you can set up a CI/CD pipeline with GitHub Actions and automate the deployment of your Rails application on DigitalOcean using `doctl` and GitHub Container Registry. This approach simplifies the deployment process, making it easier to manage infrastructure and deploy updates efficiently. Happy sailing, and may your deployments be swift and smooth!\n\n## Chapter 8: Advanced Docker Techniques\n\n### Ahoy, Mateys! The Secrets of Multi-Stage Builds\n\n**Benefits of Multi-Stage Builds for Docker Images**\n\nArrr, ye scallywags, gather 'round and lend an ear! The seas be rough, and our ship must be lean and mean. Multi-stage builds be our secret weapon, a true marvel of Docker wizardry. By breakin' down our build into stages, we be savin' space and keepin' our final image as trim as a corsair’s blade. No more bloatin' with unnecessary artifacts, aye, just the essentials to sail smooth and fast.\n\n**Implementin' Multi-Stage Builds in Your Dockerfile**\n\nTo start, ye be needin' a Dockerfile more cunning than a fox in a henhouse. First, we be usin' one stage to build our treasures, then another to copy only the finest loot into our final image. Here be an example from the ship’s log:\n\n```Dockerfile\n# syntax=docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_VERSION=3.3.0\nFROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base\n\n# Rails app lives here\nWORKDIR /rails\n\n# Set production environment\nENV RAILS_ENV=\"production\" \\\n    BUNDLE_DEPLOYMENT=\"1\" \\\n    BUNDLE_PATH=\"/usr/local/bundle\" \\\n    BUNDLE_WITHOUT=\"development\"\n\n# Throw-away build stage to reduce size of final image\nFROM base AS build\n\n# Install packages needed to build gems and Node.js\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config curl \u0026\u0026 \\\n    curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \u0026\u0026 \\\n    apt-get install --no-install-recommends -y nodejs\n\n# Install application gems\nCOPY Gemfile Gemfile.lock ./\n\n# Use secret to access GitHub token\nRUN --mount=type=bind,target=. \\\n    --mount=type=secret,id=GITHUB_TOKEN \\\n    GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) \u0026\u0026 \\\n    git config --global url.\"https://${GITHUB_TOKEN}@github.com/\".insteadOf \"https://github.com/\" \u0026\u0026 \\\n    bundle install \u0026\u0026 \\\n    rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git \u0026\u0026 \\\n    bundle exec bootsnap precompile --gemfile\n\n# Install Node.js packages\nCOPY package.json package-lock.json ./\nRUN npm install\n\n# Copy application code\nCOPY . .\n\n# Run Vite build\nRUN npx vite build\n\n# Precompile bootsnap code for faster boot times\nRUN bundle exec bootsnap precompile app/ lib/\n\n# Precompiling assets for production without requiring secret RAILS_MASTER_KEY\nRUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile\n\n# Final stage for app image\nFROM base\n\n# Install packages needed for deployment\nRUN apt-get update -qq \u0026\u0026 \\\n    apt-get install --no-install-recommends -y curl libvips postgresql-client \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists /var/cache/apt/archives\n\n# Copy built artifacts: gems, application\nCOPY --from=build /usr/local/bundle /usr/local/bundle\nCOPY --from=build /rails /rails\n\n# Run and own only the runtime files as a non-root user for security\nRUN useradd rails --create-home --shell /bin/bash \u0026\u0026 \\\n    chown -R rails:rails db log storage tmp\nUSER rails:rails\n\n# Entrypoint prepares the database.\nENTRYPOINT [\"/rails/bin/docker-entrypoint\"]\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 3000\nCMD [\"./bin/rails\", \"server\"]\n\n# Build command\nGITHUB_TOKEN=\u003cmy-token\u003e docker buildx build --secret id=GITHUB_TOKEN -t pirate_app .\n# Run command\ndocker run -e SECRET_KEY_BASE=\u003cmy-key\u003e -p 3000:3000 pirate_app\n```\n\nWith this strategy, our final image be as swift as a schooner, ready to plunder the seven seas!\n\n### Docker Volumes and Networks: Keepin' Our Booty Safe and Secure\n\n**Managing Data Persistence with Docker Volumes**\n\nAye, the life of a pirate be full of treasures, and we must keep 'em safe! Docker volumes be our chests to store precious data. They be independent of the container lifecycle, so our treasures don't disappear into the briny deep when a container meets Davy Jones. Here’s how ye be creatin' a volume:\n\n```bash\ndocker volume create my_volume\n```\n\nMount it in yer container like so:\n\n```bash\ndocker run -v my_volume:/path/in/container my_image\n```\n\nNow, our loot be safe and sound, even if the seas get stormy!\n\n**Purging Data and Considerations**\n\nBut beware, ye don’t want to be caught with too much ballast! When the time comes to purge old data, make sure ye know what ye be doin'. Deleting a volume be permanent, like sendin' it to the depths of the ocean. To remove a volume:\n\n```bash\ndocker volume rm my_volume\n```\n\nThink twice before ye hit that command, or ye might be losin' vital booty.\n\n**Configurin' Docker Networks for Inter-Container Communication**\n\nTo navigate the vast waters of inter-container communication, Docker networks be our charts and compass. Ye can set up a bridge network for yer containers to talk like old sea dogs:\n\n```bash\ndocker network create my_network\n```\n\nRun yer containers on this network:\n\n```bash\ndocker run --network my_network --name container_one my_image\ndocker run --network my_network --name container_two my_image\n```\n\nNow, `container_one` and `container_two` be chattin' like old mates in a tavern, sharin' secrets and plans for their next big raid.\n\nSo there ye have it, me hearties! Master these advanced Docker techniques, and ye'll be the scourge of the seven seas, feared by all and master of your digital domain! Arrr!\n\n## Chapter 9: Monitoring and Scaling Your Application\n\n### Avast, Me Hearties! Application Monitoring on the High Seas\n\n**Tools and Techniques for Monitoring a Rails Application**\n\nAhoy, ye salty dogs! Keepin' a sharp eye on yer Rails application be as crucial as watchin' the horizon for enemy ships. Here be a list of fine tools to help ye monitor the health and performance of yer app:\n\n* **Raygun**: Catch errors and crashes faster than a cannonball flyin' across the deck. Raygun gives ye detailed reports on where yer app be takin' on water.\n* **Honeybadger**: Another trusty tool for error trackin', Honeybadger also keeps an eye on uptime and alertin' ye when things go awry.\n* **Axiom**: For log aggregation and analysis, Axiom be the tool to gather all yer logs into one treasure chest for easy searchin' and visualizin'.\n* **Datadog**: A full fleet of monitorin' services, includin' metrics, traces, and logs. Datadog helps ye keep tabs on every corner of yer app.\n* **Vector**: A log processor that sails smoothly, collectin', processin', and transportin' yer logs to where they need to be.\n\nSettin' up these tools be a task for a seasoned quartermaster. Configure 'em properly to ensure they be reportin' accurate and useful information.\n\n**Logging at the Application and System Level**\n\nLoggin' be the ship’s log of yer application. At the application level, log errors, warnings, and key events to understand the state of yer app. System-level logging captures events at the OS level, such as resource usage and network activity. Together, they paint a full picture of yer ship’s health.\n\n```ruby\n# Rails example for logging\nRails.logger.info \"Shiver me timbers! This be a log message.\"\n```\n\n### Scaling with Docker and Cloud: Unfurl the Sails!\n\n**Strategies for Scaling Your Application Using Docker and Cloud Services**\n\nScalin' yer application be like addin' more sails to catch the wind. Docker and cloud services be the wind in those sails, helpin' ye handle more traffic without capsizin'. Here be some strategies:\n\n* **Container Orchestration**: Tools like Kubernetes and Docker Swarm manage yer fleet of containers, deployin' and scalin' 'em as needed.\n* **Load Balancin'**: Distribute incoming requests across multiple containers or instances to ensure smooth sailin'.\n* **Microservices**: Break yer monolithic application into smaller services that can be scaled independently.\n\nHere be an example of a `docker-compose.yml` file that scales yer Rails app with PostgreSQL and Redis:\n\n```yaml\nservices:\n  db:\n    image: postgres:16\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n    environment:\n      POSTGRES_DB: pirate_app_production\n      POSTGRES_USER: pirate_app\n      POSTGRES_PASSWORD: ${PIRATE_APP_DATABASE_PASSWORD}\n    ports:\n      - \"5432:5432\"\n\n  redis:\n    image: redis:7\n    ports:\n      - \"6379:6379\"\n\n  web:\n    build: .\n    command: bundle exec rails server -b 0.0.0.0\n    volumes:\n      - .:/rails\n    ports:\n      - \"3000:3000\"\n    environment:\n      RAILS_ENV: production\n      SECRET_KEY_BASE: ${SECRET_KEY_BASE}\n      DATABASE_URL: postgres://pirate_app:${PIRATE_APP_DATABASE_PASSWORD}@db:5432/pirate_app_production\n      REDIS_URL: redis://redis:6379/1\n    depends_on:\n      - db\n      - redis\n\nvolumes:\n  postgres_data:\n```\n\n**Auto-Scaling and Load Balancin' Considerations**\n\nAuto-scaling keeps yer ship ready for any storm, addin' or removin' resources based on demand. Cloud providers like AWS, Azure, and Google Cloud offer auto-scaling services. Configure yer auto-scaling policies to match yer needs, considerin' metrics like CPU usage, memory, and req","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floftwah-demo%2Flinux-for-pirates-2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floftwah-demo%2Flinux-for-pirates-2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floftwah-demo%2Flinux-for-pirates-2/lists"}