|
| 1 | +# Shipping |
| 2 | + |
| 3 | +_Ahoy, matey!_ |
| 4 | +Oh! you've built the greatest app ever and, of course, using Crystal!! |
| 5 | +And now you want to share it with the whole world?! |
| 6 | + |
| 7 | +Well, it’s your lucky ~~pirate~~ day because we are going to ship our first Crystal application!! |
| 8 | + |
| 9 | +So, _weigh anchor and hoist the mizzen! Yarr!_ |
| 10 | + |
| 11 | +## The App |
| 12 | + |
| 13 | +The application we are shipping is an example of a static file sharing server. Here’s the source code: |
| 14 | + |
| 15 | +```crystal |
| 16 | +# staticserver.cr |
| 17 | +require "http" |
| 18 | +require "option_parser" |
| 19 | +
|
| 20 | +# Handle Ctrl+C and kill signal. |
| 21 | +# Needed for hosting this process in a docker |
| 22 | +# as the entry point command |
| 23 | +Signal::INT.trap { puts "Caught Ctrl+C..."; exit } |
| 24 | +Signal::TERM.trap { puts "Caught kill..."; exit } |
| 25 | +
|
| 26 | +path = "/www" |
| 27 | +port = 80 |
| 28 | +
|
| 29 | +option_parser = OptionParser.parse do |parser| |
| 30 | + parser.on "-f PATH", "--files=PATH", "Files path (default: /www)" do |files_path| |
| 31 | + path = files_path |
| 32 | + end |
| 33 | + parser.on "-p PORT", "--port=PORT", "Port to listen (default: 80)" do |server_port| |
| 34 | + port = server_port.to_i |
| 35 | + end |
| 36 | +end |
| 37 | +
|
| 38 | +server = HTTP::Server.new([ |
| 39 | + HTTP::LogHandler.new, |
| 40 | + HTTP::ErrorHandler.new, |
| 41 | + HTTP::StaticFileHandler.new(path), |
| 42 | +]) |
| 43 | +
|
| 44 | +address = server.bind_tcp "0.0.0.0", port |
| 45 | +puts "Listening on http://#{address} and serving files in path #{path}" |
| 46 | +server.listen |
| 47 | +``` |
| 48 | + |
| 49 | +So, starting the server (listening on port 8080 and serving files under the current directory) is as easy as running: |
| 50 | + |
| 51 | +```shell-session |
| 52 | +$ crystal ./src/staticserver.cr -- -p 8080 -f . |
| 53 | +Listening on http://0.0.0.0:8080 and serving files in path . |
| 54 | +``` |
| 55 | + |
| 56 | +**Note:** the default behavior is to listen on `port 80` and serve the folder `/www`. |
| 57 | + |
| 58 | +## Compiling our application |
| 59 | + |
| 60 | +Let’s go over Crystal’s [introduction](https://crystal-lang.org/reference/). One of the main goals of the language is to _Compile to efficient native code_. That means that each time that we compile our code then an executable is built, but with an important property: it has a target platform (architecture and operating system), which is where the application will run. Crystal knows the target platform because is the same as the one being used to compile. |
| 61 | +For example, if we use a Linux OS based computer for compiling, then the executable will be meant to run on a Linux OS (and in some cases we will need to use the same Linux distribution). |
| 62 | + |
| 63 | +Can we set the target when calling the compiler? Oh, that’s a great idea, but for now it’s not an option (there are a lot of great buccanears [working on a solution](https://forum.crystal-lang.org/t/cross-compiling-automatically-to-osx/1330/12) and remember that Crystal is open source: so you are welcome aboard!) |
| 64 | + |
| 65 | +Let’s compile our application: |
| 66 | + |
| 67 | +```shell-session |
| 68 | +$ shards build --production |
| 69 | +Dependencies are satisfied |
| 70 | +Building: staticserver |
| 71 | +``` |
| 72 | + |
| 73 | +and now, if we want to know the file type: |
| 74 | + |
| 75 | +If we are using Mac OS, we will see something like this: |
| 76 | + |
| 77 | +```shell-session |
| 78 | +$ file bin/staticserver |
| 79 | +bin/staticserver: Mach-O 64-bit executable x86_64 |
| 80 | +``` |
| 81 | + |
| 82 | +And if we are using a Linux distribution, for example Ubuntu: |
| 83 | + |
| 84 | +```shell-session |
| 85 | +$ file bin/staticserver |
| 86 | +bin/staticserver: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=a78ffe59325c3f9668d551852e7717e3996edb3b, not stripped |
| 87 | +``` |
| 88 | + |
| 89 | + |
| 90 | +Furthermore, our application may use some libraries (our application’s dependencies!) and so the target platform should have this libraries installed. To list the libraries used by our application: |
| 91 | + |
| 92 | +On Mac OS: |
| 93 | + |
| 94 | +```shell-session |
| 95 | +$ otool -L ./bin/staticserver |
| 96 | +./bin/staticserver: |
| 97 | + /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11) |
| 98 | + /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0) |
| 99 | + /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0) |
| 100 | + /usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version 1.1.0) |
| 101 | + /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1) |
| 102 | + /usr/local/opt/libevent/lib/libevent-2.1.7.dylib (compatibility version 8.0.0, current version 8.0.0) |
| 103 | + /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0) |
| 104 | +``` |
| 105 | + |
| 106 | +On a Linux OS we may use `ldd bin/staticserver` with a similar result. |
| 107 | + |
| 108 | +Up to this point, we know that for shipping our application, we need to compile for each target platform where we want our application to run; and also, we need to provide the dependencies used by our application. |
| 109 | + |
| 110 | +Here we will see two ways for shipping our application: |
| 111 | + |
| 112 | +* Using a [Docker](https://www.docker.com/get-started) image. |
| 113 | +* Using a [Snapcraft](https://snapcraft.io/build) package. |
| 114 | + |
| 115 | + |
| 116 | +## Shipping with Docker |
| 117 | + |
| 118 | +The idea behind using Docker is to create a Docker container, with a target platform, and use it for building our application and then create a really small image for shipping and running our application! |
| 119 | + |
| 120 | +Wow! I want to [embark on this adventure](./shipping/docker.html)! |
| 121 | + |
| 122 | +## Shipping with Snapcraft |
| 123 | + |
| 124 | +The idea behind using Snapcraft is to use this tool for building an executable targeting the Linux OS and then publishing it! |
| 125 | + |
| 126 | +Oh great! Let’s follow [this sea lane](./shipping/snapcraft.html)! |
0 commit comments