GraphQL & React & Docker

Sebastian Wachter, Christophe Hoste, Immanuel Haag, Axel Forstenhäusler

Live slides & excersies

What is GraphQL?

QL  The "QL" in GraphQL stands for query language.

Graph  The "Graph" in GraphQL refers to the organized data on the application server in a graph structure.

What is GraphQL?

  • New API standard, alternative to REST
  • Invented & open sourced by Facebook
  • Declarative data fetching
    • Specify exactly what you want from the API
  • ONE single endpoint

Why GraphQL?

  • Increased mobile usage
  • Different clients
  • Sloppy Networks
  • Backend and frontend team communication

Initial reasons

Not only for React developers!

  • C# .Net
  • Clojure
  • Elixir
  • Erlang
  • Go
  • Groovy

Server libraries for GraphQL:

  • Java
  • JavaScript
  • PHP
  • Python
  • Scala
  • Ruby

Client side: 

Any programming language

Additional informations

Companies using GraphQL:

Who is using GraphQL: https://graphql.org/users/

Conferences:

  • San Francisco - GraphQL Summit in October
  • Berlin - GraphQL Conf. Berlin in June

Request - Response

Blogging App

REST

GET api/users/:id

{
  "id": "42",
  "email": "alice@bob.gql",
  "firstname": "Alice",
  "lastname": "Bob",
  …
}

REST

GET api/users/:id/posts

{
  "posts": [
    {
      "id": "1",
      "title": "Title 1",
      "published": true,
      "createdAt": "2019-04-10T18:29:16.983Z",
      "content": "lorem ipsum ..."
    },
    …
  ]
}

GraphQL

POST /graphql

query {
  user(where: {
    id: "42"
  }) {
    firstname
    posts(last: 3) {
      title
      published
    }
  }
}
{
  "data": {
    "user": {
      "firstname": "Alice",
      "posts": [
        {
          "title": "Title 1",
          "published": true
        },
        …
      ]
    }
  }
}

GraphQL prevents

{
  "id": "42",
  "email": "alice@bob.gql",
  "firstname": "Alice",
  "lastname": "Bob",
  … posts are missing
}
Underfetching Overfetching
{
  "posts": [
    {
      "id": "1",
      "title": "Title 1",
      "published": true,
      "createdAt": "2019-04-10T18:29:16.983Z",
      "content": "lorem ipsum ..."
    },
    …
  ]
}
  • Imagine showing comments for every post!

=> 3 additional requests (api/posts/:id/comments)

Different clients - Web-Browser

How does GraphQL work?

  • GraphQL is only a specifiation, not a concrete implementation!

GraphQL Resolvers

export const Query: QueryResolvers.Type = {

  post: (parent, args, ctx) => {
    return ctx.data.posts.find(post => post.id === args.id)!
  },
}
type Query {
  post(id: ID!): Post
}

type Mutation {
  createUser(name: String!): User!
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
  author: User!
}

type User {
  id: ID!
  name: String
  posts: [Post!]!
}

GraphQL Resolvers

export const Mutation: MutationResolvers.Type = {
  createUser: (parent, { name }, ctx) => {
    const id = ctx.data.idProvider()
    const newUser = { id, name, postIDs: [] }
    ctx.data.users.push(newUser)
    return newUser
  }
}
type Query {
  post(id: ID!): Post
}

type Mutation {
  createUser(name: String!): User!
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
  author: User!
}

type User {
  id: ID!
  name: String
  posts: [Post!]!
}

GraphQL Resolvers

export const Post: PostResolvers.Type = {
  ...PostResolvers.defaultResolvers,

  author: (parent, args, ctx) => {
    return ctx.data.users.find(user => user.id === parent.authorId)!
  },
}
type Query {
  post(id: ID!): Post
}

type Mutation {
  createUser(name: String!): User!
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
  author: User!
}

type User {
  id: ID!
  name: String
  posts: [Post!]!
}

GraphQL Resolvers

export const User: UserResolvers.Type = {
  ...UserResolvers.defaultResolvers,

  posts: ({ postIDs }, args, ctx) => {
    return ctx.data.posts.filter(post => postIDs.includes(post.id))
  },
}
type Query {
  post(id: ID!): Post
}

type Mutation {
  createUser(name: String!): User!
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
  author: User!
}

type User {
  id: ID!
  name: String
  posts: [Post!]!
}

Prisma

CRUD resolvers are generated for us when using Prisma!

GraphQL Schema Definition Language (SDL)

type Post {
  id: ID! @id
  createdAt: DateTime! @createdAt
  updatedAt: DateTime! @updatedAt
  title: String!
  content: String!
  published: Boolean! @default(value: false)
  author: User! @relation(name: "PostsByUser")
}

type User {
  id: ID! @id
  email: String! @unique
  firstname: String!
  lastname: String!
  createdAt: DateTime! @createdAt
  updatedAt: DateTime! @updatedAt
  imgUrl: String
  posts: [Post!]! @relation(name: "PostsByUser", onDelete: CASCADE)
}

GraphQL Schema Definition Language (SDL)

Scalar Types

  • Int
  • Float
  • String
  • Boolean
  • ID
  • DateTime

Field

  • name and type
  • age: Int
  • age: Int!

Lists

  • square brackets
  • names: [String!]
  • names: [String!]!

Schema Directive

  • @defaultValue
  • @unique
  • @relation
  • @id
  • @createdAt
  • @updatedAt

More

  • Enum
  • Interfaces

Queries - Simple

query {
  users {
    id
    email
    firstname
    lastname
  }
}
{
  "data": {
    "users": [
      {
        "id": "cjultjpjk41t70b95ltbteew0",
        "email": "af096@hdm-stuttgart.de",
        "firstname": "Axel",
        "lastname": "Forstenhäusler"
      },
      {
        "id": "cjultojzy3j380b22vhjmyfck",
        "email": "ch152@hdm-stuttgart.de",
        "firstname": "Christophe",
        "lastname": "Hoste"
      }
    ]
  }
}

Queries - Nested

query {
  users {
    firstname
    posts {
      published
      title
    }
  }
}
{
  "data": {
    "users": [
      {
        "firstname": "Axel",
        "posts": [
          {
            "published": false,
            "title": "Post 1"
          },
          {
            "published": false,
            "title": "Post 2"
          }
        ]
      },
      {
        "firstname": "Christophe",
        "posts": [
          {
            "published": false,
            "title": "Post 3"
          }
        ]
      }
    ]
  }
}

Queries - Filtering

query {
  user(where: {
    email: "af096@hdm-stuttgart.de"
  }) {
    firstname
    posts {
      published
      title
    }
  }
}
{
  "data": {
    "user": {
      "firstname": "Axel",
      "posts": [
        {
          "published": false,
          "title": "Post 1"
        },
        {
          "published": false,
          "title": "Post 2"
        }
      ]
    }
  }
}

Queries - Filtering

query {
  users(where: {
    email_contains: "@hdm-stuttgart.de"
  }) {
    firstname
    posts {
      published
      title
    }
  }
}
{
  "data": {
    "users": [
      {
        "firstname": "Axel",
        "posts": [
          {
            "published": false,
            "title": "Post 1"
          },
          {
            "published": false,
            "title": "Post 2"
          }
        ]
      },
      {
        "firstname": "Christophe",
        "posts": [
          {
            "published": false,
            "title": "Post 3"
          }
        ]
      }
    ]
  }
}

Operators

  • _not
  • _in
  • _not_in
  • _lt(e)
  • _gt(e)
  • _contains
  • _not_contains
  • _starts_with
  • _not_starts_with
  • _ends_with
  • _not_ends_with
  • _every
  • _some
  • _none

Queries - Ordering & Pagination

query {
  users(
    orderBy: id_ASC // or DESC
    first:/*or last*/ 30
    after:/*or before*/ "cjultjpjk41t70b95ltbteew0" // id of Axel
  ) {
    firstname
    posts {
      published
      title
    }
  }
}
{
  "data": {
    "users": [
      {
        "firstname": "Christophe",
        "posts": [
          {
            "published": false,
            "title": "Post 3"
          }
        ]
      }
    ]
  }
}

Mutation - Create

mutation {
  createUser(data: {
    email: "sw200@hdm-stuttgart.de"
    firstname: "Sebastian"
    lastname: "Wachte"
  }) {
    id
    email
  }
}
{
  "data": {
    "createUser": {
      "id": "cjumf4py79m8p0b95wgbwt2mp",
      "email": "sw200@hdm-stuttgart.de"
    }
  }
}

Mutation - Create & Connect

mutation {
  createPost(data: {
    title:"Post 4",
    content:"Content 4",
    author: {
      connect: {
        email: "sw200@hdm-stuttgart.de"
      }
    }
  }) {
    id
    title
    author {
      id
      email
    }
  }
}
{
  "data": {
    "createPost": {
      "id": "cjumf6ofb9mpx0b95c98y1vy4",
      "title": "Post 4",
      "author": {
        "id": "cjumf4py79m8p0b95wgbwt2mp",
        "email": "sw200@hdm-stuttgart.de"
      }
    }
  }
}

Mutation - Update

mutation {
  updateUser(where: {
    email: "sw200@hdm-stuttgart.de"
  } data: {
    lastname: "Wachter"
  }) {
    id
    email
    firstname
    lastname
  }
}
{
  "data": {
    "updateUser": {
      "id": "cjumf4py79m8p0b95wgbwt2mp",
      "email": "sw200@hdm-stuttgart.de",
      "firstname": "Sebastian",
      "lastname": "Wachter"
    }
  }
}

Mutation - Upsert

mutation {
  upsertUser(where: {
    email: "sw200@hdm-stuttgart.de"
  } create: {
    firstname: "Sebastian"
    lastname: "Wachter"
    email: "sw200@hdm-stuttgart.de"
  } update: {
    lastname: "Wachter"

  }) {
    id
    email
    firstname
    lastname
  }
}
{
  "data": {
    "upsertUser": {
      "id": "cjumf4py79m8p0b95wgbwt2mp",
      "email": "sw200@hdm-stuttgart.de",
      "firstname": "Sebastian",
      "lastname": "Wachter"
    }
  }
}

Mutation - Delete

mutation {
  deleteUser(where: {
    email: "sw200@hdm-stuttgart.de"
  }) {
    id
    email
  }
}
{
  "data": {
    "deleteUser": {
      "id": "cjumf4py79m8p0b95wgbwt2mp",
      "email": "sw200@hdm-stuttgart.de"
    }
  }
}

Subscriptions

subscription {
  user(where: {
    mutation_in: [CREATED, UPDATED, DELETED]
  }) {
    mutation
    node {
      lastname
    }
    previousValues {
      lastname
    }
    updatedFields
  }
}
{
  "data": {
    "user": {
      "mutation": "UPDATED",
      "node": {
        "lastname": "Wachte"
      },
      "previousValues": {
        "lastname": "Wachter"
      },
      "updatedFields": [
        "lastname",
        "updatedAt"
      ]
    }
  }
}

Deploy a test application

npm install -g prisma
mkdir hello-world
cd hello-world
# you will need a prisma account
prisma init
# choose Demo server + MySQL database
# choose a name
# choose a stage (dev)
# choose Don't generate
prisma deploy
type User {
  id: ID! @id
  name: String!
}
endpoint: https://eu1.prisma.sh/forstenhaeusleraxel/hello-world/dev
datamodel: datamodel.prisma

Deploy locally with docker

npm install -g prisma
mkdir hello-world
cd hello-world
# you will need a prisma account
prisma init
# choose Create new database
# choose MySQL
# choose Don't generate
docker-compose up -d
prisma deploy
type User {
  id: ID! @id
  name: String!
}
endpoint: http://localhost:4466
datamodel: datamodel.prisma
docker-compose.yml

Challenges and outlook

  • Authentication
  • Permission Queries

Graphcool (BaaS)

=> Resolvers are needed

  • Authorization
query ($user_id: ID!, $node_id: ID!) {
  SomeUserExists(
    filter: {
      OR: [{
        AND: [
          {id: $user_id}
          {id: $node_id}
        ]
      }, {
        AND: [
          {id: $user_id}
          {role: ADMIN}
        ]
      }]
    }
  )
}

Additional informations

Wrapping existing REST-API in GraphQL

Use existing database in GraphQL

JSX & React introduction

Introduction

Names:

React / React.js or React JS 

 

 

A JavaScript library for building user interfaces.

React JS !== React Native

Introduction

History

 

Initial release: May 2013

 

   Created by Jordan Walke

at Facebook.

 

 

Introduction

Current state: 16.8.6 (March 27, 2019)

Used by:

 

 

 

 

 

 

Introduction

Hello-World example:

 

 

 

 

 

 

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('app')
);

JSX

JavaScript XML / JavaScript Syntax Extension

Extension of the common JavaScript grammar for React

 

JSX is not valid JavaScript so it needs to be compiled to be browser conformant

Example:

const heading = <h1>This is JSX</h1>;

JSX

In React the render logic is coupled with UI logic so it explains:

  • How events get handled
  • How state is changed 
  • How data is rendered

⇒ loosely coupled units called "components" *

Example:

const Nav = () => (
  <ul id="nav">
    <li><a href="#">item1</a></li>
    <li><a href="#">item2</a></li>
  </ul>
);

*Components will be explained later

JSX

JSX needs to be compiled to JavaScript to be executable by a browser

Example:

const Nav = () => React.createElement("ul", {
  id: "nav"
}, React.createElement("li", null, React.createElement("a", {
  href: "#"
}, "item1")), React.createElement("li", null, React.createElement("a", {
  href: "#"
}, "item2")));
const Nav = () => (
  <ul id="nav">
    <li><a href="#">item1</a></li>
    <li><a href="#">item2</a></li>
  </ul>
);

Will be compiled to:

JSX

If you don't want to use JSX give this projects a try:

JSX-Expressions

Render a variable using curly braces {}

const name = 'Axel Forstenhäusler';
const element = <h1>Hello, {name}!</h1>;

ReactDOM.render(
  element,
  document.getElementById('app')
);

// Expected output: Hello, Axel Forstenhäusler!

JSX-Expressions

all valid JavaScript expressions are available
(+,-,*, ...)

 

const formatName = ({ firstname, lastname }) => `${firstname} ${lastname}`;

const user = {
  firstName: 'Axel',
  lastName: 'Forstenhäusler'
};

const element = (
  <h1>Hello, {formatName(user)}!</h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

// Expected output: Hello, Axel Forstenhäusler!

JSX-Expressions

Since JSX is basically JavaScript you can use all methods, statements and operators like .map, if, ternary, etc.

const getGreeting = (user) => {
  if (user) return <h1>Hello, {formatName(user)}!</h1>;
  return <h1>Hello, Stranger.</h1>;
}

JSX-Attributes

Use quotes to specify string literals as attributes:

const button = <button tabIndex="0">Click!</button>;

Use curly braces to embed JavaScript expressions in an attribute/prop

const image = <img src={avatarUrl} alt="avatar" />;

React DOM: camelCase property naming convention instead of HTML attribute names

For example:

class becomes className

tabindex becomes tabIndex

List rendering

In JSX you just loop over the array and return the JSX you want to render:

const persons = [
  'Axel',
  'Christophe',
  'Immanuel',
  'Sebastian',
];

const App = () => persons.map(person => <p>{person}</p>);


// Expected result:
// Axel
// Christophe
// Immanuel
// Sebastian

Components

Components

Like other frameworks React is based on  components.

Therefore the application consists of logically separated and reusable units.

There are two different types of components in React:

  • functional components

  • class components

Components - differences

Functional components:

const Welcome = ({ name }) => <h1>Hello, {name}!</h1>;

These are called "functional component" because they are literal JavaScript functions.

They also cannot have state or access

class Welcome extends React.Component {
  render() {
    const { name } = this.props;
    return <h1>Hello, {name}</h1>;
  }
}

Class components:

These may have state and may access component lifecycle hooks as well.

State

State represents a component's data. A component is able to modify its state by itself. State may also be passed to child components using props.

class App extends React.Component {
  state = {
    message: 'Hello I am a state message!',
  };

  handleClick = () => {
    const { message } = this.state;
    const newMessage = message.split('').reverse().join('');
    this.setState({ message: newMessage });
  }

  render() {
    const { message } = this.state;
    return (
      <div>
        <h1>{message}</h1>
        <button onClick={this.handleClick}>Reverse message</button>
      </div>
    );
  }
}

Modifying State

You may modify a component's state using events and corresponding handler functions.

class App extends React.Component {
  state = {
    message: 'Hello I am a state message!',
    value: '',
  };

  handleClick = () => {
    const { message } = this.state;
    this.setState({ message: message.split('').reverse().join('') });
  }

  handleChange = (e) => {
    this.setState({ value: e.currentTarget.value });
  }

  render() {
    const { message, value } = this.state;
    return (
      <div>
        <p>{message}</p>
        <button onClick={this.handleClick}>Reverse message</button>
        <p>{value}</p>
        <input type="text" value={value} onChange={this.handleChange} />
      </div>
    );
  }
}

State

Things to remember about state in React:

Do not modify state directly (make local copies and use setState):

handleClick = () => {
  const { data } = this.state;
  data = `I modify ${data} now.`;
  this.setState({ data });
}

Remember that setState is async!

Components - Props

"Props" stands for properties.

Using props we may pass data from a parent to a child component.

const Parent = () => <Child content="I got passed by the parent"/>;

const Child = ({ content }) => (
  <>
    <h3>I render the passed data:</h3>
    <p>{content}!</p>
  </>
);

// Expected result:
// I render the passed data:
// I got passed by the parent!

The child component may not modify the prop data. To do that it has to emit an event to the parent which will modify it according to its business logic.

Components

Components can refer to other components

Example: an App component which renders several Welcome components

const Welcome = ({ name }) => <h1>Hello, {name}!</h1>;

const App = () => (
  <>
    <Welcome name="Axel" />
    <Welcome name="Christophe" />
    <Welcome name="Immanuel" />
  </>
);

// Expected output:
// Hello, Axel!
// Hello, Christophe!
// Hello, Immanuel!

Conditional rendering

There are multiple ways to render JSX conditionally:

const IfExample = () => {
  if (trueStatement) return <h1>True case</h1>;
  return <h1>False case</h1>;
}

const InlineExample = () => trueStatement ? <h1>True case</h1> : <h1>False case</h1>;

const OnlyTrue = () => (
  <>
    {unreadMessages.length > 0 &&
      <h2>You have {unreadMessages.length} unread messages.</h2>
    }
  </>
);

Components

Usually React applications have an App component as their entry point.

 

Splitting business logic into small reusable components is recommended.

Routing - Router

To enable routing in React you need to wrap your app between one of five router components:

import { BrowserRouter, HashRouter, MemoryRouter, Router, StaticRouter } from 'react-router';

BrowserRouter: Uses HTML5 history API (/newsfeed)

HashRouter: Uses a hash portion of the URL (#/newsfeed)

MemoryRouter: Keeps URL in memory (useful for Native)

Router: Low-level interface for other router components

StaticRouter: Never changes its location (server side rendering)

Routing - Route

The Route component defines which component should be rendered matching the URL.

Route parameters can be accessed through a prop.

import { Route, Redirect, Link } from 'react-router-dom';
<Route path="/news" component={News} />
<Route path="/users" exact component={ProfileList} />
<Route path="/users/:id" component={SingleProfile} />

Routing - Link

A Link component defines a link which leads to a route.

import { Route, Redirect, Link } from 'react-router-dom';
<Link to="/news">Navigate to newsfeed</Link>

Routing - Redirect

A Redirect component is used to lead the user somewhere else.
For example after a successful login redirect the user to the newsfeed

import { Route, Redirect, Link } from 'react-router-dom';
<Redirect to="/news" />

React & GraphQL

Packages

To use GraphQL together with React we will use the React Apollo Client.

What we need:

Apollo Boost: helps setting up an Apollo Client

React Apollo: View layer intergration of Apollo Client for React

GraphQL Tag: Parsing the GraphQL queries

Get started

Create a client:

import ApolloClient from 'apollo-boost';
import { gql } from 'graphql-tag';
import { ApolloProvider } from 'react-apollo';
const App = () => (
  <ApolloProvider client={client}>
    ... Your app here
  </ApolloProvider>
);
const client = new ApolloClient({
  uri: 'https://eu1.prisma.sh/forstenhaeusleraxel/evwa/dev',
});

Connect your client to React:
To access Apollo's features you need to wrap your app into the ApolloProvider:

Now we are ready to use!

Get started

Create a client:

import ApolloClient from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
const App = () => (
  <ApolloProvider client={client}>
    ... Your app here
  </ApolloProvider>
);
const client = new ApolloClient({
  uri: '<your-url>',
});

Connect yout client to React:
To access Apollo's features you need to wrap your app into the ApolloProvider:

Request data

To request data we use the Query component of react-apollo:

const GET_PLANTS = gql`
  {
    plants {
      name
      type
    }
  }
`;
import gql from 'graphql-tag';
import { Query } from 'react-apollo';

After that we write our query using graphql-tag:

Pass the query to the Query component and render the response data:

<Query query={GET_PLANTS} fetchPolicy="network-only">
  {({ loading, error, data }) => {
    if (loading) return 'Loading...';
    if (error) return `Error! ${error.message}`;

    return data.plants.map(({ name, type }) => (
      <div key={name}>
        <p>Name: {name}</p>
        <p>Type: {type}</p>
      </div>
    ));
  }}
</Query>

Request specific data

const GET_PLANT = gql`
  query Plant($name: String!) {
    plants(where: { name: $name }) {
      type
      size
    }
  }
`;

To request specific data we need to define the query differently. GraphQL also checks whether the passed variable is of the correct type (in this case String).

Using the Query component we can pass a variables object:

<Query query={GET_PLANT} variables={{ name: 'ivy' }} fetchPolicy="network-only">
  {({ loading, error, data }) => {
    if (loading) return 'Loading...';
    if (error) return `Error! ${error.message}`;
    const [{ type, size }] = data.plants;

    return (
      <>
        <p>Type: {type}</p>
        <p>Size: {size}</p>
      </>
    )
  }}
</Query>

Mutate data 1

For all kinds of mutations Apollo provides a Mutation component:

const CREATE_PLANT = gql`
  mutation CreatePlant(
    $name: String!
    $type: String!
    $size: Int!
  ) {
    createPlant(data: {
      name: $name
      type: $type
      size: $size
    }) {
      name
    }
  }
`;
import gql from 'graphql-tag';
import { Mutation } from 'react-apollo';

We define the mutation using graphql-tag again:

Mutate data 2

<Mutation mutation={ADD_TODO} ignoreResults>
  {createPlant => (
    <form
      onSubmit={e => {
        e.preventDefault();
        createPlant({ variables: { name: name.value, type: type.value, size: size.value } });
      }}
    >
      <input ref={node => name = node} type="text" placeholder="Name"/>
      <input ref={node => type = node} type="text" placeholder="Type"/>
      <input ref={node => size = node} type="number" placeholder="Size"/>
      <button type="submit">Add plant</button>
    </form>
  )}
</Mutation>

Now we can pass the GraphQL statement to the Mutation component. We mutate data using a form and the React onSubmit handler.

We get the values from the inputs and pass them to the GraphQL statement:

Wrap up

Docker

   Introduction - Docker

  • release of Docker as Open Source Project (2013)
  • slogan: “Build, Ship, Run”
  • ease of packaging and deploying applications
  • focused on usability
  • trigger for DevOps movement

Container Technologies

Success Stories

Success Stories

  • 200+ Dockerized Apps
  • Increased infrastructure efficiency by reducing the number of VMs.
  • Increased agility and achieved rapid response to evolving customer needs.
  • Achieved more application portability over multiple environments.  

    Saved time, money and resources.

Success Stories

Docker != Container

user-friendly "Framework" / "Ecosystem" for handling Containers!

  • Docker Client:

for interaction with Docker Daemon
shares a UNIX socket with the daemon

  • Docker Daemon:

connects to the same UNIX socket as the client
responsible for starting, stopping and monitoring containers

  • Docker Hub:

public registry for Docker images​

Today? Not only Containers

Technical Stuff

  • A software container is very similar to a shipping container  ​

 

  • Simply package a piece of software along with everything that is needed to make it work.

 

  • Software containers: isolated working environments for an application.
    With necessary:
    • dependencies
    • libraries
    • binaries
    • configurations

Technical Stuff

  • Containers depend on an image layer system (reduces duplication, enables reusability & security) --> docker hub registry 

 

  • A Container is a Linux process, or many processes, which are running isolated from other processes on the system, using the chroot system call and some Linux kernel features such as cgroups and namespaces.

 

But why not simply use a VM? 

Technical Stuff

VM

Container

VM vs. Container

 

VMs

  • Virtualize a complete operating system (OS)
  • Virtualize the kernel of the host
  • Heavyweight
  • Suffer from a small overhead as the Machine instructions are translated from Guest to Host OS
  • Take a few mins to boot up
  • Take much more storage as the whole OS kernel and its associated programs have to be installed and run

Containers

  • Virtualize the required file system
  • Use/share the kernel of the host
  • Lightweight
  • Provide near-native performance as compared to the underlying Host OS
  • Can be booted up in a few secs as compared to VMs (testing & CI/CD)
  • Take a lower amount of storage as the base OS is shared

Docker Workflow/Lifecycle

FROM ubuntu:xenial

RUN apt-get update

RUN apt-get install -y nginx php7.0-fpm supervisor && \
    rm -rf /var/lib/apt/lists/*

...

docker build -t mysuperimage  .

mysuperimage:v2

mysuperimage:v2

   Web-Dev & Docker?

Why should Devs know Docker?

 

 

 

   Web-Dev & Docker?

Demo

 

source: https://insights.stackoverflow.com/survey/2019#key-results

   Web-Dev & Docker?

  1. Build, Ship, Run principle
     
  2. No more "but this works on my machine" fails
     
  3. Test new software really quick
     
  4. Sandbox your software --> keep your laptop clean (Spotify in container etc)  
     
  5. Transition into cloud & CI/CD pipeline ready software!

--> State of the art! --> $​

Example 1

Docker hello-world and run a ubuntu based container 

 

Live Demo

 

Recorded example

Example 1

Live Demo Prisma Setup

version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.31
    restart: always
    ports:
    - "4466:4466"
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: mysql
            host: mysql
            user: root
            password: prisma
            rawAccess: true
            port: 3306
            migrations: true
  mysql:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: prisma
    volumes:
      - mysql:/var/lib/mysql
volumes:
  mysql:

Requirements:

- Docker installed

- NPM installed

- CLI :)

To-Do:

$ npm install -g prisma
$ mkdir hello-world && cd hello-world
$ prisma init (create new database -> MySQL -> don't generate)


 

 

$ docker-compose up -d
 

$prisma deploy

Example 2

Live React Setup Demo 

 

Try it yourself

GraphQL

By Axel Forstenhäusler

GraphQL

GraphQL introduction and comparison to REST

  • 560