首页 >数据库 >mysql教程 >使用 Docker 和 MySQL 设置新的 Rails 应用程序

使用 Docker 和 MySQL 设置新的 Rails 应用程序

Barbara Streisand
Barbara Streisand原创
2025-01-04 18:36:44212浏览

我是一家中型技术和数据公司的高级软件工程师。从历史上看,我曾担任过很多职务:我构建了客户获取流程,完成了数据库管理,复杂的 React 工作,为内部使用精心设计了功能齐全的 CMS,从头开始构建了面向公众的 Golang API 微服务,精心设计了 API 身份验证系统,交付了各种 B2B 和 B2C 产品,(同时)担任多个团队的技术主管等等。目前,我对于从头开始构建新的 Rails 应用程序还缺乏实践。所以我想我应该尝试一下!

这是一个非常基本的教程,但我发现缺乏实用指南。话虽这么说,我确实想大声说出我在写这篇文章时大量借用的两个教程——将其视为这些帖子加上我个人喜好的综合:Tallan Groberg 和 Nicolas Iensen。我们将避开很多细节,以便直接进入。我使用全新的 M4 Macbook Pro 来编写本文,但基础知识应该适用于大多数 Mac 或 Linux 环境。

我们将构建一个简单的 Ruby 应用程序,它使用 Rails 作为主框架,使用 MySQL 作为数据库(部分是因为它的功能,部分是为了增加我在这篇文章中的目标的复杂性),以及 Docker用于虚拟化和跨平台兼容性。在本教程中,我们不会构建任何模型或控制器:这都是关于设置的。在本教程结束时,您将拥有一个非常经典的 Hello World 应用程序。您应该能够掌握这个基本概念并将其应用到您正在构建的任何应用程序中。

入门

首先,这假设您对终端和基于 Unix 的计算机有一定的熟悉。如果这在某种程度上有意义,那么您将需要安装 Docker 和 Homebrew(假设您使用的是 Mac)。如果您运行 zsh 作为主 shell(现在大多数 Mac 都是默认的),您可能需要将以下内容添加到 ~/.zshrc 文件中以便能够运行 brew 命令:

path+=/opt/homebrew/bin

保存文件后,运行 source ~/.zshrc 就可以了!

小提示:以 $ 为前缀的命令表示在本地 shell(最有可能是 zsh 或 bash)中运行的命令,而以 # 为前缀的命令在 Docker 容器内运行。在所有情况下,不应复制前缀,它只是新行提示的视觉指示符。

首先要事

许多开发人员将所有编码项目放入一个目录中(我的项目是“下载”和“文档”目录的同级目录,我创造性地将其称为“代码”)。在终端中,导航到等效目录并键入以下命令:

$ mkdir my-app
$ cd my-app

在这个新目录中,我们需要一些新文件。使用以下命令创建它们:

path+=/opt/homebrew/bin

首先,Dockerfile.dev 将创建您的基础 Docker 映像,在现有映像的基础上构建,该映像安装了我们将用于此项目的 Ruby 版本(撰写本文时最新版本为 3.3.6)并进行设置关于该图像应如何表现的一些小细节。文件名的 .dev 部分表示该 Dockerfile 仅在本地使用,而不是在生产环境中使用。我们在本教程后面运行的命令实际上将为我们构建一个更强大的生产就绪 Dockerfile,我希望能够区分这两者。鉴于本教程的范围,我们并不担心这些细节。将以下行添加到该文件中:

$ mkdir my-app
$ cd my-app

接下来是 docker-compose.yml 文件:它的目的是将多个 Docker 容器协调在一起,以确保我们正在构建的 Web 应用程序的所有组成部分都可以一起通信:Web 服务器、数据库、潜在的Redis 服务器,也许是 Elasticsearch 服务器等。所有这些不同的元素都将存在于它们自己的“虚拟计算机”中,并且需要以模仿生产环境的方式进行连接以相互通信。理论知识已经足够了,重要的是我们需要向 docker-compose.yml 文件添加一些配置代码:

$ touch Dockerfile.dev
$ touch docker-compose.yml
$ touch Gemfile

不用担心细节,但它基本上是在说“当你运行这个程序时,你将运行一个名为“web”的应用程序,它将尝试使用一个名为“Dockerfile.dev”的 dockerfile 构建主应用程序' 并将 docker 系统网络中的内部端口 3000 映射到其运行的本地计算机的端口 3000 哦,而且,启动数据库并允许它们相互通信。”或者类似的东西。如果您已经在端口 3000 上运行应用程序,请随意将左侧端口号更改为您喜欢的任何端口号。

好的!现在我们有一个文件将构建一个图像,另一个文件将使用该图像运行容器并将其弹出到它启动的小网络中。好的!但是...我们该怎么做呢?

进入其中

为了开始清理,我们需要实际进入我们正在构建的容器中做一些事情。我们通过运行以下命令来做到这一点:

FROM ruby:3.3.6

WORKDIR /usr/src/app

COPY . .
RUN bundle install

现在我们在计算机中。我们的想法是,现在我们可以在容器的环境中运行命令,而无需在我们正在使用的计算机上安装某些软件。例如,Rails 不需要存在于计算机上的任何位置即可在计算机上运行的 Docker 容器上运行。很漂亮。

好吧,现在我们已经开始了,让我们安装 Rails:

services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: app
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3307:3306"
  web:
    build:
      context: .
      dockerfile: Dockerfile.dev
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - ".:/usr/src/app"
    ports:
      - "3000:3000"
    depends_on:
      - db
    links:
      - db
    environment:
      DB_USER: root
      DB_NAME: app
      DB_PASSWORD: password
      DB_HOST: db

现在让我们创建我们的应用程序!我们想使用 MySQL 构建此应用程序,因此请在以下命令中记下其规范:

path+=/opt/homebrew/bin

这需要一点时间。系统会询问您是否要覆盖 Gemfile。按 y 确认。对于此命令生成的任何其他文件,系统都会询问您同样的问题。相应地使用 y/n 键跳过或接受新版本。

万岁!我们已经完成了应用程序的框架!然而,我们实际上还没有完成。我们必须解决一个重要问题才能让数据库做好准备。然后,理想情况下,我们应该解决一个重要的安全细节。

设置数据库

如果您只是在本地做一些事情并且不打算部署任何内容,那么本节的第一部分可能不是非常必要。此外,这里还有很多需要考虑的地方,我认为值得一个单独的教程来深入研究一些数据库配置和基本存储库安全性 - 特别是如果您的存储库是公共的(如果是公共的,不用担心,只需小心即可!) .

通过前面的命令,我们最终得到了大量的新文件和目录。其中之一是 config/database.yml。对我来说,第 12 行是一个如下所示的块:

$ mkdir my-app
$ cd my-app

从技术上讲,上述方法是有效的。这没有什么“问题”。但我们可以做得更好。最大的问题是我们的数据库没有密码。下一个问题是数据库没有名称。最后,用户名以纯文本形式可见。不是我最喜欢的。让我们用以下内容更改所有内容(以下第一个是新字段,后两个应替换任何现有值):

$ touch Dockerfile.dev
$ touch docker-compose.yml
$ touch Gemfile

您还可以使用 ENV.fetch("VARIABLE_NAME") { "fallback_value" } 样式。 ENV["VARIABLE_NAME"] 和 ENV.fetch("VARIABLE_NAME") 之间的区别在于,如果前者找不到具有指定名称的环境变量,则前者将返回 nil,而后者可能会引发一些警告或错误(请参阅此有关 ENV.fetch 的更多信息)。

有了这些,假设您还没有退出 shell(您可以使用 docker-compose run --service-ports web bash 重新进入),我们需要创建一个新的数据库。使用以下命令执行此操作:

FROM ruby:3.3.6

WORKDIR /usr/src/app

COPY . .
RUN bundle install

退出 Docker shell 并在本地终端环境中运行以下命令:

services:
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: app
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3307:3306"
  web:
    build:
      context: .
      dockerfile: Dockerfile.dev
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - ".:/usr/src/app"
    ports:
      - "3000:3000"
    depends_on:
      - db
    links:
      - db
    environment:
      DB_USER: root
      DB_NAME: app
      DB_PASSWORD: password
      DB_HOST: db

就是这样!如果您将浏览器(或像 Postman 这样的 API 客户端)指向 localhost:3000,您应该看到经典的 Rails 启动页面:

Setting up a new Rails application with Docker & MySQL

添加一些极其简单的安全性

我们已经有了一个可以运行的应用程序!它配备了一个很好的数据库,可供生产操作使用(Rails 提供的默认数据库 SQLite,非常适合将基本想法组合在一起,但它不适合生产工作,而且它的创建者是个怪人)!但更强大的数据库需要承担一些额外的责任。

正如我们在本教程前面所看到的,我们的任务是提供三个重要的值:数据库名称、用户名和该用户的密码。到目前为止,我们有 1 层抽象:我们从 Rails 环境中获取这些值,而不是仅仅将原始字符串值传递到 database.yml。那么,Rails 环境从哪里获取这些值呢?来自 docker-compose.yml 文件!

但这留下了一个有待解决的重要问题:假设我们要在生产中使用此代码,我们已经在代码本身中包含了除系统管理员之外任何人都不应有权访问的信息。那不太好。我们应该有一个额外的抽象层,消除对某些有价值的、理论上包含的信息的任何直接引用。

现在,我们必须在 Ruby 环境首次启动时实际 GET 在 Ruby 环境中正确设置这些环境变量。我们将分两步完成此操作,但如果您愿意,也可以一步完成。首先,我们需要停止直接引用 Rails 项目中的数据库机密。我们正在这样做。接下来我们需要将它们从 Docker 传输到 Rails 中。最后,我们将通过添加我们对 Git 隐藏的文件中的秘密值来进一步抽象它,以更好地掩盖这些信息,防止潜在的不善行为。

将环境变量从 Docker 传送到 Rails

我们有几个选项,但我的首选是创建一个存储这些值的环境文件。如果您与团队合作,您可以通过更隐蔽的措施(GPG 加密是经典)在你们之间共享此文件,而无需冒将此信息发布到公共互联网上的风险。如果您查看一下可能在不久前运行 Rails new 时创建的 .gitignore 文件,您会注意到项目根目录中以 .env 开头的任何文件都有一个行项目。这正是我们想要的:一个不会添加到 git 跟踪中的秘密文件,但我们可以在其中以纯文本形式保存重要的绝密信息。让我们开始吧:

path+=/opt/homebrew/bin

我添加了 .dev 后缀,以防万一我们最终需要不同的环境文件用于开发、生产和测试环境。在新创建的文件中,我们添加一些值:

$ mkdir my-app
$ cd my-app

我们还需要更新 docker-compose.yml 文件才能实际使用新的环境文件。在网络服务下,添加以下内容:

$ touch Dockerfile.dev
$ touch docker-compose.yml
$ touch Gemfile

就是这样!使用 docker compose up 再次启动应用程序并导航到 localhost:3000 以确认一切正常。

以上是使用 Docker 和 MySQL 设置新的 Rails 应用程序的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn