Saturday, June 03, 2023

Javascript Concepts Arranged by Difficulty

 Sure, here is a recommended order to learn advanced JavaScript/ES6 concepts. Note that the "difficulty" of a concept can vary based on an individual's previous experience and comfort with programming. 

1. **Template Literals**: These are an easy starting point, providing a more powerful way to work with strings.

2. **Arrow Functions**: A more concise syntax for defining functions, but understanding how `this` works with arrow functions can be tricky.

3. **Default Parameters**: An easy-to-understand feature that can make your functions more flexible.

4. **Destructuring Assignment**: This syntax can make your code more concise, but it can be a little tricky to understand at first, especially when dealing with nested data.

5. **Spread/Rest Operators**: These provide powerful ways to work with arrays and objects, but can be tricky to understand at first.

6. **Array Methods (map, filter, reduce)**: These are higher-order functions, which are a core part of functional programming in JavaScript. Understanding these methods will significantly improve your ability to work with arrays.

7. **Import/Export (ES6 Modules)**: These are essential for any large JavaScript project, but understanding the different ways to export and import can take some time.

8. **Promises**: Asynchronous programming is a challenging but essential part of JavaScript, and promises are a key part of that.

9. **Async/Await**: This syntax makes asynchronous code look more like synchronous code, making it easier to understand and work with. However, you need to understand promises before you can fully understand async/await.

Remember, the best way to learn these concepts is by doing. Try to use each concept in a small project or coding exercise before moving on to the next one. Happy learning!

Customized Learning Plan for NextJS

 Absolutely! Given your strong background in backend development and familiarity with REST APIs and JavaScript, I'd suggest focusing your efforts on the frontend-specific aspects of JavaScript and diving deep into React before stepping into Next.js. Here's a customized action plan:

1. **Advanced JavaScript/ES6**: Since you already have basic knowledge of JavaScript, dive deeper into ES6+ features such as promises, async/await, arrow functions, destructuring, spread/rest operators, and modules. Resources like Mozilla Developer Network (MDN) and JavaScript.info provide great guides for these topics.

2. **React**: Given that Next.js is a React framework, understanding React is essential. Key topics include:

   - **JSX**: Learn how to use JSX, the syntax used by React to mix HTML with JavaScript.

   - **Components**: Understand the difference between functional and class components (though you'll primarily use functional components with hooks in modern React).

   - **Hooks**: Learn the useState and useEffect hooks, which allow you to add state and side effects to functional components. Other hooks like useContext, useReducer, and useRef are also worth exploring.

   - **State & Props**: Understand the difference between state and props, and how data flows between parent and child components.

3. **Building a React Application**: Put your React knowledge into practice by building a simple React application. This will help you become familiar with creating components and managing state.

4. **Next.js Basics**: Once you're comfortable with React, start learning the basics of Next.js from the official Next.js documentation and tutorial. Understand how to create a new Next.js app and the difference between pages and components.

5. **Routing in Next.js**: Explore the built-in file-system based routing in Next.js. Understand how to create dynamic routes.

6. **Data Fetching in Next.js**: Given your familiarity with REST APIs, learn about the data fetching methods provided by Next.js: `getStaticProps`, `getServerSideProps`, and `getInitialProps`. Understand when to use each method.

7. **API Routes in Next.js**: Learn how to create API routes in Next.js, which will allow you to build your API directly into your Next.js app.

8. **Static Site Generation (SSG) and Server-Side Rendering (SSR)**: These are key features of Next.js. Understand how and when to use SSG and SSR.

9. **Building a Next.js Application**: Practice your new skills by building a more complex application in Next.js. Consider building a full-stack application with your backend knowledge.

10. **Deploying Next.js Application**: Learn how to deploy your Next.js application. Vercel, the company behind Next.js, provides a simple deployment platform.

Remember, while learning, the best approach is to simultaneously apply the knowledge into building small projects. This helps to reinforce the concepts you've learned. Happy learning!


NextJS Learning Plan

A general learning path to follow when learning Next.js:

1. **Prerequisites**: Before learning Next.js, you need to be comfortable with JavaScript, ES6 syntax, and React. It would also be beneficial to understand the basics of Node.js and npm (Node Package Manager). If you need to strengthen these skills, consider courses on platforms like freeCodeCamp, Codecademy, Udemy, or Coursera.

2. **Introduction to Next.js**: Start by reading the official Next.js documentation. It provides a clear, thorough introduction to the framework. Also, look at the "Learn" tutorial on the Next.js website. It's interactive and covers the main aspects of Next.js.

3. **Build a Basic Next.js Application**: Apply your knowledge by building a simple application. This could be a blog or a portfolio site. The goal is to get a feel for routing, linking between pages, and using components in Next.js.

4. **Learn about Server-Side Rendering (SSR) and Static Site Generation (SSG)**: One of the key features of Next.js is its ability to render pages on the server or statically generate pages. Understanding when and how to use these features is crucial. 

5. **Fetch Data**: Learn how to fetch data for your pages with `getStaticProps` and `getServerSideProps`. Practice fetching data from a public API and displaying it on your pages.

6. **Dynamic Routes**: Understand the concept of dynamic routes, how to create dynamic pages, and how to fetch data based on the dynamic parameter.

7. **API Routes**: Next.js allows you to create API endpoints directly in your Next.js app. Understand how these work, and when you might want to use them.

8. **Incremental Static Regeneration (ISR)**: This is a powerful feature introduced by Next.js. It allows you to update static pages after you have built your application.

9. **Next.js with a Backend**: Learn how to integrate a backend with your Next.js application. This could be a REST API or GraphQL API. You might also explore using a database with Next.js API routes.

10. **Authentication**: Understand how to add authentication to your Next.js application. You might use a service like Auth0, or implement your own authentication system.

11. **Deployment**: Learn how to deploy your Next.js application. Vercel (the company behind Next.js) provides a great platform for this, but it's also worth understanding how to deploy to other platforms.

12. **Advanced Concepts**: Once you're comfortable with the basics, you can look into advanced topics such as module path aliases, custom `_app` and `_document` files, integrating with CSS-in-JS libraries like styled-components, and performance optimization techniques.

Throughout your learning journey, building projects is key. Practical application will help consolidate your understanding of the concepts. You might start by recreating your personal website or blog, developing an e-commerce site, or creating a full-stack application using Next.js and a backend database.

Finally, don't rush. Understanding these concepts takes time. Work consistently and practice as much as possible, and you'll see progress. Good luck!

Saturday, May 27, 2023

Identity Access Control

 Identity Access Management (IAM) is a framework of business processes, policies, and technologies that manages digital identities and controls how identities can be used to access resources.


IAM is used to ensure that the right individuals access the right resources at the right times for the right reasons. Here's a brief explanation of its key components:


1. **Authentication**: This is the process of determining whether someone (or something, like a system) is who they claim to be. This is often accomplished via passwords, two-factor authentication, biometric data, or other methods.


2. **Authorization**: After a user is authenticated, the next step is to determine if they have permission to access the resource they're trying to use. This is often determined based on the role assigned to the user or the rules defined for the resource.


3. **User Management**: IAM systems manage user identities, including the creation, removal, and organization of user profiles. Administrators can assign and revoke rights and permissions, often using a dashboard or control panel.


4. **Single Sign-On (SSO)**: SSO is a feature that allows users to authenticate with one set of credentials and access a suite of related applications. This not only improves the user experience but also enhances security by limiting the use of (and thus exposure of) credentials.


5. **Multi-Factor Authentication (MFA)**: MFA adds an extra layer of security by requiring users to provide two or more verification factors to gain access to a resource.


6. **Identity Federation**: This feature allows users to use the same identity (username, password, etc.) across multiple systems, which is especially helpful in hybrid and cloud environments.


7. **Identity Governance**: This is the policy-based centralized orchestration of user identity management and access control. It helps organizations achieve compliance by providing auditable trails.


By employing IAM, organizations can enhance security, improve productivity, meet compliance requirements, and deliver a better user experience.

Role Based Authentication

 Role-Based Access Control (RBAC) is a method of managing access to a system's resources based on roles assigned to individual users within an enterprise. This method provides fine-grained control and offers a simple way to manage permissions across a large number of users.


Here's a brief explanation of how it works:


1. **Roles**: Roles are defined according to job competency, authority, and responsibility within an organization. For example, you might have roles such as "admin", "manager", "developer", "user", etc.


2. **Users**: Each user is assigned one or more roles, and each role grants certain permissions. For example, a "user" might be able to view data, a "developer" might be able to modify that data, and an "admin" might have full control over all operations.


3. **Permissions**: Permissions define what resources a role can access and what operations it can perform. Permissions are associated with roles, and users inherit these permissions through their roles.


4. **Access Decision**: When a user tries to access a resource, the system checks the user's role and determines whether that role has the required permissions to access the resource. If the role has the necessary permissions, the system allows the user to access the resource.


This approach greatly simplifies management and auditing of user privileges. Instead of assigning permissions to each user individually, permissions are assigned to roles, and users are assigned roles, allowing administrators to manage user privileges by simply assigning appropriate roles to users. 


Furthermore, RBAC can be used in combination with other access control methods such as Attribute-Based Access Control (ABAC) for even finer control over system resources.

Monday, May 15, 2023

Redoc Demo

 https://redocly.github.io/redoc/?url=openapi-3-1.yaml#tag/pet/operation/addPet

Thursday, May 04, 2023

Mikado Method

 Explain Mikodo method and creating Mikodo graphs


It seems like you might be referring to "Mikado Method" and "Mikado Graphs." If that's the case, here's an explanation of the Mikado Method and how to create Mikado Graphs:


The Mikado Method is a systematic approach to facilitate large-scale refactoring and reorganization of code in a software project. It helps developers identify and manage dependencies between different parts of the code, minimizing the risk of breaking the system while making changes. The method is particularly useful when dealing with legacy code or complex systems that require significant restructuring.


Creating Mikado Graphs:


A Mikado Graph is a visual representation of the dependencies and tasks involved in the refactoring process. It helps you keep track of the changes required and the order in which they need to be implemented. Here's a step-by-step guide to create a Mikado Graph:


Identify the goal: Define the refactoring goal you want to achieve, such as improving code structure, updating a library, or implementing a new feature. Write the goal at the top of a blank sheet of paper, whiteboard, or digital drawing tool.


Try the simplest solution: Attempt to make the desired change directly in the code. If it works without causing problems, you're done. If it introduces issues or breaks other parts of the system, proceed to the next step.


Add prerequisites: Identify the issues that need to be resolved before implementing the change. These are your prerequisites, and they should be represented as nodes in the Mikado Graph. Draw arrows from the goal node to each prerequisite node.


Recurse: For each prerequisite node, repeat steps 2 and 3. If the prerequisite can be implemented without causing problems, mark it as done. If it introduces new issues, create new nodes for each new prerequisite and connect them to the current node with arrows.


Undo changes: As you identify new prerequisites, undo any code changes made during the process to maintain a stable system. The Mikado Graph serves as a guide to implement the changes in the correct order later.


Complete prerequisites: Once the graph is complete, start implementing the prerequisites from the bottom up. Each completed node will enable you to tackle its dependent nodes until you finally reach the main goal.


By following the Mikado Method and using Mikado Graphs, you can systematically refactor and reorganize your codebase while minimizing the risk of breaking the system.


Are there any resources to learn how to apply it for Rails code base?


While there aren't many resources specifically dedicated to applying the Mikado Method to a Ruby on Rails codebase, you can still learn the method and apply it to any codebase, including Rails projects. The concepts and practices of the Mikado Method are universal and can be adapted to various programming languages and frameworks.


Here are some resources to help you learn the Mikado Method:


The Mikado Method book: The primary resource for learning the Mikado Method is the book "The Mikado Method" by Ola Ellnestam and Daniel Brolund. This book provides a detailed explanation of the method along with examples and case studies. Although not focused on Rails, the book's principles can be applied to Rails projects.

Book link: https://www.manning.com/books/the-mikado-method


Blog posts and articles: There are several blog posts and articles available online that explain the Mikado Method and its application. Here are a few examples:


https://medium.com/@_nikkormat/mikado-method-a-structured-way-to-make-big-changes-3db35e3aa3c

https://www.methodsandtools.com/archive/mikado.php

Videos and presentations: Various recorded talks and presentations can help you learn the Mikado Method through visual explanations. Here are a couple of examples:


https://www.youtube.com/watch?v=bGk_VM9Xgxo

https://vimeo.com/123635803

To apply the Mikado Method to a Rails codebase, you can follow the general principles and adapt them to Rails-specific concepts and components. As you gain a deeper understanding of the method, you'll be able to apply it effectively to refactor and reorganize Rails projects or any other codebase.


Can it be used to update library used in a web application?


Yes, the Mikado Method can be used to update a library used in a web application. The method helps you identify and manage dependencies and required changes in a systematic way, which is particularly useful when updating libraries that might have a significant impact on your application.


Here's a high-level overview of how to apply the Mikado Method for updating a library in a web application:


Define the goal: The goal is to update the library to a specific version or to replace it with another library. Write this goal at the top of your Mikado Graph.


Update the library: Attempt to update the library directly. If the update is successful and doesn't cause any issues, you're done. If it introduces breaking changes or issues, proceed to the next step.


Identify prerequisites: Determine the issues that need to be resolved before the library update can be implemented. These issues could include changes in function signatures, updated configuration settings, or modifications in the library's behavior. Add these prerequisites as nodes to your Mikado Graph and connect them to the goal node with arrows.


Recurse through prerequisites: For each prerequisite node, try to implement the required changes. If the changes introduce new issues or dependencies, create new prerequisite nodes and connect them to the current node. Remember to undo any code changes made during this process to keep the system stable.


Complete prerequisites: Once you've identified all dependencies and required changes in the Mikado Graph, start implementing the prerequisites from the bottom up. As you complete each node, you'll be able to tackle its dependent nodes, eventually leading to the main goal of updating the library.


By following the Mikado Method, you can systematically update libraries in your web application while minimizing the risk of breaking the system or introducing new issues.


So it is not really restricted to just refactoring a code base?


That's correct. The Mikado Method is not restricted to just refactoring a codebase. While it is primarily known for its effectiveness in handling large-scale refactoring, it can also be applied to other aspects of software development, such as updating libraries, implementing new features, or reorganizing code.


The strength of the Mikado Method lies in its systematic approach to identifying and managing dependencies and required changes. This makes it a versatile technique that can be adapted to various tasks within software development, ensuring that changes are implemented in a well-structured and organized manner, while minimizing the risk of breaking the system.


How to choose whether to pick breadth first or depth first when using the Mikado method?


When using the Mikado Method, choosing between breadth-first or depth-first traversal depends on the specific refactoring goal, the complexity of the codebase, and personal preferences. Both approaches have their advantages and can be effective in different situations.


Breadth-first traversal:

In breadth-first traversal, you address all immediate prerequisites of a node before moving on to their prerequisites. This approach allows you to identify and understand the full scope of required changes at each level before diving deeper into the dependencies.


Advantages:


Provides a clearer picture of the overall scope of changes at each level.

May help identify common dependencies or overlapping tasks early in the process, allowing for potential optimization.

Easier to parallelize work among team members, as multiple tasks can be tackled at the same level.

Depth-first traversal:

In depth-first traversal, you follow a single chain of prerequisites to its end before backtracking and exploring other chains. This approach allows you to focus on one dependency path at a time, which can be helpful when dealing with complex or deeply nested dependencies.


Advantages:


Helps maintain focus on a single chain of dependencies, which can be beneficial in complex codebases.

Potentially faster in identifying the full extent of a specific dependency chain.

Easier to understand the context and interconnectedness of tasks within a single chain.

To decide which approach to use for the Mikado Method, consider the following factors:


Complexity: If your codebase has a high level of complexity and deeply nested dependencies, depth-first traversal might be more manageable and efficient. For less complex codebases or when the scope of changes is relatively small, breadth-first traversal could provide a better overview.


Familiarity: If you are already familiar with the codebase, you might have a better idea of which traversal method would be more suitable. If you're new to the codebase, experimenting with both approaches might help you determine the most effective method for your specific situation.


Personal preference: Some developers may prefer the focused approach of depth-first traversal, while others may find the broader perspective of breadth-first traversal more intuitive. Choose the approach that you're most comfortable with and that aligns with your problem-solving style.


Ultimately, the choice between breadth-first and depth-first traversal in the Mikado Method depends on your specific refactoring goal, the complexity of your codebase, and your personal preferences. You can even switch between the two approaches during the process if it makes sense for your particular situation.


Wednesday, May 03, 2023

Find all users created yesterday

 To find all User records with a created_at timestamp of yesterday using ActiveRecord in Rails:


yesterday = Date.yesterday.beginning_of_day..Date.yesterday.end_of_day

users_created_yesterday = User.where(created_at: yesterday)


This code first creates a range representing yesterday's date from the beginning of the day to the end of the day. Then, it queries the User model using the where method to filter the records based on the created_at timestamp within the specified range. The result is an ActiveRecord relation containing all User records created yesterday.


Tuesday, May 02, 2023

Search and display surrounding lines in log file

 grep -n 'search_string' /path/to/log/file.log | cut -d: -f1 | xargs -I {} awk 'NR >= {} - 50 && NR <= {} + 50' /path/to/log/file.log | sed -n '1,101p'


Sunday, April 16, 2023

cloud-init Tasks

 Cloud-init can perform several tasks independent of user data and provider data. These tasks are primarily based on the cloud-init configuration you provide. Some of the common tasks include:


Set hostname: You can configure the instance's hostname according to your preferences.


Set timezone: You can configure the instance's timezone to match your requirements.


Update packages: Cloud-init can update the package cache and upgrade packages on the system.


Install packages: You can provide a list of packages to be installed during the instance initialization.


Configure users and groups: You can create and manage users and groups, including setting up passwords, SSH keys, and user permissions.


Configure networking: Cloud-init can set up and configure the networking interfaces for your instance.


Run custom scripts: You can include shell scripts or cloud-config scripts to perform custom tasks during the instance initialization.


Mount filesystems and storage: Cloud-init can automatically mount filesystems, storage devices, and configure fstab entries.


Configure NTP: You can set up Network Time Protocol (NTP) servers to synchronize the system time.


Write files: Cloud-init can create and write files on the instance with specified contents and permissions.


Disable cloud-init: You can disable specific cloud-init modules or disable cloud-init altogether for subsequent boots.


These tasks can be performed using the appropriate modules and configuration options in the cloud-init YAML file. While some tasks are provider-agnostic, others may require specific configurations depending on the cloud provider or platform you are using.


Github copilot Prompts

 To create a cloud-init file for an Ubuntu 20.04 base image with the help of GitHub Copilot, you can use the following prompts:


"Generate a cloud-init file for setting up a base Ubuntu 20.04 image with necessary updates and security packages"

"Create a cloud-init configuration for Ubuntu 20.04 with basic system settings, user creation, and firewall configuration"

"Provide a cloud-init yaml file to configure Ubuntu 20.04 with essential tools, timezone, and SSH settings"

"Show me an example of a cloud-init file to install and configure essential packages on an Ubuntu 20.04 server"

Remember that you can always modify the generated code to suit your specific requirements.


Monday, April 10, 2023

Sidekiq Problems

 Sidekiq is a popular background job processing library for Ruby on Rails applications. While it generally performs well, there are some common issues that developers may encounter:


Memory usage: Sidekiq processes can consume a significant amount of memory, especially when dealing with a large number of jobs or jobs that require large amounts of data. Monitor memory usage and fine-tune your Sidekiq configuration to reduce the impact on your infrastructure.


Slow processing: If jobs take a long time to complete, it can cause a backlog of jobs in the queue. To address this issue, optimize the performance of your jobs by reducing processing time, or consider using more Sidekiq worker processes or threads to increase throughput.


Job failures and retries: Jobs can fail for various reasons, such as exceptions, timeouts, or dependency issues. Sidekiq provides automatic retries, but excessive retries can lead to increased load on your system. Ensure that your job code is robust and handles errors appropriately.


Infrastructure configuration: Sidekiq relies on Redis for job storage, so it is important to configure and maintain your Redis server properly. A misconfigured or under-provisioned Redis server can lead to performance issues or data loss.


Scaling issues: As your application grows, you may need to scale Sidekiq to handle increased workloads. This can involve adding more worker processes, configuring additional queues, or deploying Sidekiq on separate servers. Proper planning and monitoring are essential for smooth scaling.


Monitoring and logging: Visibility into Sidekiq's performance and job processing is critical for maintaining a healthy application. Ensure that you have proper monitoring, logging, and alerting in place to identify and resolve issues quickly.


Deployment and environment issues: When deploying your Rails application, ensure that Sidekiq is properly started and configured for your production environment. Issues with environment variables, configuration files, or server setup can lead to Sidekiq not functioning as expected.


Concurrency and thread safety: Sidekiq uses threads to process jobs concurrently, so it's essential to ensure that your job code is thread-safe. Using non-thread-safe code or shared resources without proper synchronization can lead to unexpected behavior or crashes.


By addressing these common issues and following best practices for Sidekiq and Rails applications, you can improve the reliability and performance of your background job processing.


Grafana

 In that case, you'll want to monitor the infrastructure and system resources utilized by your Rails application. You can use third-party tools or services for monitoring and creating a dashboard. One of the popular tools for this purpose is Grafana.


To create an infrastructure dashboard using Grafana, you'll need to follow these steps:


Install and configure a time-series database such as InfluxDB or Prometheus on your server. This database will store metrics collected from your infrastructure.


Install and configure a metrics collector like Telegraf, Node Exporter, or collectd to collect system metrics and send them to your time-series database.


Install Grafana on your server or use the Grafana Cloud service.


Configure Grafana to connect to your time-series database.


Create a new dashboard in Grafana and add panels with the desired metrics from your time-series database. You can display metrics like CPU usage, memory usage, disk space, network usage, and more.


Customize the dashboard to show the metrics you're interested in monitoring.


Set up alerts if necessary to notify you when certain thresholds are met or if there are any issues with your infrastructure.


Please note that the specific steps to install and configure these tools will depend on the operating system and environment you're using. You can find the detailed documentation on each tool's official website:


InfluxDB: https://docs.influxdata.com/influxdb

Prometheus: https://prometheus.io/docs

Grafana: https://grafana.com/docs

If you prefer to use a hosted monitoring solution, you can explore options like New Relic, Datadog, or AppSignal, which provide easy-to-use dashboards and monitoring tools specifically designed for web applications and their underlying infrastructure.




Sunday, April 09, 2023

Explain bare metal machines

Bare metal machines, also known as bare metal servers or dedicated servers, are physical servers dedicated to a single user or organization. Unlike virtual machines (VMs) or cloud-based solutions, where multiple users share the same hardware resources through virtualization, bare metal machines provide the user with direct access to the entire hardware resources of the server.


The term "bare metal" refers to the fact that the server runs directly on the hardware, without any virtualization layer or hypervisor. This means that the operating system and applications have direct access to the server's CPU, memory, storage, and other resources, resulting in better performance and less overhead compared to virtualized environments.


Advantages of bare metal machines:


Performance: Since there is no virtualization layer, the resources are not shared, and there is no overhead associated with virtualization, bare metal machines generally provide better performance than virtual machines.


Resource control: Users have complete control over the hardware resources, allowing for more precise resource allocation and customization to fit specific needs.


Security: Running workloads directly on the hardware without a virtualization layer can provide increased security, as the attack surface is reduced. This can be particularly important for organizations with strict security requirements or regulatory compliance needs.


Stability: Without the potential for resource contention from other users or virtual machines, bare metal machines can offer a more stable and predictable environment.


Disadvantages of bare metal machines:


Cost: Since each user has dedicated hardware, bare metal machines can be more expensive than virtual machines or cloud-based solutions that share resources among multiple users.


Scalability: Scaling resources on a bare metal machine generally requires manual intervention, such as adding more physical hardware, while scaling resources in a virtualized or cloud-based environment can often be done more quickly and easily.


Management: The user is responsible for managing the entire hardware and software stack, which can increase the complexity and time required for administration compared to virtualized or cloud-based solutions.


Bare metal machines are often used in situations where performance, resource control, or security are crucial, such as high-performance computing, big data processing, gaming servers, or sensitive data storage.



Managing compute infrastructure remains a challenge despite innovations in containerization, virtual machines, and serverless computing. In the era of cloud computing, both cloud providers and customers must manage OS rollouts, patches, and fleets of VMs and containers. Container orchestration systems, like Kubernetes, require OS images for containers. It is crucial to enforce OS compliance across all containers and VMs to prevent security breaches. Providing a standardized minimal OS for all deployments ensures a secure platform for developers. Standardization has significant benefits and few downsides, but it is easier to implement in smaller companies. Large companies and cloud providers that did not standardize early on have faced massive projects to standardize OS images later.

Zally Setup



Here's the organized version of your notes:


Create an EC2 instance


Create a small EC2 instance

Note: micro instance fails to deploy Zally

Instance details


Instance ID: i-0f4b788633c7cb2ad

Default username: ubuntu

Public IPv4 address: 18.117.180.174

Public IPv4 DNS: ec2-18-118-216-23.us-east-2.compute.amazonaws.com

Accessing the instance


Generate a key pair and download the file

Set the key file permission: chmod 400 zally-demo-key-pair.pem

SSH into the instance:

ssh -i "zdemo.pem" ubuntu@ec2-18-218-124-122.us-east-2.compute.amazonaws.com

Alternative: ssh ubuntu@zallydemo.com

Switch to root user: sudo su -

Install Node.js


Install Node.js 14 or higher:


sudo curl -LO https://nodejs.org/dist/v18.0.0/node-v18.0.0-linux-x64.tar.xz

sudo tar -xvf node-v18.0.0-linux-x64.tar.xz

sudo cp -r node-v18.0.0-linux-x64/{bin,include,lib,share} /usr/

node --version


Install Yarn


sudo npm install -g yarn

Check Yarn version: yarn -v

Install Docker


Update packages: sudo apt-get update

Install dependencies:


sudo apt-get install \

  ca-certificates \

  curl \

  gnupg \

  lsb-release


Add Docker GPG key: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Set up the Docker repository:


echo \

  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \

  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null


Update packages: sudo apt-get update

Install Docker components:


sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin


Check available Docker versions: apt-cache madison docker-ce

Install specific Docker version:


sudo apt-get install docker-ce=5:20.10.15~3-0~ubuntu-jammy docker-ce-cli=5:20.10.15~3-0~ubuntu-jammy containerd.io docker-compose-plugin


Check Docker version: docker --version

Docker version 20.10.14, build a224086

Relevant links:

https://docs.docker.com/engine/install/ubuntu/

https://docs.docker.com/engine/reference/commandline/compose_up/

Install build-essential: sudo apt-get install build-essential

Development password


Generated security password: fd0d45ac-a09e-451c-babf-30df78530741

Note: This generated password is for development use only. Your security configuration must be updated before running your application in production

Friday, April 07, 2023

Cloud Init Modules

 Cloud-init modules, also known as "cloud-config modules," help automate the provisioning and configuration of servers. When provisioning a server for a Ruby on Rails application, you can use various cloud-init modules to set up your server environment, install required packages, and configure your application. Here are some useful cloud-init modules to consider:


package_upgrade: This module upgrades all packages on the system to their latest versions. It's useful for ensuring that the server starts with the latest security updates and package fixes.


package_upgrade: true



packages: This module installs a list of specified packages. For a Rails application, you may need to install packages such as Ruby, Node.js, Yarn, and a database server (e.g., PostgreSQL or MySQL).



packages:

  - ruby

  - nodejs

  - yarn

  - postgresql

  - postgresql-contrib



users: This module creates and configures system users. You might want to create a dedicated user for your Rails application.


users:

  - name: deploy

    groups: sudo

    shell: /bin/bash

    sudo: ['ALL=(ALL) NOPASSWD:ALL']

    ssh-authorized-keys:

      - <your_public_ssh_key>



write_files: This module writes content to specified files. You can use it to create configuration files, such as the Rails database.yml, environment files, or any other required configuration files.



write_files:

  - path: /home/deploy/my_app/shared/config/database.yml

    owner: deploy:deploy

    content: |

      production:

        adapter: postgresql

        encoding: unicode

        database: my_app_production

        pool: 5

        username: deploy

        password: mysecretpassword



runcmd: This module runs specified shell commands. It can be used to clone your Rails application repository, set up the database, run bundler, precompile assets, and start the Rails server.



runcmd:

  - sudo -u deploy -H git clone <your_app_repository> /home/deploy/my_app/current

  - sudo -u deploy -H bundle install --deployment --without development test --path /home/deploy/my_app/shared/bundle

  - sudo -u deploy -H yarn install --check-files --production

  - sudo -u deploy -H RAILS_ENV=production bundle exec rake db:create db:migrate

  - sudo -u deploy -H RAILS_ENV=production bundle exec rake assets:precompile

  - sudo -u deploy -H systemctl enable my_app

  - sudo -u deploy -H systemctl start my_app


These are just some examples of cloud-init modules that you can use to provision a server for your Ruby on Rails application. The specific modules and configurations will depend on your application's requirements and your chosen server environment.




To use environment variables for the database username and password in the database.yml file, you can utilize the ERB (Embedded Ruby) syntax. Here's an example:



production:

  adapter: postgresql

  encoding: unicode

  database: my_app_production

  pool: 5

  username: <%= ENV['DB_USERNAME'] %>

  password: <%= ENV['DB_PASSWORD'] %>


In this example, the DB_USERNAME and DB_PASSWORD environment variables are used to set the username and password for the PostgreSQL database connection.


Before running your Rails application, make sure to set these environment variables in your server environment. You can do this in several ways:


Set the environment variables in your server's environment or user's .bashrc or .bash_profile file:


export DB_USERNAME=my_db_user

export DB_PASSWORD=my_db_password



If you're using a process manager like systemd or Supervisor, you can set the environment variables in the service configuration file.

For example, with systemd, you can create a service file /etc/systemd/system/my_app.service:



[Unit]

Description=My Rails App


[Service]

User=deploy

WorkingDirectory=/home/deploy/my_app/current

Environment="DB_USERNAME=my_db_user"

Environment="DB_PASSWORD=my_db_password"

ExecStart=/bin/bash -lc 'bundle exec puma -C config/puma.rb'

Restart=always


[Install]

WantedBy=multi-user.target



If you're using a tool like dotenv or Figaro, you can set environment variables in your Rails app using a configuration file such as .env or config/application.yml. These files should not be added to your version control system.

For example, with the dotenv gem, create a .env file in your Rails app root directory:



DB_USERNAME=my_db_user

DB_PASSWORD=my_db_password



Don't forget to add the dotenv gem to your Gemfile and load it in the config/application.rb file:



# Gemfile

gem 'dotenv-rails', groups: [:development, :test]


# config/application.rb

require 'dotenv/load'



These are just a few methods for setting environment variables for your Rails application. Choose the one that best suits your deployment strategy and server environment.






To use environment variables for the database username and password in the database.yml file within the cloud-init configuration, you can use the ERB (Embedded Ruby) syntax and add the runcmd module to export the environment variables. Here's the revised cloud-init configuration:




write_files:

  - path: /home/deploy/my_app/shared/config/database.yml

    owner: deploy:deploy

    content: |

      production:

        adapter: postgresql

        encoding: unicode

        database: my_app_production

        pool: 5

        username: <%= ENV['DB_USERNAME'] %>

        password: <%= ENV['DB_PASSWORD'] %>


runcmd:

  - export DB_USERNAME=deploy

  - export DB_PASSWORD=mysecretpassword



However, keep in mind that this method of setting environment variables using runcmd is temporary and only applies to the current shell session. If you want to persist these variables for the deploy user, you should add them to the user's .bashrc or .bash_profile:



write_files:

  - path: /home/deploy/.bashrc

    owner: deploy:deploy

    append: true

    content: |

      export DB_USERNAME=deploy

      export DB_PASSWORD=mysecretpassword


  - path: /home/deploy/my_app/shared/config/database.yml

    owner: deploy:deploy

    content: |

      production:

        adapter: postgresql

        encoding: unicode

        database: my_app_production

        pool: 5

        username: <%= ENV['DB_USERNAME'] %>

        password: <%= ENV['DB_PASSWORD'] %>


This will add the environment variables to the .bashrc file of the deploy user, making them available for the Rails application.




Thursday, April 06, 2023

First Time Provisioning Setup for Rails

 #cloud-config

apt:

  sources:

    nodesource:

      source: "deb https://deb.nodesource.com/node_14.x $RELEASE main"

      keyid: "1655A0AB68576280"

    yarn:

      source: "deb https://dl.yarnpkg.com/debian/ stable main"

      keyid: "23E7166788B63E1E"


packages:

  - curl

  - git

  - build-essential

  - zlib1g-dev

  - libssl-dev

  - libreadline-dev

  - libyaml-dev

  - libsqlite3-dev

  - sqlite3

  - libxml2-dev

  - libxslt1-dev

  - libcurl4-openssl-dev

  - software-properties-common

  - libffi-dev

  - nodejs

  - yarn


runcmd:

  - sudo apt-add-repository -y ppa:rael-gc/rvm

  - sudo apt-get update

  - sudo apt-get install -y rvm

  - echo 'source "/etc/profile.d/rvm.sh"' >> ~/.bashrc

  - source ~/.bashrc

  - rvm install ruby

  - rvm use ruby --default

  - gem install bundler

  - gem install rails


final_message: "Rails stack is ready!"



Cloud-init is a versatile tool that helps you automate the configuration of new cloud instances. When using cloud-init, it's important to follow best practices to ensure your instances are configured efficiently, securely, and reliably. Here are some best practices for creating a cloud-init.yaml file:


Keep it modular and maintainable: Split your cloud-init.yaml into multiple files or sections to make it more modular and easier to maintain. Use the include directive to import other files, allowing you to organize your code and reuse common configurations.


Limit the use of scripts: Whenever possible, use cloud-init's built-in modules and directives to handle tasks like package installation and user management, rather than using custom scripts. This will make your configuration more declarative and easier to understand.


Use cloud-config syntax: The cloud-config syntax is more readable and easier to manage than shell scripts. It also ensures that actions are executed in the correct order, making your configuration more reliable.


Secure sensitive data: Avoid placing sensitive data like passwords or API keys directly in the cloud-init.yaml file. Instead, use a secure method to store and retrieve this information, such as environment variables, secrets management tools, or cloud provider-specific features.


Validate the syntax: Before applying your cloud-init.yaml file, validate the syntax using a YAML validator or a cloud-init validation tool like cloud-init devel schema to catch any syntax errors or issues.


Test and iterate: Test your cloud-init.yaml file on a non-critical environment before deploying it to production instances. This will help you identify and fix any issues or errors before they impact your production environment.


Document your configuration: Add comments to your cloud-init.yaml file to explain the purpose of each section, directive, or script. This will make it easier for others (or yourself) to understand and maintain your configuration in the future.


Keep your configuration up-to-date: Regularly review and update your cloud-init.yaml file to ensure it reflects the current state of your infrastructure and follows the latest best practices.


Use version control: Store your cloud-init.yaml file in a version control system like Git to track changes over time and collaborate with others.


Make it idempotent: Whenever possible, ensure that your cloud-init.yaml file can be run multiple times without causing unintended side effects. This can help prevent configuration drift and make it easier to recover from errors.


Let's apply additional best practices to the cloud-init YAML files I provided earlier.


Add a header to each file for better readability and understanding.


Use the package module and the user module to manage users and groups.


Use the write_files module with proper permissions for creating files.


Here's the revised version of the files:


packages.yaml



# Install necessary packages

# Filename: packages.yaml


packages:

  - postgresql

  - postgresql-contrib

  - libpq-dev

  - redis-server

  - build-essential

  - nodejs

  - yarn


postgres.yaml


# Set up PostgreSQL

# Filename: postgres.yaml


write_files:

  - content: |

      CREATE DATABASE myapp_production;

      CREATE USER myapp WITH PASSWORD 'secure_password';

      GRANT ALL PRIVILEGES ON DATABASE myapp_production TO myapp;

    path: /tmp/setup_postgres.sql

    permissions: '0644'


runcmd:

  - sudo -u postgres psql -f /tmp/setup_postgres.sql




ruby.yaml


# Install Ruby and Bundler

# Filename: ruby.yaml


runcmd:

  - curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash

  - echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc

  - echo 'eval "$(rbenv init -)"' >> ~/.bashrc

  - source ~/.bashrc

  - rbenv install 2.7.4

  - rbenv global 2.7.4

  - gem install bundler



rails_app.yaml


# Set up your Rails application

# Filename: rails_app.yaml


runcmd:

  - git clone https://github.com/your-username/your-rails-app.git /home/ubuntu/your-rails-app

  - cd /home/ubuntu/your-rails-app

  - bundle install

  - RAILS_ENV=production bundle exec rails db:migrate

  - RAILS_ENV=production bundle exec rails assets:precompile



sidekiq.yaml


# Set up Sidekiq as a systemd service

# Filename: sidekiq.yaml


write_files:

  - content: |

      [Unit]

      Description=Sidekiq Background Worker

      After=network.target


      [Service]

      Type=simple

      WorkingDirectory=/home/ubuntu/your-rails-app

      ExecStart=/bin/bash -lc 'bundle exec sidekiq -e production'

      Restart=always

      RestartSec=3

      User=ubuntu

      Group=ubuntu


      [Install]

      WantedBy=multi-user.target

    path: /tmp/sidekiq.service

    permissions: '0644'


runcmd:

  - sudo mv /tmp/sidekiq.service /etc/systemd/system/sidekiq.service

  - sudo systemctl enable sidekiq.service

  - sudo systemctl start sidekiq.service


And finally, the main cloud-init.yaml file:


#cloud-config


# Update package lists and upgrade packages

package_upgrade: true


# Include separate files

include:

  - packages.yaml

  - postgres.yaml

  - ruby.yaml

  - rails_app.yaml

  - sidekiq.yaml


These revisions apply better practices by adding headers, using proper modules for package installation and user management, and setting appropriate file permissions.




To ensure that all services start automatically when the server is rebooted, we need to enable them using the systemctl enable command. I've made the necessary changes to the YAML files. The only change required is in the sidekiq.yaml file:


sidekiq.yaml


# Set up Sidekiq as a systemd service

# Filename: sidekiq.yaml


write_files:

  - content: |

      [Unit]

      Description=Sidekiq Background Worker

      After=network.target


      [Service]

      Type=simple

      WorkingDirectory=/home/ubuntu/your-rails-app

      ExecStart=/bin/bash -lc 'bundle exec sidekiq -e production'

      Restart=always

      RestartSec=3

      User=ubuntu

      Group=ubuntu


      [Install]

      WantedBy=multi-user.target

    path: /tmp/sidekiq.service

    permissions: '0644'


runcmd:

  - sudo mv /tmp/sidekiq.service /etc/systemd/system/sidekiq.service

  - sudo systemctl enable sidekiq.service

  - sudo systemctl start sidekiq.service



The main cloud-init.yaml file remains the same:


cloud-init.yaml:


#cloud-config


# Update package lists and upgrade packages

package_upgrade: true


# Include separate files

include:

  - packages.yaml

  - postgres.yaml

  - ruby.yaml

  - rails_app.yaml

  - sidekiq.yaml


Now, the Sidekiq service will automatically start when the server is rebooted. Other services like PostgreSQL and Redis are already set to start automatically on boot by default when installed via package management.


You can create a separate cloud-init config file for the security updates and include it in your main cloud-init.yaml file using the include directive.


Create a separate file for security updates, let's call it security_updates.yaml:


# security_updates.yaml

package_upgrade: true

packages:

  - unattended-upgrades

  - update-notifier-common

write_files:

  - path: /etc/apt/apt.conf.d/20auto-upgrades

    content: |

      APT::Periodic::Update-Package-Lists "1";

      APT::Periodic::Download-Upgradeable-Packages "1";

      APT::Periodic::AutocleanInterval "7";

      APT::Periodic::Unattended-Upgrade "1";

  - path: /etc/apt/apt.conf.d/50unattended-upgrades

    content: |

      Unattended-Upgrade::Allowed-Origins {

          "${distro_id}:${distro_codename}-security";

      };


Now, update your main cloud-init.yaml file and include the security_updates.yaml file using the include directive:


#cloud-config

include:

  - security_updates.yaml


# Rest of the main cloud-init configuration


This way, you can maintain the security updates configuration separately and include it in the main cloud-init file when needed. This is especially helpful if you want to maintain modular and reusable configuration files.


#cloud-config
include:
  - security_updates.yaml

# Add the deploy user with sudo privileges
users:
  - name: deploy
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: sudo, adm
    shell: /bin/bash

# Rest of the main cloud-init configuration

Setup ssh-authorized-keys using Ansible playbook when customizing the prebuilt image for the customer.


Monday, April 03, 2023

Packages in Ubuntu

 Explain system package in Ubuntu in simple terms without using technical jargon


A system package in Ubuntu is like a pre-packaged box that contains a software program, or a set of related software programs, and all the necessary files and information needed to run that software on your Ubuntu computer.


When you want to use a new software on your computer, you would normally have to find it, download it, and install it. In Ubuntu, system packages make this process easier by organizing everything you need for a specific software into one neat package. You can think of it as a ready-to-use kit for that software.


Ubuntu has a tool called package manager, which is like a store that keeps track of all the available packages. You can browse through the available packages, choose the ones you want, and the package manager will automatically install them for you. This helps you keep your computer organized and up-to-date with the latest software.


Now define that term using technical terms


A system package in Ubuntu is a collection of files and metadata bundled together, which includes software applications, libraries, and other related resources required for the proper functioning of the software on the Ubuntu operating system.


System packages in Ubuntu are typically distributed in the DEB (Debian Package) format, which consists of binary executables, configuration files, dependency information, and installation instructions. These packages are managed through a package management system, such as APT (Advanced Package Tool) or dpkg, which handles package installation, removal, and updates.


The package management system maintains a repository, a central database of available packages and their metadata, including version numbers and dependency information. Package managers like APT or dpkg can automatically resolve dependencies, ensuring that all required packages are installed together with the desired package, and can also handle upgrades or removal of packages while preserving system stability.


Package management in Ubuntu streamlines the process of software installation and maintenance, providing an efficient and organized way to manage software applications and their dependencies within the operating system.


Why is called a "system" package?



The term "system package" is used because these packages not only include user-level applications but also encompass libraries, utilities, and other components that are critical for the proper functioning and maintenance of the operating system itself.


System packages serve as the building blocks of the Ubuntu operating system, providing the necessary software and resources to run, manage, and maintain the system. They consist of a wide variety of software, ranging from essential system components (such as the kernel, core libraries, and system utilities) to user applications (like text editors, web browsers, and media players).


By referring to these packages as "system packages," it highlights their role as a fundamental part of the operating system, managing both user-facing applications and critical system components. This terminology helps differentiate them from standalone software installations that are not managed by the package management system and do not follow the same structure or conventions.


What are examples of system package in ubuntu?


In Ubuntu, system packages can be found across a wide range of categories, including system utilities, libraries, and applications. Here are some examples of common system packages in Ubuntu:


libc6: The GNU C Library, which is a core component providing essential system functions and interfaces for the GNU/Linux operating system.

coreutils: A collection of basic file, shell, and text manipulation utilities for the GNU/Linux operating system.

bash: The Bourne-Again SHell, which is the default command-line shell in Ubuntu and many other Linux distributions.

gnupg: The GNU Privacy Guard, a tool for secure communication and data storage, implementing encryption and digital signatures.

openssh-server: The OpenSSH server, which provides secure remote login and file transfer capabilities using the SSH (Secure Shell) protocol.

apache2: The Apache HTTP Server, a widely-used web server software.

mysql-server: The MySQL database server, a popular open-source relational database management system.

python3: The Python 3 programming language interpreter, essential for running Python scripts and applications.

git: A distributed version control system, commonly used for managing source code in software development projects.

gimp: The GNU Image Manipulation Program, a powerful and versatile image editor.

These are just a few examples of the thousands of system packages available in Ubuntu. Each package serves a specific purpose, either as a standalone tool or as a dependency for other software, and is managed by the package management system to ensure a smooth and consistent user experience.



In Ubuntu, apart from system packages, there are other types of packages that are usually distinguished by their purpose, source, or the way they are maintained. Some of these package types include:


Snap packages: Snap packages (or snaps) are a newer packaging format introduced by Canonical, the company behind Ubuntu. Snaps are self-contained, which means they include all dependencies and can be installed alongside other versions of the same software. They are designed to work across multiple Linux distributions and provide easier updates and enhanced security.


Flatpak packages: Flatpak is another alternative packaging format for Linux distributions, designed to offer cross-distribution compatibility and simplified dependency management. Flatpak packages are self-contained and sandboxed, providing a consistent runtime environment and improved security.


AppImage packages: AppImage is a format for distributing portable software on Linux. An AppImage package is a single executable file that contains the application and all its dependencies, allowing it to run on any compatible Linux distribution without the need for installation or a package manager.


Source packages: Source packages contain the source code and build instructions for a software application, library, or utility. These packages allow users to compile and install the software from source, which can provide more control over the build process and enable customizations or optimizations.


Proprietary packages: Proprietary packages are software packages distributed by their developers or vendors that may not be open-source and might require a license to use. These packages can be in various formats, including DEB, Snap, or custom installers, and may not always be available through the official Ubuntu repositories.


Third-party packages: Third-party packages are software packages that are not included in the official Ubuntu repositories but are provided by external developers or vendors. These packages may be distributed in various formats, such as DEB, Snap, Flatpak, or AppImage, and can be obtained from third-party repositories or directly from the developers' websites.


Each of these package types serves a different purpose and has its own advantages and drawbacks. However, they all aim to simplify software distribution, installation, and management on Ubuntu and other Linux distributions.










Sunday, April 02, 2023

Packer File to Build Image

 {

  "variables": {

    "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",

    "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",

    "region": "us-west-2"

  },

  "builders": [

    {

      "type": "amazon-ebs",

      "access_key": "{{user `aws_access_key`}}",

      "secret_key": "{{user `aws_secret_key`}}",

      "region": "{{user `region`}}",

      "source_ami_filter": {

        "filters": {

          "virtualization-type": "hvm",

          "name": "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*",

          "root-device-type": "ebs"

        },

        "owners": ["099720109477"],

        "most_recent": true

      },

      "instance_type": "t2.micro",

      "ssh_username": "ubuntu",

      "ami_name": "ubuntu-20.04-{{timestamp}}",

      "force_deregister": true

    }

  ],

  "provisioners": [

    {

      "type": "shell",

      "inline": [

        "sudo apt-get update",

        "sudo apt-get upgrade -y",

        "sudo apt-get install -y nginx"

      ]

    }

  ]

}

packer build ubuntu-20.04.json

Thursday, March 30, 2023

Omega Life View - Skill Attribute

 I want you to imagine a person with no devops skills and a devops expert. What are the attributes related to provisioning and deployment product?


When considering provisioning and deployment tools for a person with no DevOps skills versus a DevOps expert, the attributes and requirements will likely differ due to the differences in skill level, experience, and familiarity with relevant technologies. Here are some attributes for each scenario:


Person with no DevOps skills:


Ease of use: A tool with a simple, intuitive user interface is crucial for someone new to DevOps.

Guided workflows: Step-by-step processes and clear instructions can help beginners navigate the deployment and provisioning process.

Built-in templates: Pre-configured templates for common deployment scenarios can simplify the learning curve.

Documentation and tutorials: Comprehensive documentation and learning resources are necessary to help beginners grasp the tool's capabilities and best practices.

Basic functionality: The tool should cover essential deployment and provisioning needs without excessive complexity or features.

Community support: Access to community resources or forums can be helpful for troubleshooting and learning.

DevOps expert:


Advanced functionality: Support for complex deployment scenarios, such as rolling deployments, blue-green deployments, and canary releases.

Customization and flexibility: The tool should provide options for customization and adaptability to different environments and workflows.

Integration capabilities: The ability to integrate with existing tools and systems, such as CI/CD pipelines, monitoring tools, and configuration management solutions.

Automation features: A DevOps expert will benefit from tools that support advanced automation for streamlining deployment and provisioning tasks.

Extensibility: The ability to extend the tool's functionality through plugins, APIs, or scripting languages.

Cross-platform and multi-cloud support: A DevOps expert may need to manage deployments across various platforms, operating systems, and cloud providers.

The specific requirements may vary depending on the individual's goals and the nature of the projects they are working on. However, these attributes can help differentiate between the needs of a person with no DevOps skills and a DevOps expert.