Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Persian
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
This episode is sponsored by Honey Badger.
This episode will have an interesting look where we create a Rails application,
not created this special helper called Generate.
So then I'll give it my application name, and it'll go through and set up the Rails application
as we would normally expect. However, it's going to add in a lot of different extra files.
And this is just using a Rails template. However, this template is a little bit unique
because we're not focusing on our development experience, but rather we're focusing on the deployment.
So once a project has been created, I'm going to navigate into that project, and then I'll run the command bin deploy.
Then it'll start building the Docker image, and once it's finished building, it's then going to push it up to Docker Hub.
And the general premise of this template that we'll be creating is that it's going to give us a development environment in Docker.
So if we want to run bin dev, it's going to start up everything that we need for our development environment,
and then we can start cutting right away.
And the other part of the template that we'll be creating is a production deployment. And for this deployment, I am using Docker swarm
and a have or tanner installed on the Docker swarm as well as traffic, which we'll look at setting up this entire infrastructure and another episode.
And really the purpose of this template that we're going to be creating is for kind of hobby projects.
A lot of times we have different projects that we are creating and we're creating these often, but setting up an entire deployment infrastructure for these can be a rather pain.
So all we have to do for this example application is to deploy the Yemmo file that was generated for us.
So we'll deploy this, and we can navigate in to make sure that everything is up and running.
In navigating to our fully qualified domain name, we now have our application up and running.
And so for this template with this hobby-esque kind of environment, we're going to be able to create our application and deploy it within minutes.
And in another episode, we'll actually have a look at setting up the portainer servers, the Docker swarm, as well as traffic, and getting all of that up and running as we would expect.
And be sure to check out episode 163 on an introduction to templating and rubion rails applications.
So to start off, I created an empty folder and I'm going to just touch a file and we'll call it the main.rb.
And so to start off, I'm going to create a method and it's just going to be ask underscore with underscore default.
We'll take in a couple of parameters, we'll have our prompt, and then we'll also have our default value.
We'll set the value is equal to ask, then I'm just going to interplay it in the prompt, and then in parentheses, we'll show the default value.
We can check if the value is blank, and if it is, then we'll return the default value.
Otherwise, we'll return the value that the user entered, and this will be helpful because we need to find out what the username is for the Docker hub,
account that we'll be pushing our images to. So we can set an instance variable registry, and then we'll do an ask with default,
and then we can enter in our prompt, and then some kind of default value. I'll just use my screen tag,
and then we can invoke the registry method. We could also ask the domain name, and typically, if you're using this method,
then it's going to be the same domain name. In my case, I've secured the domain rails app.dev
that I'm using for this example, and so we'll just give a prompt for the domain name of the server,
and then we can invoke this method as well. For this kind of application, we are going to use postgres SQL.
So I'm going to set a Rails command, and we'll have the DB system change, and we'll set it to the postgres SQL.
We'll also remove the file under the config database.eml, and then we're going to have to grab it template.
And so I'll create another folder called config, and then we'll have a database, dyeyaml.erb.
We're going to copy this over to the config slash database dyeyaml.
So we need to create the config directory, and then we need to touch the config and the database dyeyaml.erb.
And for this database, gaml file, I'll just try to keep it pretty simple, where we'll have some default values,
our adapter, we'll be the postgres SQL. We'll set the encoding to unicode, and then we'll set the pull,
and we do need to use 2% here, because when this template is generated, and the database gaml.erb file is copied over,
we want this to still be an ERB tag. We can get our environment dot fetch,
the Rails underscore max underscore threads, and if there's no value provided, then we'll just default to five.
We then set a URL, and it's going to be something very similar, except we'll change the environment variable to the database,
underscore URL, with a default value, and we'll just set this to local host.
Then for our development environment, our test environment, and the production environment,
in each of these cases, we're going to inherit from our default config.
We do need to set our database name, and even though we have a database URL, I'm just going to go ahead and create our database name,
because typically we would have our app name underscore development, but we don't know what our application name is here yet,
and because this is a template, it's going to vary for every single application.
So we'll generate it, and I'm going to use a app name, and then dash a rise,
and this is a method that we'll need to create, but essentially all we're going to do here is to set up the different database names for each environment.
But we do have to define this app name dash rise.
But at the top of our main dot RB, we'll create this method, and we'll just take the app underscore name,
and we'll substitute any kind of underscore's, and instead we'll insert a dash.
We can then generate a controller, we'll call it welcome, and we'll have an index action.
We'll set our route to the root to our welcome index.
And so this will create the basis of our application, but then we also need to create our doctor files that we're going to be using for development as well as production.
So the files that we need to create, we're going to have a docker ignore.
We also need to have a docker compose file, we need to have a docker file, and I'll add a dot dev to this, just so we know it's for our development environment,
and then we're going to have a docker compose, and we'll add a dash prod on here for production environment, and we'll have a docker file dot prod.
So in each case of these, we're going to have a template, and we'll put each one of these files and another folder called docker files.
And because we are going to be modifying them, we'll set the ERB tag, and then we can copy the found name strings, because we are going to place these in the root directory of our application.
But we do need to get rid of the dot ERB.
So we need to create the docker files folder, and we'll need to touch each one of these files.
And so starting at the top of the docker file ignore, I'm just going to pay stins some common files that you may want to ignore.
And because it's a lot to go through, I'm also going to do the same thing for the other files, but I'll run through what we're doing in these, and I do have some other episodes.
On docker that I highly recommend that you read up on, because some of this will be repetitive.
So because this is our docker file dot dev, we're taking in an argument for the Ruby version, which will be passed in from the docker compose file.
We're updating to make sure we have any of the latest packages, we're installing build essentials, and also the Postgres SQL client.
The next three lines is just a standard setup for downloading the node and the yarn sources, we'll then run app update, so that we can then install no JS and yarn.
And we're doing this because when I create Rails applications, I like using ES build over important maps.
Well, then run the gym update system, well, then also install bundle, we'll set our work directory to the root of our docker image in the app folder.
And so, gyms will install a little bit faster because we don't need documentation for these gyms that we're installing, we'll just echo the gym, no our doc and no R I into our home folder and in the gym R C.
We'll copy just the gym file and the gym file dot lock to the root of our work directory and same for the package JSON and the package lock, because then we can run bundle install and the dash j in proc is just so when we run bundle install, we're going to use however many CPU cores that we have, we'll be the number of threads that we'll run bundle install with.
And then we'll run yarn install and the docker file dot prod is going to be very similar, so I'm just going to paste it in, but we are going to have a few different changes.
So I'll start out and I want to specify our Ruby version, in this case we're going to use 3.1.2 and I'm also going to set an environment variable for the Rails environment and we'll set it to production.
Everything else is going to be the same, except for the bundle install, because on our development environment, we need any kind of development or test gyms, but for our production image, we don't need that.
So we'll have a command or we can run the bundle config set dash dash local and then we can say without and we want to do this without the development or the test.
We can then copy everything in the current folder to the app folder, which is our work directory, we then need to run and we'll specify the Rails groups is set to assets and we'll run the bin Rails assets pre compile.
And so this way our doctor image before we even try to deploy, we are already pre compile the assets and then we're going to do something a little bit interesting here.
As entry point, we're going to set to the app, the bin folder, and then we'll set an entry point dot s h. And this is going to be important because when we are deploying these doctor containers for the first time, we're not going to have any production database created.
And each subsequent time, we're not going to have the migrations ran and we want to make sure that we're doing this. So that's all really the entry point is going to do. Then we'll call back and then we can run the command.
We'll call the bin Rails, the server. This will be important because we want to bind and this is going to bind to an IP address and the IP address we want to bind to zero dot zero dot zero dot zero dot zero.
And that essentially means any IP address or any interface on this Docker image. And then we're going to specify the port and we'll use the default port 3000.
We can expose the port 3000 and then our doctor file dot product is done.
And so when I am using different Docker files like this for the development and production, I try to keep them very similar as closest possible. And that will just help prevent any kind of unexpected surprises that we could run into when we deployed to production.
And for the Docker compose file that we'll use for our development environment, I'm going to paste this in here.
Because it is repetitive for what we have done in the past and some of the episodes have covered on Docker. The main points of interest here is that we have this x base, which we'll use to inherit on some of our services.
And the important part here is setting the Docker file dot dev for the Docker file and passing in the Ruby version because we are using that to pull the Ruby image and we're using three one two.
And we're using our volume to the current directory. And if you remember, the Docker file has a root of the image as app where our work directory is.
We'll set the database URL and notice on the database URL, I'm not putting a port slash in the database name because our database Gamble file has the name of the databases that we'll be using.
And we'll set up the app to run the real service exposing port 3000 and I'm also setting up a CSS and a JS service because again, I am using JS bundling with ES build along with CSS bundling with bootstrap.
And then you can just use a command to start up site kick. We'll have our redness instance then also our postgres SQL.
And that's all we had to do for the Docker compose file and I'm going to copy this over into the Docker compose production.
So we're going to have to make a lot more changes. And so the first thing that we're going to do is have some kind of networks because we do need to expose our real server to a public network.
But we also need a network for the other applications or the services, whether it's redness or postgres to communicate internally on the same network, we would not want to expose those to the public.
So for my environment and what we'll explore in a future episode is that I am using traffic and I have a traffic dash public network.
We'll set this to external and we'll set it to true and then I need some kind of internal network.
And so I'm going to use ERB to take in our app underscore name and we'll just call dot underscore on here and then we'll have our underscore network.
So we're going to move the volumes up to the top of this list just so it's easier to see and then we'll delete the x space because we're not going to be inheriting from anything.
And we're not going to need the CSS or the JavaScript services because this is a production environment.
And when that's a production environment, I just mean that the Rails environment variable is set to production.
And again, I wouldn't really recommend this methodology for a production environment because you wouldn't want your redness or your postgres sequel running in Docker containers.
It's better to use a cloud services for those.
So for our image, we'll need to get the username that we had said earlier and that's for the registry.
We can set this to registry for slash, then we also need our app name dot underscore and for my case, I have a underscore app that will use when we're building the image.
And we need a special via version and I'm just going to use latest and again for a hobby project, I don't mind pushing up a Docker image with the tag latest and then just pulling from that.
If this were a real production environment, then I probably would have some kind of versioning of the Docker images just in case if I need to roll back.
We'll set the restart to always will still have the same command.
And then we need to set some environment variables because our infrastructure doesn't have engineers and front of our Rails application.
We are going to need to serve these static files from the Rails environment or the Rails server.
So we can set the environment variable Rails underscore serve underscore static files and we can just set this to enable yes, it just needs to exist.
We could also set the Rails underscore log to standard out and just for consistency, we'll set this to enable this well.
Then we need to get our database URL and we're just going to set this to the same path that we had for our development Docker compose file because that part hasn't changed.
But one neat thing that we can do here is that we can set a volumes and we're just going to call this the storage and we're going to set it to the app for slash storage.
And if you're using active storage by default in the Yemal files, that's where it's getting set to and then we just need to specify that we have a storage volume under the volumes.
And then this would basically completely mitigate the need to run S3 or something like that.
You could still run many over here as a separate service like that, but it's not really necessary for this hobby kind of project and I would like to just keep it all a bit more simple.
Because we could be running multiple replicas, I don't necessarily want to specify the port and log it to port 3000 on the host.
Instead, we'll get one that's dynamically generated and that's going to be okay because when we set up traffic, it will automatically do the routing as it should.
And then we'll do need the depends on and it's going to depend on Postgres and Redis and this simply so the Rails application doesn't get booted in life before the Postgres and Redis instances are up and running.
And then we get down to networks and this is going to be pretty interesting because we're going to have the traffic public network because this app service doesn't need to be user facing.
And then we'll also have our app name dot underscore underscore network and that's going to match the one that we specified earlier up here.
And so what's interesting on the networks on a redis server, we do need to specify the networks, but we're not going to include the public network.
So this is going to include the network for our application, so internally the redis server, the Postgres server and our app server will be able to talk together.
However, you would not be able to access the redis or Postgres SQL server from outside the network.
And so back under the app services, we're also going to have a deploy tag on here and we'll set our replicas and let's just set it to two and then we need some labels.
And then we need to set the traffic enabled, we'll set it to true. We then need the traffic dot HTTP dot services.
And then we need our app name underscore and we'll set our load balancer dot server dot port is equal to 3000.
And that basically tells traffic that for this service for the app regardless of what dynamic port you will be getting. We need a forward. There were quests over to port 3000 which the application knows how to listen on.
And then we need to set up some traffic routers.
The first one will have a rule is equal to and then we're going to specify a host. You can set a lot of different options here, but essentially this is going to be something like example and then our domain name.
So we'll have by default the app underscore name dot underscore and then we'll also need our domain name and the domain name if we go back to the main dot RB that's a question that we asked at the beginning of generating our template.
So we'll just specify the domain here and then it should all get interplayed and just find. We then need to set some entry points and we'll set it to web and this is something that we'll see in the next episode.
That's going to be specific to traffic and that basically just saying that the entry points for the web address is going to be something like port 80.
We can then set the traffic dot constraint dash label and we're going to set this equal to the traffic public, which should match the network that we're specifying for app service.
I'll copy this down again and then we'll have the Docker dot network and that is also set to the traffic public.
And so back in our template, we still need to create a couple more files. So we'll have another template. We're going to put these under the bin folder. We need to have a deploy.rb and this going to map to the bin slash deploy.
And if you remember, we also had an entry point dot s h and that was specified in the Docker file dot prod and that's where we're going to run our migrations. So for the deployed.rb will first start off with a should bang bin bash will have a Docker login, which on your local machine is probably going to be set to the username that was specified.
And in my particular situation, I'm going to name one machine and building the images on a l1 for an x86 platform is very slow because of the processor emulation.
And so the way that I do my Docker builds is that I reference a builder and the builder essentially is a remote machine that I have somewhere that will build based off the platform.
I have a Docker build x create, I'll create a new line, I'll give it a name and I'm just going to call this the AMD 64 underscore builder.
I then need to give this some kind of node name and it's going to be Linux AMD 64 underscore builder. You can give it whatever name you want.
And this is going to be helpful in situations where maybe you need a bill for different type of architectures will set the platform and this going to be a Linux slash AMD 64.
And then it is specified the address. So I've set up a build server virtual machine that have locally that I'm going to handle for all the building.
But if you don't want to go through these steps if you're okay with building the Docker image and taking them while think you don't have to have this build x create.
We then have a Docker build x build and this going to be for our actual production image. We want to specify the file the Docker file dot prod and that's going to be really important that we specify the production one because that's the one that we're going to use to deploy.
We can specify the builder that we just created, which is the AMD 64 builder.
And again, if you don't want to use a build server, you don't have to you just wouldn't include that line.
And if you don't include the line, then you do need to specify the platform. And it doesn't hurt if we have the platform specified here as well.
Well, then have a tag is going to our registry username for slash and then the app underscore name dot underscore and if you remember we had a underscore app for our Docker image name and we're going to push us to the latest.
We can then call a dash dash push. So once it's done building it'll push it up to the registry and our context is going to be the current directory of our application. In the entry point dot s h dot erb.
We have a shabang with a bin bash will do a set dash e which basically means if we get an error, then we want to stop everything just so we're not continuing on with a potentially broken image.
So if you can do a check if there is a file for the app temp p id's and the server dot p id then we can remove this file.
And if we don't do this, then we could get into a situation if for whatever reason this file was built into the image and deployed.
Then when we try to run our Rails application, it's not going to work because it's going to say that a servers p id file already exist.
And then we can run the bin rails db migrate and I don't care to see the output. So I'm just going to pipe this to the dev no and if this doesn't work,
meaning if it returns in exit zero, then everything is okay, but if it's unable to do the migration, then we know that we don't have our database set up yet. So we can disable the environment database check.
And then we can run the bin rails db setup. We think all the exec bundle exc bundle exec and then imprint the sees a dollar sign at symbol.
And that basically means that to our Docker file, which originally invoked the entry point dot s h, we want to go back and then execute whatever command.
And after we run bundle, there are going to be some sets that we need to do some of them could be optional. We can run bundle lock and then dash dash add dash platform and we'll have a few different platforms that we need to add.
And just from my experience, a pretty good cover all is the AR 64 Linux, the x86 64 Darwin 19 and that's going to be helpful if you have an Intel MacBook and then the x86 64 dash Linux.
We then remove the file, bin dev, because on a real seven application, it comes with a bin dev file that will launch form and but because we have dock rise our development environment, we don't need that bin dev file.
Instead, we're going to have a template and we'll just call the bin dev.erb now basically replace the bin dev file. We then run the ch mod plus x and that basically sets a permission to make the file executable and we want to make the bin dev executable.
We also want to make the bin deploy executable and we also want to make the entry point dot sh executable as well. We can remove the file and the file that we want to remove is a proc file.dev because we don't need that anymore because our bin dev is actually just going to run the docker compose up.
And then we can do some things which could be helpful if you're generating a lot of applications just make sure that they will build correctly so you don't get too far into the development where we can run the Docker compose run the app bundle install we could also run the yarn install and the bin rails db setup or if you just want to write it out the db drop db create db migrate and if you have any seeds.
You may want to run another command for that as well but typically just running db setup should be fine. Once those all run then we'll call the Docker compose down and something that I like to do is to run a git init will do a git add and we'll just specify the current directory.
Then a git commit and we want to pass a message and we'll just say that this is our base and this basically is all that we should really have to do to have a fully dock rise and deployable application.
And so now let's try this out. We'll have a rails new. I'll just call this the test app. We are going to pass the dash dash JavaScript ES build and also the dash dash CSS and we'll use bootstrap. Then we need to specify what they dash in our template and that's going to be the main dot RB it'll run through it'll ask us our registry username the domain of our server will just say yes to override.
The database Gamal file and then we get a weird error even though the config database Gamal file exists we can cat that out to see it doesn't find it and there's a little trick that we can do.
We'll just create a method called source underscore paths and then in square brackets we'll have a underscore underscore d IR and then two more underscores and that's all we should have to do there.
So we can run the same command again except I'm going to first RM dash RF the test app folder and then we'll just chain in the rails new command will go with the defaults and then that should go through and then build out our entire application.
But one thing that we did forget to do is we've got to create the dev.erb file and now just be a shabang the user been environment and then we'll have bash and we'll run the Docker compose up.
So I'll delete the test app folder again I'll rerun the generator and this time it should go all the way through including building our gems installing yarn running bundle install and building our local Docker images.
And so all the gems within there and now it's running yarn install and depending on how you have your template setup you may get an error that the schema dot RB doesn't exist yet that's because we haven't created any migrations yet our command was a bin rails DB setup.
So I'm going to run the DB create the DB migrate and also the DB seed I'll delete the folder rerun everything again then it all happened successfully I can check out I do have the test app folder and then I can pull it up and Vs code.
So if we check out some of the files we have our Docker compose all of this we know is good because it's already ran the bundle installing yarn install on those but if we check out the Docker compose prod we can see the image that's trying to pull from.
We got the network that's working properly here and that's referencing to the test app network all the traffic variables are loaded in as we would expect and everything looks good.
So to test this out now we need a build and then push up the Docker image and we can do that with a bin deploy it'll log into our Docker is going to use our builder VM it'll build the image and then because this is our production image.
It's running the assets pre compile then it's exporting the image and then I'll push it up to the registry and so if we go back to portator I'll go under the stacks will create a new stack for a test app and then I'll just copy and paste the Docker compose prod file into here we can then deploy the entire stack we should get.
And message as succeeded we then go into our test app we will expand the services just make sure everything is running.
We can go to the logs we can see that our Rails application is up and running we can check the other server it created the database test app production which is great we can see that was given a dynamic port.
So we can then navigate to the test app.railsapp.dev and everything is working great so if I'm working on hobby projects then I think that this is going to be a great way to do it you can get a couple of digital ocean droplets and then create a Docker swarm with those to have an environment where you can quickly and easily push up Rails apps that you just want to take around with without having to worry about all the data.
And again in another episode we'll actually go through setting up that entire infrastructure of the virtual machines with Docker Docker swarm, portator and traffic.
Well that's all for this episode thanks for watching.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.